Built-in project · Arduino Uno R3

Fortune printer on an Arduino Uno

Press the button and a thermal printer rolls out a fortune and a lucky number, in big bold type with a barcode under it. The whole build, an Arduino Uno and 2 more parts, runs here in your browser on the firmware below; open it in the editor to change the wiring or the code and run it again.

Teaching? Assign it to your class in one click.

Beginner About 20 minutes to build and run. Runs in your browser. Free, and no account needed.

The parts retail for about $55. On Mokxi they're free.

Step by step, with the wiring and the common mistakes: Arduino Thermal Printer: Wiring, Code and Barcodes

The circuit runs here once the page has loaded.

What you'll learn

  • Talking to a serial device with SoftwareSerial
  • Powering a printer from its own supply with shared ground
  • Debouncing a button with a short delay
  • Picking random items from an array
  • Difficulty: Beginner
  • Time: About 20 minutes
  • Board: Arduino Uno R3
  • Parts: 5

How it works

The Uno talks to a thermal receipt printer over two pins: 5 for its TX and 6 for its RX, using SoftwareSerial at 19200 baud. The printer has its own 9 V supply and shares ground with the Uno. A button on pin 2 starts a print.

Each press prints a ticket. It has a big bold centered FORTUNE header, a dashed line, one random fortune from a list of eight, and a lucky number from 10 to 99. The number is printed as text and as a CODE39 barcode.

Parts list

5 parts, plus the jumper wires. They retail for about $55; on Mokxi they're free.

Wiring table

Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.

Part and pinConnects to
Thermal receipt printer pin RXArduino Uno R3 pin 6
Thermal receipt printer pin TXArduino Uno R3 pin 5
Pushbutton pin 1aArduino Uno R3 pin 2
Thermal receipt printer pin GNDArduino Uno R3 pin GND
Pushbutton pin 2aArduino Uno R3 pin GND
Thermal receipt printer pin VH9 V

The code

The firmware exactly as the editor opens it. Change a line there and press Run: it compiles in the browser.

sketch.ino · Arduino Uno R3
// Fortune printer: a mini thermal printer and a button.
//
//   pins 5, 6  SoftwareSerial: the printer's TX into 5, its RX from 6
//   pin 2      the button, to ground (INPUT_PULLUP)
//
// The printer runs from its own 9 V supply, sharing ground with the Uno.
// Each press prints a ticket: a bold, centered, double size header, one of
// the fortunes below, and a lucky number as text and as a barcode. The time
// of the press seeds the random numbers, so the tickets differ run to run.

#include <Adafruit_Thermal.h>
#include <SoftwareSerial.h>

const int BUTTON = 2;

SoftwareSerial printerSerial(5, 6);
Adafruit_Thermal printer(&printerSerial);

const char *const FORTUNES[] = {
  "A soldered joint holds fast.",
  "Your next build works first try.",
  "Check the ground wire first.",
  "A blinking light brings joy.",
  "Patience fixes most bugs.",
  "Today, the magic smoke stays in.",
  "An old project wants finishing.",
  "Read the datasheet. It knows.",
};
const int FORTUNE_COUNT = sizeof(FORTUNES) / sizeof(FORTUNES[0]);

int tickets = 0;

void printTicket() {
  randomSeed(micros());
  int lucky = random(10, 100);

  printer.justify('C');
  printer.boldOn();
  printer.setSize('L');
  printer.println("FORTUNE");
  printer.setSize('S');
  printer.boldOff();
  printer.println("--------------------------------");
  printer.justify('L');
  printer.println(FORTUNES[random(FORTUNE_COUNT)]);
  printer.feed(1);
  printer.justify('C');
  printer.print("Lucky number: ");
  printer.println(lucky);

  char code[3];
  code[0] = (char)('0' + lucky / 10);
  code[1] = (char)('0' + lucky % 10);
  code[2] = 0;
  printer.setBarcodeHeight(40);
  printer.printBarcode(code, CODE39);
  printer.justify('L');
  printer.feed(2);

  tickets++;
  Serial.print("Ticket ");
  Serial.print(tickets);
  Serial.print(", lucky number ");
  Serial.println(lucky);
}

void setup() {
  Serial.begin(9600);
  pinMode(BUTTON, INPUT_PULLUP);
  printerSerial.begin(19200);
  printer.begin();
  if (!printer.hasPaper()) Serial.println("Out of paper");
  Serial.println("Press the button for your fortune");
}

void loop() {
  if (digitalRead(BUTTON) == LOW) {
    delay(20);
    if (digitalRead(BUTTON) == LOW) {
      printTicket();
      while (digitalRead(BUTTON) == LOW) delay(10);
      delay(20);
    }
  }
}

Code walkthrough

The key functions of the sketch, and what each one does.

printTicket sketch.ino

Seeds the random generator with micros, picks a lucky number, then sends the layout to the printer: centered bold large header, a dashed line, a random fortune, then the number. It builds a two character string from the number for the barcode and counts the ticket.

void printTicket() {
  randomSeed(micros());
  int lucky = random(10, 100);

  printer.justify('C');
  printer.boldOn();
  printer.setSize('L');
  printer.println("FORTUNE");
  printer.setSize('S');
  printer.boldOff();
  printer.println("--------------------------------");
  printer.justify('L');
  printer.println(FORTUNES[random(FORTUNE_COUNT)]);
  printer.feed(1);
  printer.justify('C');
  printer.print("Lucky number: ");
  printer.println(lucky);

  char code[3];
  code[0] = (char)('0' + lucky / 10);
  code[1] = (char)('0' + lucky % 10);
  code[2] = 0;
  printer.setBarcodeHeight(40);
  printer.printBarcode(code, CODE39);
  printer.justify('L');
  printer.feed(2);

  tickets++;
  // ... 5 more lines in the editor

setup sketch.ino

Opens the serial monitor, sets the button as INPUT_PULLUP, starts the printer's serial link at 19200 baud and calls printer.begin. It then checks hasPaper and prints a message if the paper is out.

void setup() {
  Serial.begin(9600);
  pinMode(BUTTON, INPUT_PULLUP);
  printerSerial.begin(19200);
  printer.begin();
  if (!printer.hasPaper()) Serial.println("Out of paper");
  Serial.println("Press the button for your fortune");
}

loop sketch.ino

Waits for the button to read LOW, waits 20 ms and checks again to skip bounce, then calls printTicket. It then waits for the button to be released, so holding it down prints only one ticket.

void loop() {
  if (digitalRead(BUTTON) == LOW) {
    delay(20);
    if (digitalRead(BUTTON) == LOW) {
      printTicket();
      while (digitalRead(BUTTON) == LOW) delay(10);
      delay(20);
    }
  }
}

Troubleshooting

The usual mistakes with this circuit, and the fix for each.

  • Nothing prints or the output is garbage This project
    Check the printer's RX goes to pin 6 and its TX to pin 5, and that the baud rate matches 19200.
  • The printer stays dead This project
    It needs its own 9 V supply on VH, with its GND joined to the Uno's GND.
  • The serial monitor says Out of paper This project
    Load paper in the printer. The sketch checks hasPaper once at startup.
  • The printer prints garbage or nothing. Thermal receipt printer
    Match the baud rate, 19200 for these, and cross TX and RX. Join the grounds. Use a library such as Adafruit_Thermal and call begin after the printer has warmed up.
  • The printer resets the board, faint prints, or jams. Thermal receipt printer
    It needs a strong 5 V to 9 V supply, usually 2 A or more, separate from the board. Weak power gives light prints and resets. Use the correct paper side, since only one side is heat sensitive.
  • The input reads random HIGH and LOW when the button is not pressed. Pushbutton
    A floating pin picks up noise. Add a 10 k pull-down or pull-up resistor, or use INPUT_PULLUP and wire the button between the pin and GND. Then pressed reads LOW.
  • The button seems always pressed, or never changes. Pushbutton
    A 4-leg tactile switch has legs joined in pairs. Place it across the breadboard center gap so the pairs sit on different rows. Wired along one side, the legs are already connected.
  • Upload fails or nothing runs after wiring pins 0 and 1 to a module. Arduino Uno R3
    Pins 0 and 1 are the USB serial port. Move the module to other pins, or unplug it while uploading. Also check the right board is selected.

Change it and keep it

Open it in the editor, change the circuit or the code, and keep your version in a free account.