Barcode scans arrive when they arrive: two codes a second apart in a burst, then minutes of nothing. If the PLC-to-HMI link is a polled DATA_WAITING level feeding a single BARCODE_DATA string register, a stress run of 1000 codes drops a handful, and so does production. The fix is a full handshake: a sequence number stamped on every scan, request and echo-confirm between the PLC and the consumer, and arithmetic that sizes the poll interval, the dwell and the FIFO before you deploy. The reader-to-PLC half of the path is its own subject, covered by the barcode reader PLC communication plan; below is the PLC-to-HMI half.
Why the polled level drops scans
DATA_WAITING is a level: on whenever SCANNER_FIFO holds at least one string. A level answers whether there is work, not how many items or which one, and the three ways this design loses codes all follow from that.
- Identical consecutive strings. BARCODE_DATA goes from one lot code to the same lot code. Nothing in the string changed, so a change-triggered consumer never fires. Real lines repeat lot numbers back to back all day, so this drop survives randomized stress tests and shows up only in production.
- The request that never clears. HMI_DATA_REQUEST written to 1 and left there lets the PLC pop one string per dwell expiry as long as the FIFO is non-empty. A single register overwritten faster than its consumer samples it silently discards the intermediate values.
- The throughput ceiling. Every code needs its own poll sighting plus dwell before the next one is served, which caps the link at a rate the sizing section computes.
The PLC side of the design is not the fault: a scan class at 250 ms pushes every scan into SCANNER_FIFO, which is why a 1000-code stress run missed codes only after the FIFO, at the hand-off. Edge-versus-level discipline bites inside the PLC too: a copy instruction you believe sits behind an edge contact but that actually executes every scan will double-pop the queue. That copy-every-scan fault and its fix is worth ten minutes before you blame the script.
The full handshake: sequence, request, echo-confirm
The repair is the standard register-exchange handshake, the same discipline as sending vision coordinates to a PLC through a register handshake:
- Stamp every scan. When the PLC pushes a string into SCANNER_FIFO, it pairs the string with a sequence number: parallel queues STRING_FIFO and SEQ_FIFO, or one queue of combined elements. The stamp guarantees consecutive scans always differ, so two identical lot codes register as two events.
- Request one item. The consumer pulses HMI_DATA_REQUEST: write 1, then 0, so the PLC sees an edge.
- Pop and echo. On the request edge the PLC pops both queues into BARCODE_DATA and BARCODE_SEQ, then copies the popped sequence into ECHO_SEQ.
- Consume and confirm. The consumer writes the database record, updates the HMI counters, then writes DONE_SEQ equal to BARCODE_SEQ.
- Serve the next only after the confirm. The PLC pops nothing further until ECHO_SEQ equals DONE_SEQ.
The rule this enforces: no FIFO item is overwritten or dropped before its consumer confirms it was taken. The 500 ms dwell disappears with it, because the dwell existed only to make a level blink between pops and the confirm now does that job. Sequence numbers also give a free audit: a database query must return consecutive values, and any gap names the exact scan that was lost. Once a string is confirmed, splitting it into lot and part number fields is where the parsing belongs.
Alternating buffers: the two-slot variant
For lines under about one scan per second, a slimmer pattern works. Hand each scan to BUFFER_A or BUFFER_B alternately, scan n to slot n mod 2, and let each slot drive its own change-triggered consumer. A second scan cannot overwrite the first while it sits in the other slot, and the two consumers run in parallel. Keep the scan counter visible so ordering is known and a skipped slot, meaning three codes arriving between consumption cycles, is caught and re-requested from the PLC FIFO. The same split-register idea appears in two barcode scans into separate HMI data entry fields. Use the two-slot variant when rate is low and strict ordering does not matter; past about one scan per second, run the full FIFO handshake.
Sizing the poll and the FIFO
Two numbers size the link: how fast it can serve codes, and how deep the queue must be to survive a consumer outage.
T_poll is the poll interval in ms, the worst-case wait before the consumer sights a newly set level. T_dwell is any forced off-time between pops; the echo-confirm handshake sets it to 0. The 60000 is ms per minute, so R_max comes out in codes per minute. Arrival above R_max grows the queue during every run, and overflow drops codes at peak production, the worst possible time. For depth, r is arrival in codes per second and t_outage is the longest consumer outage in seconds, a client restart or a gateway deploy, with the factor of 2 as margin.
The PLC-side housekeeping behind such queues, FIFO status bits and pointer discipline, is the territory of moving data every scan cycle: techniques and status bits.
Worked example: 1000 ms poll, 500 ms dwell, 250 ms scan class
Inputs, from a real commissioning case of exactly this design: T_poll = 1000 ms (the client script interval), T_dwell = 500 ms (the PLC dwell between data requests), a scan class at 250 ms slow rate on the trigger and string tags, and a stress run of 1000 simulated codes that lost a few at the HMI.
Rule: one code leaves the FIFO only after the poll sights the level, worst case one full interval, and the dwell expires, so R_max = 60000 / (T_poll + T_dwell).
Arithmetic:
- T_cycle = 1000 ms + 500 ms = 1500 ms
- R_max = 60000 / 1500 = 40 codes per minute
- Demand at one scan per second is 60 codes per minute, a shortfall of 60 - 40 = 20 codes per minute
- After a 5 minute run the queue is 20 × 5 = 100 codes deep; an array limit or a client restart inside that window drops codes, which is the few-per-1000 the stress run showed
Decision:
- Sustained demand under 40 codes per minute, one scan every 1500 ms or slower: the polled level link holds. Still add sequence stamps, because the duplicate-string drop is independent of rate.
- Demand at 60 codes per minute: cut the poll to 250 ms to match the scan class and delete the dwell. R_max = 60000 / 250 = 240 codes per minute, 4× headroom over the line.
- FIFO depth on the same line: a worst outage of 30 s with the client closed for a restart gives D_min = 2 × (60/60) × 30 = 60 codes, so size the array at 64.
Run the consumer in the gateway, not in the client
A client-side consumer is a second drop mechanism hiding in plain sight. The operator closes the HMI window, the script stops, scans keep arriving, and the next shift inherits a backlog that overflows the FIFO. Run the consumer where it cannot die with a window: a gateway-side tag event on BARCODE_SEQ, or a scheduled script that drives the handshake loop. The HMI screen then only displays what the gateway has already committed.
Platforms also differ in what happens when a tag changes while its change script is still running: some queue the trigger, some coalesce it. The sequence handshake makes that difference irrelevant, because the consumer pulls one confirmed item per request instead of trying to catch every change. The event-handling pitfalls of writing that consumer are covered in barcode scan event handling without recursive updates, and the same pull-into-a-queue consumer on a 500 ms timer is worked through for another HMI platform in sampling a tag into a FIFO queue in VBScript.
When the queue belongs upstream: readers and controllers
Past a few codes per second, or whenever the HMI link also carries MES transactions, stop hauling raw streaming strings through the PLC. Fixed code readers decode and buffer on board and push strings over Ethernet themselves; a vision controller with several Ethernet ports then separates reader traffic from the HMI gateway and the plant network, and the PLC receives a clean handshake result instead of the stream. Browse the fixed code readers and the code reader finder to size the reader, and the vision controllers for the box between the networks.
- Interface
- Fast Ethernet
- Resolution
- Up to 3 MP
- Shutter
- Global
- Lens mount
- M12
For compact stations, the MV-ID3013PM-12M-WBN pairs a 12 mm lens with a 1.3 MP sensor on Fast Ethernet, the same Ethernet the handshake rides.
- Interface
- Fast Ethernet
- Resolution
- 5 MP
- Sensor format
- 1/1.7"
- Shutter
- Global
The LS-CRD-0028 decodes up to 60 codes/s at 30 fps on a 2560 x 2048 sensor with an 8 mm lens. At 3600 codes per minute that is 90× the 40 codes per minute the polled link served in the worked example, which is the whole argument for queuing in the reader and handing the PLC a finished result.
- LAN ports
- 5+ LAN ports
- USB 3 ports
- 3-4 USB 3 ports
- Light outputs
- 4 built-in channels
- Memory
- 8 GB
The MV-VC3301H-128G66 gives the cell an Intel Core i3, 8 GB of memory and 5+ LAN ports, so reader, gateway and plant traffic land on separate ports instead of sharing one.
The configurator matches a camera, lens, light, light controller and cables to each other, step by step, and lists only parts that fit what you already picked.
Checks before you sign off the link
Run these five before calling the link done:
- Rate test. Inject 1000 codes at your fastest sustained arrival and count database rows against the sequence numbers. Zero gaps is the pass mark.
- Duplicate test. Scan one code 20 times back to back; all 20 must land. With sequence stamps they are 20 distinct events.
- Outage test. Kill the consumer mid-run and bring it back. The FIFO must hold the backlog and drain it with no missing sequence.
- High-water mark. Alarm at 75% FIFO depth in the PLC. The peak depth you record is your link's real service rate, measured rather than calculated.
- Pulse discipline. Request and confirm travel as edges or pulses, never as levels left set. A request left at 1 is how the double-pop started.
More integration patterns sit on the systems topic page. If the sizing says your link is undersized, resize it with the formulas above or move the queue upstream; for help mapping the handshake onto your PLC and HMI platforms, contact the applications team.
Questions
How many codes per minute can a PLC-to-HMI handshake carry?
Divide 60000 ms by the poll interval plus any forced dwell. A 1000 ms poll with a 500 ms dwell serves 40 codes per minute; a 250 ms poll with no dwell serves 240. For scale, a mid-range fixed reader decodes tens of codes per second, so the HMI link, not the reader, is nearly always the bottleneck. Keep sustained demand under a quarter of the link's ceiling and the queue never grows during a run.
Where should the barcode queue live?
In the PLC or on the gateway server, never in an HMI client. A client-side array dies with the window: the operator closes it, scans keep arriving, and the data is gone when it reopens. A PLC FIFO survives client restarts and holds the backlog through a gateway restart up to its depth, which is why the depth sizing matters more than script efficiency.
Do I still need the 500 ms dwell between data requests?
No. The dwell exists to make a level bit blink so a slow poll cannot miss the gap between pops. A sequence-and-echo handshake needs no dwell: the PLC pops strictly on request and waits for the confirm before serving the next item, so the level can stay high throughout. Deleting the dwell alone lifts the 1000 ms link from 40 to 60 codes per minute; a 250 ms poll then reaches 240.
How wide should the sequence number be?
A 16-bit counter covers most lines: at 60 codes per minute it wraps after 65535 scans, about 18 hours, and the consumer can treat a decreasing sequence as a valid wrap. Store the sequence with each database record so one query proves no rows are missing. Lines that archive continuously across shifts are simpler on a 32-bit counter, which removes the wrap logic entirely.
Can the reader feed the HMI directly instead of going through the PLC?
Yes, and it is the better architecture when the PLC does not need the code for control. A reader that pushes strings over Ethernet or serial straight to the gateway removes the poll link altogether, and the gateway handles database writes and counters. Keep the PLC in the path when the code drives a reject gate, a diverter or an interlock, because machine control should never wait on an HMI link.


