Tutorial: Arduino and a Thermal Printer

This is chapter thirty-eight of a series originally titled “Getting Started/Moving Forward with Arduino!” by John Boxall – a series of articles on the Arduino universe. The first chapter is here, the complete series is detailed here. Any files from tutorials will be found here.

Welcome back fellow arduidans!

In this article we introduce the inexpensive thermal printer that has recently become widely available from Sparkfun and their resellers. The goal of the article is to be as simple as possible so you can get started without any problems or confusion. In the past getting data from our Arduino to a paper form would either have meant logging it to an SD card then using a PC to finish the job, or perhaps viewing said data on an LCD then writing it down. Not any more – with the use of this cheap and simple serial printer. Before we get started, here is a short demonstration video of it in action:


Not bad at all considering the price. Let’s have a look in more detail. Here is the printer and two matching rolls of thermal paper:

… and the inside of the unit:

Loading paper is quite simple, just drop the roll in with the end of the paper facing away from you, pull it out further than the top of the front lip, then close the lid. The paper rolls required need to be 57mm wide and have a diameter of no more than 39mm. For example. There is a piece of white cardboard stuck to the front – this is an economical cover that hides some of the internals. Nothing of interest for us in there. The button next to the LED on the left is for paper advance, and the LED can blink out the printer status.

From a hardware perspective wiring is also very simple. Looking at the base of the printer:

… there are two connections. On the left is DC power, and data on the right. For this example I have fitted my own rubber feet to stop the printer rocking about. Thankfully the leads are included with the printer and have the plugs already fitted – a great time saver.

Please note – you need an external power supply with a voltage of between 5 and 9 volts DC that can deliver up to 1.5 amps of current. When idling the printer draws less than 10 milliamps, but when printing it peaks at around 1.47 A. So don’t try and run it from your Arduino board. Furthermore you need to ensure the GND from your printer runs to the power supply GND and the Arduino GND. However the data lines are easy, as the printer has a serial interface we only need to connect printer RX (white) to Arduino digital 3, and printer TX (green) to Arduino digital 2. We will use a virtual serial port on pins 2 and 3 as 0 and 1 will be taken for use with the serial monitor window for debugging and possible control purposes.

If you want to quickly test your printer – connect it to the power, drop in some paper, hold down the feed button and turn on the power. It will quickly produce a test print.

Next we need to understand how to control the printer in our sketches. Consider this very simple sketch (download):

/* Example 38.1 - Sparkfun Thermal Printer Test (COM-10438) http://tronixstuff.wordpress.com/tutorials > chapter 38 Based on code by Nathan Seidle of Spark Fun Electronics 2011  http://littlebirdelectronics.com/products/thermal-printer  */  #include NewSoftSerial Thermal(2, 3); // printer RX to digital 2, printer TX to digital 3  int heatTime = 80; int heatInterval = 255; char printDensity = 15; char printBreakTime = 15;  void setup() { Serial.begin(57600); // used for debugging via serial monitor Thermal.begin(19200); // used for writing to the printer initPrinter(); }  void initPrinter() { //Modify the print speed and heat Thermal.print(27, BYTE); Thermal.print(55, BYTE); Thermal.print(7, BYTE); //Default 64 dots = 8*('7'+1) Thermal.print(heatTime, BYTE); //Default 80 or 800us Thermal.print(heatInterval, BYTE); //Default 2 or 20us //Modify the print density and timeout Thermal.print(18, BYTE); Thermal.print(35, BYTE); int printSetting = (printDensity<<4) | printBreakTime; Thermal.print(printSetting, BYTE); //Combination of printDensity and printBreakTime Serial.println(); Serial.println("Printer ready"); }  void loop() { Thermal.println("  Visit http://tronixstuff.com  "); Thermal.print(10, BYTE); // Sends the LF to the printer, advances the paper Thermal.print("    Millis = "); Thermal.println(millis()); Thermal.print(10, BYTE); Thermal.print(10, BYTE); do { } while (1>0); }

After ensuring your printer is connected as described earlier, and has the appropriate power supply and paper – uploading the sketch will result in the following:

Now that the initial burst of printing excitement has passed, let’s look at the sketch and see how it all works. The first part:

#include <NewSoftSerial.h> NewSoftSerial Thermal(2, 3); // printer RX to digital 2, printer TX to digital 3

configures the virtual serial port and creates an instance for us to refer to when writing to the printer. Next, four variables are defined. These hold parameters used for configuring the printer. As the printer works with these settings there is no need to alter them, however if you are feeling experimental nothing is stopping you. Next we have the function initPrinter(). This sets a lot of parameters for the printer to ready itself for work. We callinitPrinter() only once – in void setup(); For now we can be satisfied that it ‘just works’.

Now time for action – void loop(). Writing text to the printer is as simple as:

Thermal.print("text");

You can also use .println to advance along to the next line. Generally this is the same as writing to the serial monitor with Serial.println() etc. So nothing new there. Each line of text can be up to thirty-two characters in length.

The next thing to concern ourselves with is sending commands to the printer. You may have noticed the line

  Thermal.print(10, BYTE);

This sends the command to advance to the next line (in the old days we would say ‘carriage return and line feed’). There are many commands available to do various things. When sending commands, don’t use .println() – as this sends the carriage return as well. At this point you will need to refer to the somewhat amusing user manual.pdf. Open it up and have a look at section 5.2.1 on page ten. Notice how each command has an ASCII, decimal and hexadecimal equivalent? We will use the decimal command values. So to send them, just use:

Thermal.print(value, BYTE);

Easy. If the command has two or more values (for example, to turn the printer offline [page 11] ) – just send each value in a separate statement. For example:

Thermal.print(27, BYTE);
Thermal.print(61, BYTE);
Thermal.print(0, BYTE);

… will put the printer into offline mode.

For out next example, let’s try out a few more commands:

  • Underlined text (the printer seemed to have issues with thick underlining, however your experience may vary)
  • Bold text
  • Double height and width
Here is the sketch (download):
/* Example 38.2 - Sparkfun Thermal Printer Test II (COM-10438) http://tronixstuff.wordpress.com/tutorials > chapter 38 Based on code by Nathan Seidle of Spark Fun Electronics 2011  http://littlebirdelectronics.com/products/thermal-printer  */  #include NewSoftSerial Thermal(2, 3); // printer RX to digital 2, printer TX to digital 3  int heatTime = 80; int heatInterval = 255; char printDensity = 15; char printBreakTime = 15;  void setup() { Serial.begin(57600); // for debug info to serial monitor Thermal.begin(19200); // to write to our new printer initPrinter(); }  void initPrinter() { //Modify the print speed and heat Thermal.print(27, BYTE); Thermal.print(55, BYTE); Thermal.print(7, BYTE); //Default 64 dots = 8*('7'+1) Thermal.print(heatTime, BYTE); //Default 80 or 800us Thermal.print(heatInterval, BYTE); //Default 2 or 20us //Modify the print density and timeout Thermal.print(18, BYTE); Thermal.print(35, BYTE); int printSetting = (printDensity<<4) | printBreakTime; Thermal.print(printSetting, BYTE); //Combination of printDensity and printBreakTime Serial.println(); Serial.println("Printer ready"); }  void loop() { // underline - one pixel Thermal.print(27,BYTE); Thermal.print(45,BYTE); Thermal.print(1,BYTE); Thermal.println("Underline - thin"); Thermal.println("01234567890123456789012345678901"); Thermal.print(10,BYTE);  // underline - two pixels Thermal.print(27,BYTE); Thermal.print(45,BYTE); Thermal.print(2,BYTE); Thermal.println("Underline - thick"); Thermal.println("01234567890123456789012345678901"); Thermal.print(10,BYTE);    // turn off underline Thermal.print(27,BYTE); Thermal.print(45,BYTE); Thermal.print(0,BYTE); delay(3000); Thermal.print(10,BYTE);    // bold text on Thermal.print(27,BYTE); Thermal.print(32,BYTE); Thermal.print(1,BYTE); Thermal.println(" #### Bold text #### "); Thermal.println("01234567890123456789012345678901"); delay(3000);    // bold text off Thermal.print(27,BYTE); Thermal.print(32,BYTE); Thermal.print(0,BYTE); Thermal.print(10, BYTE); //Sends the LF to the printer, advances the paper delay(3000);    // height/width enlarge Thermal.print(29,BYTE); Thermal.print(33,BYTE); Thermal.print(255,BYTE); Thermal.println("ABCDEF"); Thermal.println("012345"); delay(3000);    // back to normal Thermal.print(29,BYTE); Thermal.print(33,BYTE); Thermal.print(0,BYTE); delay(3000);  Thermal.print(10, BYTE); Thermal.println("Back to normal..."); Thermal.print(10, BYTE); Thermal.print(10, BYTE); do { } while (1>0); // do nothing }

And the results:

Frankly bold doesn’t look that bold, so I wouldn’t worry about it too much. However the oversized characters could be very useful, and still print relatively quickly.

Next on our list are barcodes. A normal UPC barcode has 12 digits, and our little printer can generate a variety of barcode types – see page twenty-two of the user manual. For our example we will generate UPC-A type codes and an alphanumeric version. Alphanumeric barcodes need capital letters, the dollar sign, percent sign, or full stop. The data is kept in an array of characters named … barCode[]  and barCode[]2. Consider the functions printBarcode(), printBarcodeThick()  and printBarcodeAlpha() in the following example sketch (download):

/* Example 38.3 - Sparkfun Thermal Printer Test III (COM-10438) http://tronixstuff.wordpress.com/tutorials > chapter 38 Based on code by Nathan Seidle of Spark Fun Electronics 2011  http://littlebirdelectronics.com/products/thermal-printer  */  #include NewSoftSerial Thermal(2, 3); // printer RX to digital 2, printer TX to digital 3  int heatTime = 80; int heatInterval = 255; char printDensity = 15; char printBreakTime = 15; char barCode[]={  '9','2','3','0','5','6','4','8','9','8','4','4'}; char barCode2[]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };  void setup() { Serial.begin(57600); // for debug info to serial monitor Thermal.begin(19200); // to write to our new printer initPrinter(); }  void initPrinter() { //Modify the print speed and heat Thermal.print(27, BYTE); Thermal.print(55, BYTE); Thermal.print(7, BYTE); //Default 64 dots = 8*('7'+1) Thermal.print(heatTime, BYTE); //Default 80 or 800us Thermal.print(heatInterval, BYTE); //Default 2 or 20us //Modify the print density and timeout Thermal.print(18, BYTE); Thermal.print(35, BYTE); int printSetting = (printDensity<<4) | printBreakTime; Thermal.print(printSetting, BYTE); //Combination of printDensity and printBreakTime Serial.println(); Serial.println("Printer ready"); }  void printBarcode(char zz[]) { Thermal.print(29, BYTE); //GS Thermal.print(107, BYTE); //k Thermal.print(0, BYTE); //m = 0 for (int z=0; z<12; z++) { Thermal.print(zz[z]); } Thermal.print(0, BYTE);  // bar code terminator delay(3000);             // necessary delay Thermal.print(10, BYTE); Thermal.print(10, BYTE); Thermal.print(10, BYTE); }  void printBarcodeThick(char zz[]) { Thermal.print(29, BYTE); // specified height of barcode Thermal.print(104, BYTE); Thermal.print(200, BYTE); // 200 pixels high (default is 50)  Thermal.print(29, BYTE); //GS Thermal.print(107, BYTE); //k Thermal.print(0, BYTE); //m = 0 for (int z=0; z<12; z++) { Thermal.print(zz[z]); } Thermal.print(0, BYTE);  // bar code terminator delay(3000);             // necessary delay Thermal.print(29, BYTE); // specified height of barcode Thermal.print(104, BYTE); Thermal.print(50, BYTE); // need to set back to 50 pixel height delay(3000); Thermal.print(10, BYTE); Thermal.print(10, BYTE); Thermal.print(10, BYTE); }  void printBarcodeAlpha(char zz[]) { Thermal.print(29, BYTE); //GS Thermal.print(107, BYTE); //k Thermal.print(4, BYTE); //m = 0 for (int z=0; z<16; z++) { Thermal.print(zz[z]); } Thermal.print(0, BYTE);  // bar code terminator delay(3000);             // necessary delay Thermal.print(10, BYTE); Thermal.print(10, BYTE); Thermal.print(10, BYTE); }  void loop() { printBarcode(barCode); printBarcodeThick(barCode); printBarcodeAlpha(barCode2); do {} while (1>0); }

Notice in printBarcodeThick() we make use of the ability to change the vertical size of the barcode – the height in pixels is the third parameter in the group. And here is the result:

So there you have it – another practical piece of hardware previously considered to be out of our reach – is now under our control. Now you should have an understanding of the basics and can approach the other functions in the user guide with confidence. Please keep in mind that the price of this printer really should play a large part in determining suitability for a particular task. It does have issues printing large blocks of pixels, such as the double-width underlining and inverse text. This printer is great but certainly not for commercial nor high-volume use. That is what professional POS printers from Brother, Star, Epson, etc., are for. However for low-volume, personal or hobby use this printer is certainly a deal. As always, now it is up to you and your imagination to put this to use or get up to other shenanigans.

This article would not have been possible without the example sketches provided by Nathan Seidle, the founder and CEO of Sparkfun. If you meet him, shout him a beer.  Please don’t knock off bus tickets or so on. I’m sure there are heavy penalties for doing so if caught. Finally, I hope you enjoyed reading this as much as I did writing it for you.

If you have any questions about the processes or details in this article, please ask in our Google Group – dedicated to the projects and related items on this website. Sign up – it’s free, there is the odd competition or give-away –  and we can all learn something. Or follow tronixstuff on twitter and facebook. High resolution images available on flickr.

Otherwise, have fun, stay safe, be good to each other – and make something!

Advertisements
By John Boxall

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s