A barcode whose payload carries a carriage return or a line feed scans, the HMI acknowledges the read, and the text input stays empty — or keeps only the part before the invisible character. Codes without those two bytes read normally, so the cable, the port and the input object all work. The failure sits one layer up: CR (0x0D) and LF (0x0A) are control characters, and a text input treats them as commands, not as characters. This page shows how to prove where the byte disappears, what your symbology and reader can do about it, and how to keep a multi-element payload intact, with the byte counts and the split arithmetic worked through.
Why do CR and LF never appear in an HMI text field?
CR (0x0D, decimal 13) and LF (0x0A, decimal 10) are ASCII control characters: they sit in the non-printing range 0x00–0x1F, so a text input treats them as actions — commit the entry, break the line — or filters them outright, and no glyph can ever appear.
Printable ASCII starts at 0x20, the space. Every byte below it is a control code with a function, not a shape: 0x0D moves the cursor to the start of a line, 0x0A moves it to the next. The control-character reference table lists the whole range.
STX (0x02) and ETX (0x03) are control characters too — yours work today only because your protocol layer consumes them as frame markers before the string reaches the field. A CR inside the payload takes the opposite path: it reaches the input handler itself, which commits whatever sits in the field or drops the scan when a length or format check fails. That is why the field can end up completely empty rather than showing the characters before the CR: an input object that commits on CR with an empty or too-short value discards the entry.
Is the scanner dropping the character or is the HMI hiding it?
Capture the bytes before you touch a setting: read the same code into a PC terminal or a script that prints byte values in hex, and if byte 13 or byte 10 appears inside the payload, the reader is sending it and the HMI path is hiding it.
The capture also tells the three input paths apart, because a fix on one proves nothing on another: in HID keyboard mode CR arrives as the Enter keystroke; over serial into an HMI input object it is a byte the object parses; into a PLC buffer it is just data. The input methods from a barcode scanner to a PLC cover the differences, and the keyboard-wedge path into an HMI behaves differently again.
Then locate the CR. One immediately after the last data byte is probably the reader's own suffix; one between two data elements is payload. Scan three test codes — CR at the end, CR mid-string, LF mid-string — and the pattern tells you whether the object rejects control bytes outright or commits early. If the HMI takes the reader over a serial port, its expected record framing matters as well; the serial-port framing for an HMI guide covers that side.
Decision: byte 13 in the capture means fix downstream, with the PLC split below. No byte 13 in the capture means the label or the reader is the cause, and the next two sections apply.
Can my barcode symbology carry a carriage return at all?
Code 128, QR Code and Data Matrix carry CR and LF as ordinary data; standard Code 39 cannot encode them at all, and the numeric symbologies (EAN/UPC, Interleaved 2 of 5) carry digits only.
| Symbology | CR or LF inside the payload? |
|---|---|
| Code 128 | Yes — the full 128-value ASCII set |
| QR Code | Yes — arbitrary bytes |
| Data Matrix | Yes — arbitrary bytes |
| Code 39, full-ASCII variant | Yes — the whole ASCII set via shift pairs |
| Code 39, standard | No — a 43-character set with no control characters |
| EAN/UPC, Interleaved 2 of 5 | No — digits only |
The table settles one confusing case. If the capture shows no CR and the label is standard Code 39, the character was never in the code; what fails is the reader's own suffix CR landing in a field that commits on CR — a different problem with the same symptom. Check the symbology before blaming the HMI.
If you control the label and the payload needs embedded separators, move to Code 128 or a 2D symbology. If the label is fixed, the fix lives downstream.
Which reader settings change which characters get sent?
Suffix and prefix settings change only the characters wrapped around the decoded data — the familiar CR suffix that acts as an Enter key — and they never touch a CR or LF sitting inside the payload; character substitution, where a reader offers it, is the only configuration-level cure.
Many readers ship with the CR suffix enabled so keyboard-connected software commits each scan. With a payload that already ends in its own CR, the host then sees two terminators. Disable the suffix when the payload frames itself — the prefix and suffix framing guide walks the settings.
If the reader's configuration offers match-and-replace, substitute the payload CR with the two printable characters \r (bytes 0x5C 0x72) and restore the real byte in the PLC if a downstream system needs it. Where the scanner is an industrial fixed code reader on a line, the same rules apply to its serial or Ethernet output.
How do I keep CR and LF data intact in the PLC and the HMI?
Receive the scan into a raw byte buffer, search it for byte 13 (0x0D) or byte 10 (0x0A), split the payload into fields at that index and write each field to its own string tag — the HMI then displays printable strings and never sees a control byte.
- Size the receive buffer for the longest payload plus suffix plus margin; 32 bytes covers the 19-byte example below.
- Search the buffer for the first byte equal to 13 or 10 and record its index. The byte-level search for 0x0D in a PLC receive buffer shows the pattern.
- Copy the bytes before the index into string tag 1 and the bytes after it into tag 2; the field-splitting pattern for barcode strings is the same one, just triggered by your control byte instead of a delimiter you chose.
- Display one field per string object. Most HMI platforms render a byte tag as decimal, hexadecimal or binary — 13 or 0x0D — and never as a glyph, so if you must show where the break fell, write the four printable characters
<CR>from the PLC. - Where a downstream message genuinely needs a line break, assemble it there from the known byte values; the CR and LF assembly for PLC message bodies page shows the byte-level construction.
The same handling applies when the source is a smart camera sending its decode string instead of a scanner: the payload, the terminator and the display rules do not change. If the payload length varies between reads, the variable-length input fix pairs with this split.
What does a payload with an embedded CR look like on the wire?
Take the payload LOT4821<CR>EXP2027-05 with the reader's CR suffix enabled: 19 bytes leave the scanner, the payload CR sits at index 7, and at 9,600 baud 8N1 the whole scan takes 19 × 10 ÷ 9,600 = 19.8 ms on the wire.
| Segment | Indices | Decimal byte values |
|---|---|---|
LOT4821 |
0–6 | 76 79 84 52 56 50 49 |
| CR, payload | 7 | 13 (0x0D) |
EXP2027-05 |
8–17 | 69 88 80 50 48 50 55 45 48 53 |
| CR, suffix | 18 | 13 (0x0D) |
The arithmetic: 7 + 1 + 10 + 1 = 19 bytes; 19 × 10 = 190 bits; 190 ÷ 9,600 = 0.01979 s, about 19.8 ms (10 bits per byte at 8 data bits, 1 start, 1 stop, no parity). The first byte 13 sits at index 7, so field 1 is indices 0–6 — LOT4821, 7 characters — and field 2 is indices 8–17 — EXP2027-05, 10 characters. A 16-byte string tag holds 15 characters where the platform stores a length byte, so both fields fit with room.
If your capture shows byte values that match nothing in this table, the problem is the serial link itself, not the CR — the garbage-character diagnosis for a PLC serial link covers baud, parity and cable causes.
Which fix should I choose for my case?
Fix it at the label if you print it, in the reader if its configuration can substitute characters, and in the PLC if neither is open to you — that order keeps every device downstream simple.
-
You print the label: encode Code 128 or QR and separate fields with a printable character that never occurs in the data — the pipe
|(0x7C) is a common choice. Every receiver then sees printable bytes only. -
The label is fixed, the reader has substitution: map 0x0D to
\rin the reader setup and undo it in the PLC where needed. - The label is fixed, the reader is plain: split the buffer in the PLC, following the steps above, and give each field its own string object.
- The payload is GS1: variable-length fields end with FNC1, which decoders output as GS, 0x1D (decimal 29) — a control character like CR, so plan the same split; it will not display either.
What do I check before going live?
Six checks cover the whole path: capture the bytes, count the terminators, confirm the symbology, size the strings, test the three code types, and decide the one side that commits the record.
- Hex capture on a PC: the payload bytes are present and the suffix byte is identified.
- One terminator per record: reader suffix off when the payload frames itself.
- Symbology confirmed: standard Code 39 cannot carry your separator; Code 128 or a 2D code can.
- String tag sizes: each tag holds its longest field plus margin — 16 bytes covers both example fields where a length byte is stored.
- Three test codes: a normal code, one ending in CR, one with CR or LF mid-string.
- Exactly one commit side: the HMI commits on CR, or the PLC frames the record — never both.
If the reading hardware is the piece you are replacing rather than the data path, the code reader finder filters fixed readers by interface and resolution, and the code-reading guides cover the rest of the chain from framing to PLC links.
Questions
What are the ASCII codes for CR, LF, STX and ETX?
CR is 0x0D (decimal 13), LF is 0x0A (10), STX is 0x02 (2) and ETX is 0x03 (3). All four sit in the non-printing control range 0x00-0x1F; printable ASCII starts at 0x20. An HMI can consume STX and ETX as frame markers while rejecting CR and LF inside the payload — same character family, different handling at each layer.
How do I check what my label software actually encoded?
Scan the label into a terminal or script that prints byte values in hex. Some label packages write the escape as two printable bytes, 0x5C 0x72, instead of a real CR, and some drop it silently. If you see 13, the byte is real; if you see 92 and 114, you have a literal backslash-r — a printable pair, not a control character.
Why does my scanner add a CR I never put in the barcode?
That is the suffix, not the payload. Many readers ship with a CR suffix enabled so keyboard-connected applications commit each scan like an Enter keypress. Reader setup codes toggle it. Disable it when your host frames records itself or the payload already ends in its own terminator, otherwise the second CR starts an empty record.
What character can I use instead of CR as a field separator?
Pick a printable character that never occurs in the data: the pipe | (0x7C) and the comma (0x2C) are common. Mind what the symbology reserves — GS1 already reserves FNC1, which decoders output as GS, 0x1D. Test the choice end to end: encode, scan, capture the bytes, then split on that single byte in the PLC.
Does USB keyboard mode handle CR differently from serial?
In HID keyboard mode CR becomes the Enter keystroke, so the input commits at the first CR and the rest of the payload lands as a new entry — often in the next field or nowhere. Over serial, CR is only byte 13 and your buffer logic decides what it means. If a payload must keep embedded separators intact, prefer the serial path into a PLC buffer.