thermal printers/When it stops/10. Asking the printer about paper
When it stops · 10 of 11

Asking the printer about paper

Send three bytes and the printer says whether it has paper. It answers in three bytes too, and two different answers start with the same one — which is how a check that stops too early reports an empty roll on a full printer.

Three bytes out, three bytes back

10 04 01 is the question, and both printers answer it. It is worth wiring for: a printer that can say "I am out of paper" is a device that can be left unattended, and one that cannot is a device somebody has to watch.

Three bytes come back, and the first one is not enough
nothing asked yet
What the printer says
10 04 01 is the question. Run it and watch what comes back — and note that this only works if the printer’s TXD is wired back to your board’s RX. With that wire missing the query is sent and nothing ever answers.

The trap is the first byte. 1A opens the reply whether the answer is good news or bad, and the verdict is in the second byte — FE for paper loaded, EF for out of paper. Anything that decides on one byte gets it wrong half the time, and gets it wrong in the direction that stops a working machine.

The label kit's library does exactly this: its noPaper() helper compares the first byte with 1A and returns true. On a printer with a full roll it reports an empty one. Read the three bytes yourself.

No answer is not the same as no paper

If the printer's TXD is not wired back to your board's RX, the query goes out and nothing ever returns. A sketch that treats a timeout as "out of paper" will sit there reporting an empty roll on a printer that is printing happily.

Three outcomes, not two: paper, no paper, and no answer. The third is a wiring fault and should be reported as one.

Flush before you ask

The printers also send packets nobody asked for — a notice when a job finishes, another when one fails. Those sit in the buffer, and the next status query reads the stale packet instead of the fresh reply. Emptying the buffer before sending the question costs one line and removes a whole class of confusing results.

The code

receipt_paper_status.ino

A status query once a second, with the whole three-byte reply read and decoded. It prints the bytes to the Serial Monitor as well as its verdict, so you can see what your own printer actually sends — take the roll out while it runs and watch the second byte change.

// Receipt printer wiring for this sketch.
//
//   USB-C PD charger (9 V capable) -> base board PD TYPE-C
//   base board PRINTER POWER -> printer POWER socket
//   base board PRINTER DATA TTL -> printer TTL socket
//
//   base board 3V3 MCU header -> ESP32-S3:
//     TX  -> GPIO16   (this board's RX - required here, not optional)
//     RX  -> GPIO17   (this board's TX)
//     3V3 -> 3V3
//     GND -> GND
//
// Arduino IDE: Tools > Board "ESP32S3 Dev Module", Tools > USB CDC On Boot
// "Enabled". No library needed.

#define PRN_RX 16
#define PRN_TX 17
#define PRN_BAUD 9600

HardwareSerial printer(2);

enum Status { PAPER_OK, PAPER_OUT, NO_ANSWER };

Status askAboutPaper() {
  while (printer.available()) printer.read();   // drop anything stale

  printer.write(0x10); printer.write(0x04); printer.write(0x01);
  printer.flush();

  uint8_t reply[3];
  uint8_t got = 0;
  unsigned long started = millis();
  while (got < 3 && millis() - started < 1000) {
    if (printer.available()) reply[got++] = printer.read();
  }
  if (got < 3) return NO_ANSWER;

  Serial.printf("reply: %02X %02X %02X\n", reply[0], reply[1], reply[2]);

  // The first byte opens both answers. The second one carries the verdict.
  if (reply[0] == 0x1A && reply[1] == 0xFE && reply[2] == 0x23) return PAPER_OK;
  if (reply[0] == 0x1A && reply[1] == 0xEF && reply[2] == 0x23) return PAPER_OUT;
  if (reply[0] == 0x1A && reply[1] == 0xFC && reply[2] == 0x6E) return PAPER_OUT;
  return NO_ANSWER;
}

void setup() {
  Serial.begin(115200);
  printer.begin(PRN_BAUD, SERIAL_8N1, PRN_RX, PRN_TX);
  delay(500);
  printer.write(0x1B); printer.write(0x40);
}

void loop() {
  switch (askAboutPaper()) {
    case PAPER_OK:   Serial.println("paper loaded");                  break;
    case PAPER_OUT:  Serial.println("out of paper");                  break;
    case NO_ANSWER:  Serial.println("no answer - check the RX wire");  break;
  }
  delay(1000);
}

This needs the return wire. The printer's TXD has to reach your board's RX or the query goes out and nothing ever comes back, which this sketch reports as no answer rather than as no paper. That distinction is the point of the whole article.

When it does not work

The query never gets a reply

Printing only needs one wire; asking needs two. The printer's TXD must reach your board's RX pin. Without it the query goes out and nothing comes back, and a sketch that treats silence as out-of-paper will report an empty roll forever.

It says out of paper and there is paper in it

Read all three bytes. The reply 1A FE 23 means paper is loaded and 1A EF 23 means it is not, so a check that looks only at the first byte and treats 1A as empty gets the answer backwards half the time. Decide on the second byte.

The label library's noPaper() reports empty on a full roll

It compares the first byte of the reply with 1A and calls that out-of-paper, but 1A opens both replies. Prefer your own three-byte read, as in the sketch here, or treat the library's result as a prompt to check rather than as an answer.

Status works, then stops working after a print

The printer sends its own unsolicited packets after a job — a print-finished or a print-failed notice — and those are still sitting in the buffer when the next query goes out, so the reply you read is the old packet. Flush anything waiting before you ask, which is what the first line of the function does.

Where this goes next

Four silences that look identical from the sketch, and the single observation that tells each one apart.

When nothing prints

Edit this page — content/books/thermal-printer/asking-about-paper.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

This page covers several products. Choose yours to see the right discussions.

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum