Data Types

Reference for tag data types in rungs.dev — BOOL, SINT, INT, DINT, REAL, TIMER, COUNTER, CONTROL, FBD_TIMER, FBD_COUNTER, FBD_ONESHOT — what each holds and which instructions read or write it.

Every tag has a data type. The type decides what values the tag can hold, how much memory it uses, and which instructions can read or write it.

Summary

TypeUsed For
BOOLContacts, coils, one-shots, timer/counter status bits
SINTBytes: packed status, serial data, -128 to 127
INTDevice registers and drive words, -32768 to 32767
DINTCounts, presets, numeric values
REALAnalog values, setpoints, calculations
TIMERLadder timer tags — used by TON, TOF, RTO
COUNTERLadder counter tags — used by CTU, CTD
CONTROLLadder array tags — used by BSL, FFL, FAL and the rest of the Array tab
FBD_TIMERStructured Text timer function block — TONR, TOFR, RTOR
FBD_COUNTERStructured Text counter function block — CTUD
FBD_ONESHOTStructured Text one-shot function block — OSRI, OSFI

BOOL

A single bit — 0 or 1. The most common type in ladder logic — every contact and coil operates on a BOOL.

Use BOOL for:

  • Pushbuttons, limit switches, and other digital inputs
  • Motors, pilot lights, alarms, and other digital outputs
  • Internal flags — running, fault, ready, enabled
  • Status bits on structured tags (.DN, .EN, .TT, etc.)

Write BOOL values as 0 or 1. Do not use the strings "true" or "false".

DINT

A 32-bit signed integer. Range: -2,147,483,648 to 2,147,483,647.

Use DINT for:

  • Counts and totals
  • Timer and counter presets (in milliseconds / steps)
  • Numeric comparisons
  • Array indices

Example: PartsToday counts pieces produced; CycleTime.PRE sets a timer to 5000 ms.

Writing DINT literals

A plain number without a decimal point is a DINT literal: 42, -42, 0.

You can also write a DINT as a radix literal — a bit pattern in hexadecimal, binary, or octal. This is the natural way to write masks, where which bits are set matters more than the decimal value:

  • 16#00FF — hexadecimal (base 16), digits 0-9 and A-F. Same value as 255.
  • 2#0000_1111 — binary (base 2), digits 0 and 1. Same value as 15.
  • 8#377 — octal (base 8), digits 0-7. Same value as 255.

Underscores may group digits for readability — in radix literals (2#1010_1010) and in plain decimals (1_000_000) alike — and hex digits are case-insensitive (16#ff equals 16#FF).

A radix literal describes all 32 bits of the DINT, so it can name values a decimal literal writes with a minus sign: 16#FFFFFFFF is every bit set, which as a signed DINT is -1. The widest patterns are 16#FFFFFFFF, 2#1111_1111_1111_1111_1111_1111_1111_1111, and 8#37777777777 — anything wider than 32 bits is a compile error. Radix literals never take a sign: write the pattern itself, or use a decimal number.

SINT and INT

Narrower whole numbers, for data that arrives already sized by a device.

TypeBitsRangeWhere you meet it
SINT8-128 to 127A byte: packed status bits, serial data, a barcode character
INT16-32,768 to 32,767A device register: a drive speed word, a Modbus register, a raw analog count

Use them when the equipment you are talking to uses them. A drive that wants a speed reference from 0 to 32767 is describing an INT; a protocol that hands you bytes is describing SINT. For your own counters, totals and presets, use DINT.

Arithmetic is 32-bit, and overflow wraps

Arithmetic happens in 32 bits, and only the result is narrowed. In_A * In_B on two SINT tags is worked out in full and then cut down to fit when it is stored. So the answer can be right in the middle of a calculation and still not fit at the end.

A value that does not fit is not clipped — it wraps. Storing 300 in a SINT gives 44, not 127. Storing -129 gives 127. The controller keeps the low 8 bits (or 16 for an INT) and reads them back as a signed number:

Out_Byte := 300;    // Out_Byte is 44
Out_Byte := -129;   // Out_Byte is 127
Out_Reg  := 40000;  // Out_Reg is -25536

This is not an error — it is exactly what a real controller does, and the program still runs.

The top bit is the sign bit

Bits are numbered from 0, and the highest bit of a signed type carries the sign. Setting bit 7 of a SINT gives -128, and setting bit 15 of an INT gives -32768:

Out_Byte := 0;
Out_Byte.7 := 1;    // Out_Byte is -128

For the same reason there is no bit 8 on a SINT or bit 16 on an INT — the type has no such bit, and naming one is a compile error. A DINT has bits 0 to 31.

Hexadecimal is often the clearer way to write these values: 16#FF in a SINT is -1, and reads as "all eight bits set" rather than as a negative number.

REAL

A 32-bit floating-point number with decimal precision.

Use REAL for:

  • Temperatures, pressures, flow rates
  • Sensor readings that need decimal values
  • Engineering-unit calculations

Mixing REAL and DINT:

  • DINT / DINT into a DINT destination truncates toward zero (7 / 2 = 3).
  • DINT / DINT into a REAL destination keeps the fraction (7 / 2 = 3.5).
  • Any REAL operand into a DINT destination uses banker rounding (ties-to-even): 2.5 → 2, 3.5 → 4, −1.5 → −2.

Writing REAL literals

A REAL literal must contain a decimal point. Scientific notation needs a digit on both sides of the decimal point, and a leading + sign is not allowed.

  • Accepted: 3.14, -0.5, -.5, 1.0e3, -1.5e1, -2.5e2.
  • Rejected: 1e3 (no decimal), .5e2 (no digit before the decimal), +1.5e0 (unary + not allowed on literals).

To write a positive REAL literal, just omit the sign — 1.5e0, not +1.5e0. This matches the rule used by the current generation of Rockwell tooling.

See Arithmetic and Comparison Operators for the full division and rounding matrix, or the MOVE instruction for type conversion in ladder logic.

Structured types

TIMER, COUNTER, CONTROL, FBD_TIMER, FBD_COUNTER, and FBD_ONESHOT are structures, not single values. They expose named members (.PRE, .ACC, .DN, …) that your logic reads and writes on a rung.

Each instruction that uses a structured tag documents its members in the instruction reference — see the Ladder Logic and Structured Text instruction pages.

CONTROL

The array instructions keep their state in a CONTROL tag. Where a timer counts milliseconds, a control counts elements: .LEN is how many to work through and .POS is which one the instruction is on. .LEN and .POS are ordinary numbers your logic can read and write, and every array instruction reads them from the tag on every scan.

See Array Instructions for the full member list.

A structured tag can be Local — private to the instruction — or InOut, when the timer or counter belongs to the caller. It can never be an Input or an Output, which carry single values only. See Tag Usage.

Practice

Try data types in the Count Up exercise — a DINT counter that raises a BOOL Done flag when it reaches its target.

On this page