free quality report for PLCopenXML exports

REAL_TO_TIME truncates your setpoint, and the compiler is fine with it

An operator sets 2.7 seconds. The PLC runs 2.0. Nothing in the project is marked as wrong: it compiles, downloads and runs. The value was lost in a single line of type conversion.

2026-08 · All write-ups

The line

Somewhere between the HMI value and the timer preset there is a conversion, and it usually looks like this:

tPulse := REAL_TO_TIME(rSetpointSec) * 1000;
// intent: seconds → milliseconds

What actually happens

REAL_TO_TIME does not convert seconds. It takes the number as a count of milliseconds and returns a TIME, whose resolution is one millisecond. So 2.7 becomes T#2ms — the fraction is gone at the conversion. The multiply that follows then scales an already damaged value: T#2ms * 1000 = T#2s.

The setpoint didn't drift. It was rounded down before it was used, and every value between 2.0 and 2.9 produces the same result on the machine.

Why the compiler stays silent

Every step is legal. REAL_TO_TIME accepts a REAL, multiplying a TIME by an integer is defined in IEC 61131-3, and the assignment types match. There is no rule being broken — the meaning is wrong, not the syntax. Type conversion is exactly where a compiler stops being able to help you: it checks that the types line up, not that the number still means what you meant.

The correct conversion

Scale first, convert second — so the fraction is still there when the value becomes milliseconds:

tPulse := REAL_TO_TIME(rSetpointSec * 1000);
// 2.7 → 2700.0 → T#2s700ms

The same mistake in other clothes

The pattern is not specific to REAL_TO_TIME. It appears wherever a conversion narrows a value and a scaling factor is applied afterwards:

iPercent := REAL_TO_INT(rRatio) * 100;
// 0.85 → 1 → 100, not 85

iPercent := REAL_TO_INT(rRatio * 100);
// 0.85 → 85.0 → 85

How to find it in your own project

Without any tool: search the project for _TO_TIME and _TO_INT, and look at what stands to the right of each conversion. If there is a multiplication or a division after the closing parenthesis, read that line twice — a scaling factor outside the conversion is the signature of this bug.

Two more places worth checking while you are there: conversions fed directly from an HMI variable (the operator can enter a fraction the code never expected), and any TIME preset that a colleague once described as “close enough” on site.

Catching it automatically

This is one of the 34 checks in PLC Lint. It reads a PLCopenXML export of your project and reports the conversions where the scaling happens outside — with the POU and the line. You can run it on your own machine so the export never leaves it, or upload it here and get the report in about ten seconds.

Processing happens in memory — the uploaded code is not stored. The tool advises; code changes are up to the engineer (see what the linter can't see). What happens to your code → · Your code & privacy · Industry benchmark · Feedback · GitHub