Looking around on the forums for some hints on this topic, and finding none, I worked out the details from scratch. I figured somebody else might want to do this someday, and so if that's you, here's what worked for me. Hope it helps.
The goal is to use an Arduino to control an HP printer. We are talking standard, desktop printers here, not thermal-receipt-printers or 3D printers.
The printer in question needs to have a parallel/centronics port (Parallel port - Wikipedia). I used an HP Deskjet 952C; the protocol should work with most similar HP printers. No promises for non-HP, but it's worth a try.
The port on the printer is actually called a Centronics connector. If you have a cable to connect the printer to the computer, look at the other end - this is the actual parallel port type connector. You can wire in your Arduino at either end, but the pin-outs are slightly different depending on which end you use:
Pin # (Parallel Port Connector) | Pin # (Centronics Connector) | Signal Name | Signal Type |
---|---|---|---|
1 | 1 | nStrobe | (input) |
2 | 2 | Data pin 0 | (input) |
3 | 3 | Data pin 1 | (input) |
4 | 4 | Data pin 2 | (input) |
5 | 5 | Data pin 3 | (input) |
6 | 6 | Data pin 4 | (input) |
7 | 7 | Data pin 5 | (input) |
8 | 8 | Data pin 6 | (input) |
9 | 9 | Data pin 7 | (input) |
10 | 10 | nAck | (output) |
11 | 11 | busy | (output) |
18-25 | 19-30 | Ground (-) |
Connect each of these pins to your Arduino as follows (I did this by splicing into the wire, but there's probably better methods):
nStrobe -> arduino pin 2
data_0 -> arduino pin 3
data_1 -> arduino pin 4
data_2 -> arduino pin 5
data_3 -> arduino pin 6
data_4 -> arduino pin 7
data_5 -> arduino pin 8
data_6 -> arduino pin 9
data_7 -> arduino pin 10
nAck -> arduino pin 11
busy -> arduino pin 12
It's that simple. Now just run this code on the Arduino:
const int startup_charsPerLine = 80;
const int startup_num_lines = 2;
byte startup_message[startup_num_lines][startup_charsPerLine] = {
"This is the startup message. It prints whenever",
"the Arduino is reset.",
};
const int charsPerLine = 80; // this is the max # of chars per line
const int num_lines = 10;
byte message[num_lines][charsPerLine] = {
" ", // blank line
"This is the normal message. It prints whenever",
"you connect pin 14 (analog 0) to GND.",
" ", // blank line
"------------------------------------------------------------------------------", // a spiffy line
"1) More message content",
" ",
"II) you can have up to about 80 chars per line ",
" ",
"------------------------------------------------------------------------------",
};
// parallel port pin# = arduino pin#
const int nStrobe = 2;
const int data_0 = 3;
const int data_1 = 4;
const int data_2 = 5;
const int data_3 = 6;
const int data_4 = 7;
const int data_5 = 8;
const int data_6 = 9;
const int data_7 = 10;
const int nAck = 11;
const int busy = 12;
const int strobeWait = 2; // microseconds to strobe for
void setup() {
Serial.begin(9600);
pinMode(nStrobe, OUTPUT); // is active LOW
digitalWrite(nStrobe, HIGH); // set HIGH
pinMode(data_0, OUTPUT);
pinMode(data_1, OUTPUT);
pinMode(data_2, OUTPUT);
pinMode(data_3, OUTPUT);
pinMode(data_4, OUTPUT);
pinMode(data_5, OUTPUT);
pinMode(data_6, OUTPUT);
pinMode(data_7, OUTPUT);
pinMode(nAck, INPUT); // is active LOW
pinMode(busy, INPUT);
pinMode(13, OUTPUT);
pinMode(14, INPUT); // analog pin 0 on duemilanove and uno
digitalWrite(14, HIGH); // enable pull-up
delay(1000);
resetPrinter();
printStartupMessage();
resetPrinter();
Serial.println("Delay for 5 sec");
delay(5000);
Serial.println("Startup complete");
}
void loop() {
while(digitalRead(14) == HIGH) {
// wait
}
resetPrinter();
printMessage();
resetPrinter();
}
void printByte(byte inByte) {
while(digitalRead(busy) == HIGH) {
// wait for busy to go low
}
int b0 = bitRead(inByte, 0);
int b1 = bitRead(inByte, 1);
int b2 = bitRead(inByte, 2);
int b3 = bitRead(inByte, 3);
int b4 = bitRead(inByte, 4);
int b5 = bitRead(inByte, 5);
int b6 = bitRead(inByte, 6);
int b7 = bitRead(inByte, 7);
digitalWrite(data_0, b0); // set data bit pins
digitalWrite(data_1, b1);
digitalWrite(data_2, b2);
digitalWrite(data_3, b3);
digitalWrite(data_4, b4);
digitalWrite(data_5, b5);
digitalWrite(data_6, b6);
digitalWrite(data_7, b7);
digitalWrite(nStrobe, LOW); // strobe nStrobe to input data bits
delayMicroseconds(strobeWait);
digitalWrite(nStrobe, HIGH);
while(digitalRead(busy) == HIGH) {
// wait for busy line to go low
}
}
void resetPrinter() {
Serial.println("Reseting printer...");
printByte(27); // reset printer
printByte('E');
Serial.println("Printer Reset");
}
void printMessage() {
digitalWrite(13, HIGH);
for(int line = 0; line < num_lines; line++) {
for(int cursorPosition = 0; cursorPosition < charsPerLine; cursorPosition++) {
byte character = message[line][cursorPosition];
printByte(character);
delay(1);
}
printByte(10); // new line
printByte(13); // carriage return
}
digitalWrite(13,LOW);
}
void printStartupMessage() {
Serial.println("Print start-up mssage");
digitalWrite(13, HIGH);
for(int line = 0; line < startup_num_lines; line++) {
for(int cursorPosition = 0; cursorPosition < startup_charsPerLine; cursorPosition++) {
byte character = startup_message[line][cursorPosition];
printByte(character);
// delay(1);
}
printByte(10); // new line
printByte(13); // carriage return
Serial.print("Line ");
Serial.print(line);
Serial.println(" printed.");
}
Serial.println("Startup message printed");
digitalWrite(13,LOW);
}
It should print the startup message when the Arduino is turned on or reset. To print the other message, briefly connect pin 14 (analong 0 on Arduino Uno) to GND.
Keep in mind that the printer needs to be on, that means plugged into an outlet. The Arduino will not power the printer.
If you are successful getting your printer working with the Arduino, please let us know what model of printer it was, and any tips. If you have any questions, feel free to ask.
Cheers,
-Bob