Interfacing Centronics IEEE 1284 printer with AVR mega

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I've been given the rather dubious task of hacking an old inkjet printer to print serial numbers on products for the company where I work. I wanted, if possible, to avoid using a full-blown PC to control the device and instead use simple microcontroller & LCD with some buttons for data entry.

I have so far succeeded in making the printer (HP DeskJet 950C) print a plain text line by sending raw PCL data from ATmega168 directly to the Centronics IEEE 1284 connector following the protocols outlined here: http://www.beyondlogic.org/spp/parallel.htm

What I would like to know is what (if any) protection do I need to place between the uC port and the Centronics port. Should I use buffers and/or pull-ups? The document mentioned above discusses the PC side in detail but does not mention much of the printer end. I guess this will differ from one OEM to another.

Is there perhaps an easy way to determine whether the port is TTL or TTL level CMOS? as I've not been able to find a schematic for this printer.

I might point out that I currently have this working with a direct connection between the two ports, ie no pull-ups, internal or external. However, when I say working, I mean only if I power-up the devices in a particular order (Printer then uC) otherwise the printer gives an error. Note, I have tried adding pull-ups (10k) on the ACK/BUSY lines but this did not seem to make a differece.

I eventually plan to power the uC from the printer's own 5V supply but am unsure whether this will be enough to reliably resolve the issue or not.

I will include my test code out of interest just incase there is something I may have overlooked in the firmware.

#include 
#include  
#include 

// E(s12HHello WorldE
unsigned char hello[] = {
	0x1B, 0x45, 0x1B, 0x28, 0x73, 0x31, 0x32, 0x48,
	0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, 0x57, 0x6F,
	0x72, 0x6C, 0x64, 0x1B, 0x45
};

volatile unsigned char button_state = 0;

ISR(TIMER1_COMPA_vect)
{
	// Button State: 255 = ON, 0 = OFF, 1-254 = Transitional
	if(PINC & 0x01)
	{
	     if(button_state > 0)
			button_state--;
	}
	else if(button_state < 255)
			button_state++;

	PORTB ^= 0x02; // Toggle LED on PB1
} 

int main(void)
{
	unsigned int i;

	DDRB = 0x03;
	DDRD = 0xFF;
	DDRC = 0x00;

	PORTB |= 0x01;           // Set PB0 High (Strobe)
	TCCR1B |= (1 << WGM12);  // Configure timer 1 for CTC mode 
	TIMSK1 |= (1 << OCIE1A); // Enable CTC interrupt 
	OCR1A = 250;             // Set CTC compare value to 4Kz @ 8MHz AVR clock
	TCCR1B |= (1 << CS11);   // Start Timer1 at Fcpu/8
	sei();                   // Enable Interrupts

	while(1)                          // Loop Forever
	{
		PORTD = 0x00;
		while(PINB & 0x80) { }        // Wait while Printer Off/Busy
		while(button_state < 255) { } // Wait for Button Press
			
		for(i = 0; i < sizeof(hello); i++)
		{
			PORTD = hello[i];
			while(PINB & 0x80) { }    // Wait while Printer Busy
			PORTB &= 0xFE;            // Pull Strobe Low (Active)
			_delay_ms(1);                  
			PORTB |= 0x01;            // Set Strobe High
			while(PINB & 0x40) { }    // Wait for Ack Signal
		}
		while(button_state > 0) { }   // Wait for Button Release
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

A Centronics i/f has several status lines e.g. Paper Out etc.

Yes. You can drive it with just the STB and ACK lines. It is no bother to handle BUSY line too.

Either attach the AVR to all the i/p lines and assert defined states, or use pull-up and pull-downs to assert defined states.

You should be able to power the AVR directly from the printer. No, it should work with CMOS levels and with TTL levels. You do not need buffer chips. The printer will most likely have a 740 series controller inside. (or any other controller that is made with CMOS).

Incidentally you could initialise your C string:

char hello[] = "\033E\033(s12HHello World\033E";

or

#define ESC "\033"
char hello[] = ESC "E" ESC "(s12HHello World" ESC "E";

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks for the info David. If I understand this correctly I can safely assume CMOS gates on the printer-side therefore a 4.7K - 10K pull-up on ACK & BUSY should be all that is neccessary when using a common power source. Is this correct?

Also am I right in thinking that the data-bus PORTD and strobe PB0 (all outputs) should NOT be pulled either way? Would a small inline resistor, such as 68R, be beneficial?

Sorry for all the questions but my aim is to keep external interfacing hardware to a minimum and use an Arduino Duemilanove + LCD input shield for simplicity.

PS Thanks for the tip on initialising the C-string. I was not aware I could I write the escape sequence that way :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Having seen all kinds of blown-ups on the Centronics interface in the past in rough environments I would definitely use buffers / line drivers on the AVR and I would think about ESD protection. Unless, of course this is only a hobby project or you don't care.

Stealing Proteus doesn't make you an engineer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

10k should be fine for pull-ups or pull-downs.

There is no need to have any 68R series resistor. Unless you intend to drive o/p against o/p. In which case 470R or 1k0 would be preferable.

Bear in mind that you will probably be feeding the printer faster than it can print. So you should check the BUSY line before sending anything.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ArnoldB wrote:
Having seen all kinds of blown-ups on the Centronics interface in the past in rough environments I would definitely use buffers / line drivers on the AVR and I would think about ESD protection. Unless, of course this is only a hobby project or you don't care.

While I appreciate your concerns - would this be so much of an issue given a common power supply and very close connection?

BTW its not quite a hobby project, more an experimental project for my work. So ofcourse I do care and hence my reason for asking here :)

david.prentice wrote:
10k should be fine for pull-ups or pull-downs.

There is no need to have any 68R series resistor. Unless you intend to drive o/p against o/p. In which case 470R or 1k0 would be preferable.

Bear in mind that you will probably be feeding the printer faster than it can print. So you should check the BUSY line before sending anything.

David.


Thanks for the clarification David. I think I will build the prototype using pull-ups on the two i/p lines only and see how it goes. If I find problems with ESD etc I will add a buffer/driver stage at a later date.

Thanks again David and ArnoldB for your kind help and advice.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is up to you. If you don't care, why should I - unless there is a chance I have to use your device in the future or my safety might depend on it.

Stealing Proteus doesn't make you an engineer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I do indeed care but since this will be a one-off device, used only by myself and a few others, I don't think I need worry about it too much. Like I say, if I do experience problems I could always add some buffering and/or ESD protection later on.

My main concern was the nature of logic on the printer port. Given that the printer is not that ancient, the likelyhood is that it will be CMOS. With a nice short/shielded data-bus I have tendency to agree with David in that buffer ic's *shouldn't* be neccessary.

I am not knocking your advice though, I truly appreciate it, thanks.