Pages: [1]   Go Down
Author Topic: Arduino to Printer through Parallel Port  (Read 9652 times)
0 Members and 1 Guest are viewing this topic.
East Coast USA
Offline Offline
Newbie
*
Karma: 0
Posts: 16
Hands in the air!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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 (http://en.wikipedia.org/wiki/Parallel_port). 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       
11nStrobe(input)
22Data pin 0(input)
33Data pin 1(input)
44Data pin 2(input)
55Data pin 3(input)
66Data pin 4(input)
77Data pin 5(input)
88Data pin 6(input)
99Data pin 7(input)
1010nAck(output)
1111busy(output)
18-2519-30Ground (-) 


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:
Code:
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
Logged

Build your own sentry gun! http://psg.rudolphlabs.com

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


Sounds good,

Maybe you can make a playground article from this?
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Worked perfectly!
-Canon scaaning device.
But how can i control the scanner with the Arduino sutch as move the scan bar or turn on the scan light?
Thanks!
Logged

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


WIth direct port manipulation - http://www.arduino.cc/en/Reference/PortManipulation - the code could be made simpler

the numbers of the pins should change a bit, especially the datapins could match PORTD .

Or keeping the code similar

Code:
  int b0 = bitRead(inByte, 0);
  int b1 = bitRead(inByte, 1);
 ...
  int b7 = bitRead(inByte, 7);

  digitalWrite(data_0, b0);        // set data bit pins
...
  digitalWrite(data_7, b7);

could be written as
Code:
digitalWrite(data_0, inbyte & 0x01);
digitalWrite(data_1, inbyte & 0x02);
digitalWrite(data_2, inbyte & 0x04);
digitalWrite(data_3, inbyte & 0x08);
digitalWrite(data_4, inbyte & 0x10);
digitalWrite(data_5, inbyte & 0x20);
digitalWrite(data_6, inbyte & 0x40);
digitalWrite(data_7, inbyte & 0x80);

Finally the HP could make a nice class so one could call:  [inherit interface from print class?]

HP.reset();
HP.print(char);
HP.println(string);
HP.print(int);
HP.linefeed();
HP.formfeed();
HP.Escape("E");  // easy way to print escaped codes
etc

@wouter
You need to have the command set of the Cannon scanning device to be able to control it with arduino. You might need to build a sniffer first to capture the commands when the scanner is attached to a PC or MAC. Being familiar with TWAIN drivers could help to understand how scanner protocols work in general. No easy stuff, not too difficult either but not a one week project imho.

Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

La Crosse, Wisconsin
Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Any ideas on how to incorporate this with an Internet of Things printer? I already have a parallel receipt printer that would work great for this.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Worked well for HP Deskjet 670C
Nice work!!!
Thanks
Logged

BHZ, MG, Brazil
Offline Offline
Sr. Member
****
Karma: 10
Posts: 346
Android developer; Arduino enthusiast
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This will be great for sending ESC/P2 codes to Epson dot matrix printers.

Logged

Learn to live: Live to learn.
Showing off my work: http://arduino.cc/forum/index.php/topic,126197.0.html

Global Moderator
Netherlands
Offline Offline
Shannon Member
*****
Karma: 170
Posts: 12483
In theory there is no difference between theory and practice, however in practice there are many...
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
This will be great for sending ESC/P2 codes to Epson dot matrix printers.
Sure why not, you can get a similar class as the HP above

Epson.reset();
Epson.print(char);
Epson.println(string);
Epson.print(int);
Epson.linefeed();
Epson.formfeed();
Epson.Escape("E");  // easy way to print escaped codes
Epson.Escape(byte byte byte); // overloaded with 1..5 bytes

there might even be a printer base class that defines the interface and derive Epson (or HP) from that ...
Logged

Rob Tillaart

Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -
(Please do not PM for private consultancy)

Québec
Offline Offline
Sr. Member
****
Karma: 7
Posts: 392
When it's not human error, it's Windows going schizophrenic.
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The real challenge now will be to make a centronic port for usb printer, so I can take my old 386 out of the box, and print with brand new printer using Parallel port;) Kidding of coarse.

To bad those printer has disappear, cause a SPI version of this project, to save some pin for tv keybord ect, would make a great centronic shield.

Bravo by the way.
« Last Edit: June 17, 2013, 09:46:02 pm by Frederic_Plante » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

works well with my old fujitsu DL3300!

but i wonder how i can send messages over serial to print them in the "normal message"

i would appreciate a little help
Logged

Norway
Offline Offline
Full Member
***
Karma: 1
Posts: 138
likes to program Arduinos!
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

WOW! This works great on an OKI Microline 192 (my school have a ton of them, and I can have as many as I want!)

But how can I print my own text? I know I can edit the message function, but I'm planing to make a door logging machine.
Every time a person passes the door, it's going to write the time, and how many passages there have been.

If it was possible to use the serial.write function to enter text to the printer, that would be great!
« Last Edit: September 27, 2013, 07:46:05 am by hansibull » Logged

Pages: [1]   Go Up
Jump to: