4. IEC 61131-3基础数据类型与变量

在TwinCAT中编写PLC程序,第一步往往不是写逻辑,而是决定“这个数据用什么类型装、放在哪里、谁能访问”。IEC 61131-3把数据类型和变量作用域规定得非常明确,理解它们能避免大量隐式转换错误、内存浪费和跨POU访问混乱。本节围绕BOOL、INT、REAL、STRING、ARRAY、STRUCT、枚举、别名与变量作用域展开,并结合TwinCAT 3的实际声明语法说明。

一、基本数据类型:先分清“位、整数、浮点、文本”

BOOL只占1位,取值TRUE/FALSE,常用于按钮、限位、使能、报警标志。INT是16位有符号整数,范围−32768~32767;DINT是32位有符号整数;UINT/USINT等无符号类型不能表示负数。REAL是32位浮点数,约7位有效数字;LREAL是64位浮点数,约15位有效数字。STRING是字符序列,默认长度80个字符,声明时可写STRING(20)限定长度。

选择类型时遵循“够用且不溢出”原则:计数小于3万用INT,累计产量、时间戳用DINT;模拟量、温度、速度用REAL;只有高精度运算才用LREAL。BOOL不要用来存0/1数值,否则后续运算需要反复转换。

VAR
    bStart      : BOOL;          // 启动按钮
    nCount      : INT := 0;      // 计数,范围足够
    rTemp       : REAL := 25.0;  // 温度,单位℃
    sRecipeName : STRING(20);    // 配方名,最长20字符
END_VAR

二、ARRAY:同类型数据的批量容器

ARRAY用于存放同类型、同含义的一组数据,例如8个工位的合格数、4轴的位置。声明格式为ARRAY[下限..上限] OF 类型。TwinCAT默认下限为0,但也可以写成1..8,便于与现场编号一致。访问用下标,如aCount[3]。注意下标越界不会自动报错,可能读到相邻内存,因此循环边界必须用LOWER_BOUND和UPPER_BOUND获取。

VAR
    aStationOK : ARRAY[1..8] OF INT;   // 8个工位合格数
    aAxisPos   : ARRAY[0..3] OF REAL;  // 4轴位置
END_VAR

FOR i := 1 TO 8 DO
    aStationOK[i] := 0;
END_FOR

三、STRUCT:把相关字段打包成一个对象

STRUCT用于描述一个“整体对象”,例如一个电机包含使能、速度、当前位置、报警码。声明用TYPE ... STRUCT ... END_STRUCT END_TYPE,然后像基本类型一样使用。STRUCT可以嵌套,也可以作为ARRAY元素,形成“结构数组”,非常适合多轴、多工位建模。

TYPE ST_Motor :
STRUCT
    bEnable  : BOOL;
    rSpeed   : REAL;   // 单位 r/min
    rPos     : REAL;   // 单位 mm
    nAlarm   : INT;
END_STRUCT
END_TYPE

VAR
    stAxis1 : ST_Motor;
    aAxis   : ARRAY[1..4] OF ST_Motor;
END_VAR

stAxis1.bEnable := TRUE;
aAxis[2].rSpeed := 1500.0;

四、枚举与别名:让代码可读、可维护

枚举(ENUM)用有名字的常量代替数字,例如设备状态。声明后变量只能取枚举成员,比较时不再写0、1、2。别名(ALIAS)给已有类型起一个业务名字,例如TYPE T_Temperature : REAL;,这样声明rTemp : T_Temperature;比直接写REAL更能表达含义,且底层仍是REAL,不增加开销。

TYPE E_State :
(
    eIdle   := 0,
    eRun    := 1,
    ePause  := 2,
    eFault  := 3
);
END_TYPE

TYPE T_Temperature : REAL; END_TYPE

VAR
    eMachine : E_State := eIdle;
    rInlet   : T_Temperature;
END_VAR

IF eMachine = eFault THEN
    ; // 处理故障
END_IF

五、变量作用域:LOCAL、VAR_GLOBAL、VAR_INPUT/OUTPUT

作用域决定变量“在哪里可见”。POU内部声明的VAR是局部变量,只在本POU内有效;VAR_INPUT由调用者传入,VAR_OUTPUT返回给调用者,VAR_IN_OUT是引用传递,函数内修改会影响外部变量。全局变量在VAR_GLOBAL中声明,整个工程可访问,但滥用会导致耦合和排障困难。TwinCAT中还可使用VAR_GLOBAL CONSTANT定义常量,或用VAR_STAT保持FB实例间共享。

VAR_GLOBAL
    gbSystemReady : BOOL;
    gnTotalCount  : DINT;
END_VAR

FUNCTION_BLOCK FB_Conveyor
VAR_INPUT
    bStart : BOOL;
    rSpeed : REAL;
END_VAR
VAR_OUTPUT
    bRunning : BOOL;
END_VAR
VAR
    nLocalStep : INT;
END_VAR
END_FUNCTION_BLOCK
命名建议:BOOL用b前缀,INT用n,DINT用di,REAL用r,STRING用s,结构体用st,枚举用e,全局用g。这样在TwinCAT的变量监视和交叉引用中能快速定位。

六、类型选择与作用域的实际判断

假设要做一个4轴搬运站:每轴需要使能、目标位置、当前位置、报警码,还要统计每轴完成次数。合理做法是定义ST_Axis结构体,再用ARRAY[1..4] OF ST_Axis;完成次数用ARRAY[1..4] OF DINT;设备状态用枚举E_State;温度用别名T_Temperature。轴控制逻辑封装在FB中,输入输出通过VAR_INPUT/VAR_OUTPUT传递,只有系统级就绪和总计数放全局。这样既避免了全局变量泛滥,又让数据类型与业务含义一一对应。

需要特别注意的是类型转换:INT与REAL混合运算时,TwinCAT不会自动把INT提升为REAL,必须显式写INT_TO_REAL(nCount);REAL转INT会截断小数,需要四舍五入时用REAL_TO_INT(rTemp + 0.5)。STRING与数值之间也要用INT_TO_STRING等转换函数,不能直接赋值。

IEC 61131-3 数据类型与变量作用域关系图 基本数据类型 BOOL : 1位 TRUE/FALSE INT : 16位 −32768~32767 DINT : 32位 大计数 REAL : 32位 约7位有效 STRING: 文本,可限长 派生数据类型 ARRAY[1..8] OF INT STRUCT 多字段对象 ENUM 命名状态常量 ALIAS 业务类型别名 可嵌套 / 可组合 变量作用域 VAR : 局部,仅本POU可见 VAR_INPUT : 调用者传入 VAR_OUTPUT : 返回给调用者 VAR_IN_OUT : 引用传递,可改外部 VAR_GLOBAL : 全局,慎用 组合 声明 TwinCAT 声明示例:4轴搬运站 TYPE ST_Axis : STRUCT bEnable:BOOL; rTarget:REAL; rPos:REAL; nAlarm:INT; END_STRUCT END_TYPE VAR aAxis : ARRAY[1..4] OF ST_Axis; aDone : ARRAY[1..4] OF DINT; eState : E_State; END_VAR FB 内:VAR_INPUT bStart:BOOL; rSpeed:REAL; VAR_OUTPUT bRunning:BOOL; VAR nStep:INT; END_VAR 必须显式转换 INT_TO_REAL(nCount) REAL_TO_INT(rTemp + 0.5) // 四舍五入 INT_TO_STRING(nCount) 选择原则 计数 < 3万 → INT;累计量 → DINT 模拟量/温度/速度 → REAL 状态 → ENUM;业务量 → ALIAS

把类型和作用域定清楚后,后续的FB封装、HMI变量绑定和在线监视都会顺畅很多。建议在项目初期就建立自己的类型库(DUT),把ST_、E_、T_开头的类型集中管理,避免每个POU重复定义。