PLC Data Types Explained: INT, REAL, BOOL & Type Conversion in Structured Text

Understand every IEC 61131-3 data type, when to use each one, and how to safely convert between them in Structured Text programs.

Why Data Types Matter in PLC Programming

Choosing the correct data type is one of the most critical decisions in PLC programming. The wrong type can cause overflow errors, precision loss, or unexpected behavior that's difficult to debug on a live machine. IEC 61131-3 defines a rich type system — mastering it is essential for reliable automation code.

Boolean: The Foundation of PLC Logic

BOOL is the most fundamental PLC data type, representing a single TRUE/FALSE value. Every digital I/O point maps to a BOOL.

VAR
    StartButton   : BOOL;    // Digital input
    MotorRunning  : BOOL;    // Internal state
    AlarmActive   : BOOL := FALSE;  // Initialized
END_VAR

// Boolean operations MotorRunning := StartButton AND NOT AlarmActive;

Boolean Best Practices

  • Use meaningful names: bMotorRunning not M001
  • Initialize all BOOLs explicitly to avoid undefined states
  • Avoid deeply nested boolean expressions — break them into intermediate variables
  • Integer Types: INT, SINT, DINT, LINT, UINT

    IEC 61131-3 defines several integer types with different ranges:

    TypeSizeRange
    SINT8-bit signed-128 to 127
    INT16-bit signed-32,768 to 32,767
    DINT32-bit signed-2,147,483,648 to 2,147,483,647
    LINT64-bit signed±9.2 × 10¹⁸
    USINT8-bit unsigned0 to 255
    UINT16-bit unsigned0 to 65,535
    UDINT32-bit unsigned0 to 4,294,967,295
    ULINT64-bit unsigned0 to 18.4 × 10¹⁸
    VAR
        PartCount     : INT;      // Typical counter
        BatchTotal    : DINT;     // Large accumulator
        SensorRaw     : UINT;     // Analog input (0–65535)
        MotorSpeed    : INT;      // Signed speed reference
    END_VAR

    // Overflow danger! INT max is 32767 PartCount := PartCount + 1; IF PartCount > 30000 THEN // Consider switching to DINT before overflow END_IF;

    Choosing the Right Integer Type

  • INT (16-bit): Default for counters, indexes, and small quantities
  • DINT (32-bit): Production totals, encoder positions, large accumulators
  • UINT/UDINT: Analog raw values, bit masks, addresses — never negative
  • SINT/USINT: Memory-constrained systems, byte-level communication
  • Floating-Point Types: REAL and LREAL

    REAL (32-bit) and LREAL (64-bit) handle decimal numbers for analog processing, PID control, and engineering calculations.

    VAR
        Temperature   : REAL;         // 32-bit float
        PreciseAngle  : LREAL;        // 64-bit double
        ScaleFactor   : REAL := 0.00610352;  // 20mA / 3277 counts
    END_VAR

    Temperature := INT_TO_REAL(SensorRaw) * ScaleFactor;

    Floating-Point Pitfalls

    Never compare REALs with equality:

    // WRONG — floating-point precision errors
    IF Temperature = 25.0 THEN ...

    // CORRECT — use a tolerance band IF ABS(Temperature - 25.0) < 0.01 THEN ...

    Precision loss with REAL:

    // REAL has ~7 significant digits
    // Values like 16777217.0 cannot be represented exactly
    // Use LREAL for high-precision applications
    

    Type Conversion Functions

    IEC 61131-3 requires explicit type conversion — there is no implicit casting. Every conversion uses a function named SourceType_TO_TargetType.

    Common Conversion Functions

    FunctionDescriptionExample
    INT_TO_REALInteger to floatrVal := INT_TO_REAL(iCount);
    REAL_TO_INTFloat to integer (truncates)iVal := REAL_TO_INT(rTemp);
    BOOL_TO_INTFALSE→0, TRUE→1iFlag := BOOL_TO_INT(bRun);
    INT_TO_BOOL0→FALSE, else→TRUEbActive := INT_TO_BOOL(iState);
    DINT_TO_REALLarge int to floatrTotal := DINT_TO_REAL(diCount);
    INT_TO_STRINGInteger to textsDisplay := INT_TO_STRING(iVal);
    STRING_TO_INTText to integeriVal := STRING_TO_INT(sInput);
    INT_TO_DINTWiden integerdiVal := INT_TO_DINT(iSmall);
    VAR
        RawAnalog   : UINT;    // 0-65535 from ADC
        EngValue    : REAL;    // Scaled engineering units
        DisplayStr  : STRING;  // For HMI display
    END_VAR

    // Step 1: Convert unsigned integer to REAL for math EngValue := UINT_TO_REAL(RawAnalog) * 100.0 / 65535.0;

    // Step 2: Format for display DisplayStr := CONCAT(REAL_TO_STRING(EngValue), ' %');

    REAL_TO_INT: Truncation vs Rounding

    A common source of bugs: REAL_TO_INT truncates (rounds toward zero) in most PLC platforms.

    VAR
        rValue : REAL := 3.7;
        iResult : INT;
    END_VAR

    iResult := REAL_TO_INT(rValue); // Result: 3 (not 4!)

    // To round properly, add 0.5 before converting: iResult := REAL_TO_INT(rValue + 0.5); // Result: 4

    Byte and Bit-Level Types: BYTE, WORD, DWORD

    These types are essential for communication protocols, register mapping, and bit manipulation.

    VAR
        StatusWord  : WORD;       // 16-bit register
        ErrorByte   : BYTE;       // 8-bit status
        bBit3       : BOOL;       // Extracted bit
    END_VAR

    // Extract bit 3 from a status word bBit3 := (StatusWord AND 16#0008) <> 0;

    // Set bit 5 StatusWord := StatusWord OR 16#0020;

    // Clear bit 5 StatusWord := StatusWord AND NOT 16#0020;

    TIME, DATE, and STRING Types

    VAR
        CycleTime   : TIME := T#100ms;
        StartDate   : DATE := D#2026-01-15;
        Greeting    : STRING := 'Hello PLC';
        LongText    : STRING(200);  // Extended length
    END_VAR

    // TIME arithmetic CycleTime := CycleTime + T#50ms; // T#150ms

    // STRING operations LongText := CONCAT('Batch: ', INT_TO_STRING(BatchNum));

    Structured Types: STRUCT and ARRAY

    For organizing related data:

    TYPE MotorData :
    STRUCT
        Speed     : REAL;
        Current   : REAL;
        Running   : BOOL;
        FaultCode : INT;
    END_STRUCT
    END_TYPE

    VAR Motor1 : MotorData; Drives : ARRAY[1..4] OF MotorData; END_VAR

    Motor1.Speed := 1500.0; Drives[2].Running := TRUE;

    Common Type Conversion Mistakes

    1. Integer Overflow

    VAR iCount : INT; END_VAR
    // If iCount = 32767:
    iCount := iCount + 1;  // Wraps to -32768!
    // Fix: Use DINT for large accumulators
    

    2. Division Precision Loss

    VAR
        iNumerator   : INT := 7;
        iDenominator : INT := 2;
        rResult      : REAL;
    END_VAR

    // WRONG: integer division happens first → 3.0 rResult := INT_TO_REAL(iNumerator / iDenominator);

    // CORRECT: convert before dividing → 3.5 rResult := INT_TO_REAL(iNumerator) / INT_TO_REAL(iDenominator);

    3. BOOL-to-INT Ambiguity

    // Some platforms: TRUE = 1, others: TRUE = -1 (16#FFFF)
    // Always use explicit conversion:
    iVal := BOOL_TO_INT(bFlag);  // Guaranteed 0 or 1
    

    Practice data type conversions in our online ST editor — experiment with INT, REAL, and STRING operations in real time.