Overview
Scanning a single barcode or 2D symbol to retrieve several discrete data items (material type, part number, lot/date code, quantity, operator ID, expiration date) is a routine material-handling and traceability requirement. The scan event delivers one continuous ASCII string over the scanner's serial, USB, or Ethernet/IP interface; the PLC must then split the string into individually addressable fields.
This reference covers symbology selection, payload encoding with delimiters, serial-port configuration on AutomationDirect PLCs (Productivity 1000/2000/3000/5000, Do-more DM1/DM2, BRX BX-DM, Click C0/C2), and the string instructions used to extract fields. Three parsing strategies are demonstrated: ASCII delimiter separation, fixed-width field slots, and identifier-prefixed (tagged) records.
Prerequisites
- AutomationDirect Productivity Series or Do-more PLC with a serial port or Ethernet scanner module
- Barcode/QR scanner supporting the ASCII full-range command set (most modern 1D/2D imagers)
- Productivity Suite v4.x or Do-more Designer v2.x programming environment
- Knowledge of the scanner's serial protocol (default 9600-8-N-1 with CR/LF terminator unless reconfigured)
- Reference to the ANSI/ISO ASCII table (ISO/IEC 646) for non-printable delimiters such as GS (0x1D) and RS (0x1E)
Selecting the Symbology
Encode length dictates the symbology. The table below maps payload size to recommended symbol.
| Symbology | Standard | Max Alphanumeric Capacity | Best Use Case |
|---|---|---|---|
| Code 128 | ISO/IEC 15417 | 48 (uncompressed ASCII subset) | Short multi-field labels, GS1-128 |
| Code 39 | ISO/IEC 16388 | 43 | Legacy part tags, alphanumeric only |
| Data Matrix | ISO/IEC 16022 | 2,335 ASCII | Direct part marking, small labels |
| QR Code | ISO/IEC 18004 | 4,296 ASCII (Version 40-L) | Panel HMI, engineering documents |
For two to five fields under ~30 characters total, Code 128 with GS1 Application Identifiers is standard. For more fields or longer records, switch to Data Matrix or QR.
Encoding Multiple Data Fields
Three reliable encoding schemes are field-proven for PLC consumption. The chosen delimiter MUST NOT appear in the source data values, and the scanner must be configured to transmit non-printable delimiters verbatim (do not enable "Convert GS to "} in the scanner setup menu).
Strategy 1: ASCII Delimiter Separation
Concatenate fields with a reserved single-byte separator. Recommended delimiters from the ISO 15417 GS1 specification:
| Symbol | Hex | Decimal | Description |
|---|---|---|---|
| GS | 1D | 29 | Group Separator - field separator |
| RS | 1E | 30 | Record Separator - record terminator |
| FS | 1C | 28 | File Separator - payload boundary |
| CR | 0D | 13 | Carriage Return - line end (often appended) |
| LF | 0A | 10 | Line Feed - line end (often appended) |
Example payload (GS delimited, CR/LF terminated):
STEEL<GS>PN-12345-A<GS>2025-11-14<GS>250<CR><LF>
Strategy 2: Fixed-Width Slots
Each field occupies a pre-defined number of bytes. Avoid if any field has variable length (e.g., serial numbers). Pad short values with a known character (typically space 0x20 or zero 0x30).
STEEL PN-12345-A 2025-11-14250
^^^^^^^^10^^^^^^^^^^^15^^^^^^^^10^^^3
Strategy 3: Identifier-Prefixed (GS1 AI)
Prepend each field with a numeric Application Identifier per the GS1 General Specifications. The PLC parser walks the string, reads the AI, then extracts the defined-length data.
| AI | Meaning | Format | Example |
|---|---|---|---|
| 10 | Batch/Lot | an..20 | (10)LOT-9876 |
| 11 | Production Date (YYMMDD) | n6 | (11)251114 |
| 17 | Expiration Date (YYMMDD) | n6 | (17)271114 |
| 21 | Serial Number | an..20 | (21)SN-00041 |
| 30 | Count | n..8 | (30)250 |
| 241 | Customer Part Number | an..30 | (241)PN-12345-A |
For unprefixed in-house tags, define a custom mapping table inside the PLC's data block.
PLC String Buffer Configuration
Define a receive buffer sized to the worst-case payload plus terminators. Reserve 256 bytes for 2D codes and 64 bytes for Code 128 to handle scan bursts without overrun.
| PLC Family | Receive Instruction | Buffer Type | Notes |
|---|---|---|---|
| Productivity 1000 | RX (Receive) | STRING | Serial port module P1-04S or P1-08S |
| Productivity 2000/3000/5000 | RX / EIP Scanner | STRING | Built-in RS-232/485 ports or P3-08S |
| Do-more DM1/DM2 | STREAMIN / RX | STRING | DM1P/R and DM2 series |
| BRX BX-DM | RX / STREAMIN | STRING | BX-P-SER serial option modules |
| Click C0/C2 | RX | STRING | RS-232/485 port, 50-char limit per RX |
Enable end-of-message terminator detection on the receive instruction (CR, LF, or GS+CR/LF). Without a terminator the instruction will hold the data until timeout.
Step-by-Step Parsing with Productivity Suite
- Configure the scanner: Set the interface to ASCII command mode. Disable prefix/suffix added by the scanner except for the required terminator (CR+LF). Enable the symbology you need. Document the default baud (typically 9600), data bits (8), parity (None), stop bits (1).
- Wire the serial port: Connect scanner TX to PLC RX (pin 2 to pin 2 on DB9, crossed for null modem). Reference the Productivity 1000 serial module installation guide for the wiring diagram and shield grounding practice.
-
Configure the RX instruction: In Productivity Suite, drop an RX instruction onto a rung tied to the serial port tag. Set:
-
RXLength= 256 (maximum) -
Terminator= 13 (CR), enable LF detection separately if needed -
String= destination STRING tag (e.g.,ScanBuffer[256])
-
-
Initialize parsing on first scan: Use the
FINDinstruction to locate the first GS (decimal 29) within the buffer. The substring left of the GS is field 1 (Material Type). -
Extract field 2: Use
MIDto copy from the character after the first GS to the character before the next GS. The result is Part Number. -
Extract field 3: Repeat using the second
FINDresult minus the prior offset to extract the Date. -
Extract field 4: Final field ends at the terminator; use
LEFTwith length = terminator position - field 3 end.
Example structured text fragment for the field extraction loop:
// Find first GS (decimal 29) delimiter
Pos1 = FIND(ScanBuffer, CHR(29), 1)
MaterialType = MID(ScanBuffer, 1, Pos1 - 1)
// Find second GS
Pos2 = FIND(ScanBuffer, CHR(29), Pos1 + 1)
PartNumber = MID(ScanBuffer, Pos1 + 1, Pos2 - Pos1 - 1)
// Find CR terminator (decimal 13)
Pos3 = FIND(ScanBuffer, CHR(13), Pos2 + 1)
ProdDate = MID(ScanBuffer, Pos2 + 1, Pos3 - Pos2 - 1)
// Optional 4th field (quantity) before terminator
Qty = TRIM(MID(ScanBuffer, Pos3 - 3, 3))
Do-more / BRX Reference Implementation
Do-more Designer exposes STREAMIN which handles arbitrary byte streams with built-in terminator handling, then string instructions STRCMP, STRFIND, STRMID, STRLEFT, STRRIGHT, and STRTRIM perform the parse. BRX (BX-DM) uses the same instruction set.
// Rung 1: receive into VB1000..VB1255
STREAMIN D/VB1000, .SCAN_LEN, 0, 13, 100, &VB0
// Rung 2: locate first GS
$V101 = STRFIND(VB1000, 29, 1) // 0-based offset returned
// Rung 3: parse material type
VB2000 = STRLEFT(VB1000, $V101)
// Rung 4: parse part number
VB2100 = STRMID(VB1000, $V101 + 1, $V102 - $V101 - 1)
Refer to the Do-more Designer Help file index for STREAMIN parameters and the BRX MPU user manual for option-module port assignments.
Verifying the Parse
- Create a 4-quadrant HMI tag page in Productivity View or C-more that displays each parsed field independently with the source string for visual comparison.
- Scan a known test label five times. Confirm each field value matches the expected text byte-for-byte, including leading/trailing characters.
- Force the receive buffer to a length-zero state and scan again to verify re-initialization; confirm no leftover data from the prior scan contaminates field 1.
- Test edge cases: missing trailing field (label truncated), embedded delimiter in a value (must be escaped at print time or use a different strategy), and double scans back-to-back within the receive timeout.
- Use the PLC's task monitor (Productivity Suite Task Manager or Do-more Data View) to inspect the STRING tag contents in real time.
Troubleshooting Matrix
| Symptom | Likely Cause | Diagnostic | Corrective Action |
|---|---|---|---|
| Buffer empty after scan | Wrong baud or wrong port | Loopback test (TX→RX jumper) send known string | Match scanner settings to RX instruction; verify port tag |
| Buffer contains garbage | Parity/data-bit mismatch | Read first 4 bytes as hex; look for FF FA pattern | Set both sides to 8-N-1; disable hardware flow control unless wired |
| Delimiter not found | Scanner strips non-printable | Hex-dump buffer from laptop tap | Disable "ASCII control char filter" in scanner; enable GS/RS passthrough |
| Field offset drift after each scan | Buffer not reset | Inspect RXLength return value |
Clear STRING on first CR; use a copy-to-buffer-then-clear pattern |
| RX never completes | No terminator transmitted | Terminator log in scanner | Add CR+LF suffix; configure RX to use 0x0A as alternate terminator |
| Only first field correct, rest shifted | FIXED-WIDTH mismatch | Compare actual byte positions to layout | Re-measure fields with hex monitor; document lengths in HMI help |
| Click PLC truncates at 50 chars | RX buffer size limit | Reference manual | Use BRX or Productivity series for 2D codes > 50 chars |
Field-Engineering Notes
- Print the same delimiter scheme on EVERY label template; mismatched delimiters between line A and line B are the single most common cause of data-corruption calls.
- Always terminate the scanner's transmitted string with CR or CR+LF; without it, the RX instruction waits the full timeout (typically 100 ms-1 s depending on configuration) before exposing data to the parser.
- Reserve the FS (0x1C) character as a payload boundary marker if you ever multiplex two barcode records into one scan event. PLCs cannot de-multiplex without an explicit record separator.
- For GS1-128 with AI parsing, store the AI length table (fixed vs variable) in a lookup block at startup; this avoids hard-coding lengths inside the parse rung and keeps the logic reusable.
- Do not perform ASCII string manipulation in the same scan that triggers a high-speed motion axis. Move the parsing to a separate low-priority task or interrupt to avoid scan jitter.
What is the simplest delimiter to use between fields when designing an in-house barcode label?
Use ASCII GS (0x1D, decimal 29). It is reserved for field separation in the GS1 specification, never appears in typical alphanumeric part data, and is supported as a passthrough character by virtually every modern 1D/2D imager. Configure the scanner to transmit GS unfiltered.
Can a Click series PLC handle QR codes with 100+ characters?
No. The Click C0 and C2 RX instruction accepts at most 50 characters per receive. Use the Productivity 1000/2000/3000/5000 or BRX BX-DM series with a 256-byte STRING buffer for QR or Data Matrix codes that exceed 50 bytes.
How do I parse GS1 Application Identifiers like (10)LOT9876 in a Productivity Suite project?
Read the two-digit AI after each opening parenthesis, look up its fixed length in a data block (e.g., AI 10 = variable up to 20 alphanumeric), then use MID to extract the exact byte range. The FNC1 separator (0x1D, GS) must be enabled as a passthrough on the scanner or variable-length AIs cannot be terminated.
What scanner settings cause the PLC to see only the first field after a delimiter?
The scanner is filtering ASCII control characters below 0x20. In most 2D imagers this setting is labeled "Send Control Characters," "GS Substitution," or "Enable ASCII Extended." Disable it so GS, RS, and CR pass through unmodified.
How should I handle a delimiter character that appears inside a part number?
Either (a) escape it at label print time by prefixing with a backslash and writing an unescape routine, (b) switch to a different delimiter that cannot legally appear in the data, or (c) move to fixed-width slots so the parser does not search for delimiters. Option (b) is the most common fix in practice.