Count each confirmed part once: debounce the sensor in the input mapping, feed the clean signal to CTU (which counts rising edges), keep the batch counter separate from a lifetime total, make both retentive where the business needs it, and reset only the batch, under control.
- Count edges, never levels.
- Debounce a bouncing sensor before counting.
- Batch and lifetime are two counters with two reset rules.
Why PLC Production Counters Overcount
Three causes explain almost every wrong count: incrementing on the level instead of the edge (one part = many scans), a bouncing sensor that produces several edges per part, and a counter that is reset or lost when it should not be. Each has a simple fix, shown stage by stage below.
Lab Flow: From Part Sensor to Batch Complete
Every lesson in the Softwell PLC lab manual series follows the same six stages and the same address rule, so the code you write here plugs straight into the HMI lessons.
Stage 1Field Signal and PLC Tags
| PLC tag | Address | Type | Device / comment |
|---|---|---|---|
B60_Part | %I7.1 | Bool | Through-beam sensor at the outfeed |
H60_BatchDone | %Q3.6 | Bool | Batch complete lamp |
Stage 2Input Mapping with Debounce
// FC_InputMapping (or an FB with a static timer)
"T_B60_Deb"(IN := "B60_Part" XOR "DB_IO".B60_Part, PT := T#5MS); // must stay different for 5 ms
IF "T_B60_Deb".Q THEN
"DB_IO".B60_Part := "B60_Part"; // accept the new, stable state
END_IF;For pulses shorter than the scan, use a high-speed counter input instead – see the scan cycle lesson.
Stage 3Logic: CTU for the Batch, DInt for the Lifetime
// FB_Production – STAT: C_Batch : CTU_INT; PartOld : Bool;
#C_Batch(CU := "DB_IO".B60_Part, R := "DB_Count".Cmd_BatchReset, PV := "DB_Count".BatchPreset);
"DB_Count".BatchCV := #C_Batch.CV;
"DB_Count".BatchDone := #C_Batch.Q;
IF "DB_IO".B60_Part AND NOT #PartOld THEN // lifetime: never reset
"DB_Count".Lifetime := "DB_Count".Lifetime + 1; // DInt, Retain
END_IF;
#PartOld := "DB_IO".B60_Part;
"DB_Count".Cmd_BatchReset := FALSE; // one-shot from the HMI
// FC_OutputMapping
"H60_BatchDone" := "DB_Count".BatchDone;Shift totals, snapshots and CSV export build on this in the shift and production report.
Stage 4Link PLC Tags to the HMI
| HMI tag | PLC member | Used by |
|---|---|---|
DB_Count_BatchCV / _BatchPreset | "DB_Count".BatchCV / BatchPreset | CV/PV fields |
DB_Count_Lifetime | "DB_Count".Lifetime | Lifetime field |
DB_Count_Cmd_BatchReset | "DB_Count".Cmd_BatchReset | Reset button |
Stage 5Link the Graphics
| # | Object | Properties | Tag / event |
|---|---|---|---|
| ① | Output field CV | Format 99999 | DB_Count_BatchCV |
| ② | Input field PV | Limits 1 – 9999, authorisation Supervisor | DB_Count_BatchPreset |
| ③ | Button BATCH RESET | Confirmation; authorisation Supervisor | SetBit DB_Count_Cmd_BatchReset |
| ④ | Lamp batch complete | Appearance on BatchDone | DB_Count_BatchDone |
Who may reset counters is set in HMI user administration.
Stage 6Perform and Test: Three Ways to Count One Part
The same sensor feeds three counters: counting the level (wrong), counting the raw rising edge (wrong when the sensor bounces) and counting the debounced edge into CTU (right). Reset the batch, change the preset and power-cycle the CPU.
Troubleshooting
| Symptom | Likely cause | First check |
|---|---|---|
| Count jumps by hundreds | Counting the level | Use CTU or an edge |
| Two counts per part | Sensor bounce | Debounce in the mapping |
| Count lost after power cut | Not retentive | Retain in DB_Count |
| Lifetime reset with batch | Same counter used for both | Separate counters |
Hands-On Lab: Build and Prove a Production Counter
Hands-on- TIA Portal with an S7-1200 or PLCSIM
- A sensor or simulated input
- Estimated time: 60 minutes
Wire and declare the sensor
Declare B60_Part and the batch-complete lamp.
Debounce in the input mapping
Accept a new sensor state only after it is stable for 3 scans or 5 ms.
Count with CTU and a lifetime total
Use C_Batch (CTU, PV from the HMI) and a retentive DInt lifetime total.
Link HMI tags
Publish CV, PV, Q and the lifetime total.
Build the counter screen
Show CV/PV, a preset input and a reset button with rights.
Prove it
Compare with real parts, inject bounce, reset the batch and power-cycle the CPU.
Each part is counted exactly once, the batch resets under control, the lifetime total never resets, and counts survive a power cut.
Frequently asked questions
Why does my PLC counter increase every scan?
The program increments while the signal is true instead of only when it changes from false to true. Use a rising-edge pulse or an IEC counter, which counts edges at CU.
When should I use a high-speed counter?
When the input pulse can be shorter than the input filter or the scan cycle, such as encoders and fast packaging lines.
Should production counters be retentive?
It depends on their meaning. Batch and shift totals usually need retention through brief outages; temporary diagnostic counts may not. Document the restart and reset philosophy.
How do I stop a bouncing sensor from double counting?
Accept a new state only after it has been stable for a short time (a few ms or a few scans) and count the edge of that debounced signal.
Why keep a batch counter and a lifetime counter?
They answer different questions. The batch resets for every order; the lifetime total never resets and drives maintenance and machine history.
What do CU, R, PV, CV and Q mean on CTU?
CU counts rising edges, R resets CV to zero, PV is the preset, CV the current value, and Q becomes true when CV reaches PV.