结构化文本(ST)实现PLC温度数组1分钟定时存储的技术求助
解决ST语言中每隔1分钟存储温度到数组的问题
首先得明确:PLC的程序是循环扫描执行的,你原来写的FOR循环会在一个扫描周期里直接跑完所有6次赋值,根本不会有延迟。而且直接在循环里加阻塞延迟(比如DELAY指令)会导致整个PLC程序卡住,完全不可行。咱们得用非阻塞式定时+索引递增的思路来实现,下面给你两种实用方案:
方案一:全局变量跟踪索引+定时器状态(通用型)
这种方式几乎所有支持ST的PLC都能实现,逻辑清晰好调试:
先定义几个全局变量(如果是结构化编程,也可以放在功能块FB的内部变量里):
VAR_GLOBAL Temp: ARRAY[0..5] OF REAL; // 存储温度的目标数组 CurrentIndex: INT := 0; // 当前要写入的数组索引,初始从0开始 MinuteTimer: TON; // IEC标准的通电延时定时器(TON) DoneFlag: BOOL := FALSE; // 标记定时器触发是否已处理,避免重复执行 END_VAR主程序里的核心逻辑:
// 启动定时器:定时器未触发时,一直保持输入为TRUE,到1分钟后Q输出为TRUE MinuteTimer(IN := NOT MinuteTimer.Q, PT := T#1M); // 当定时器首次触发(Q从FALSE跳TRUE)时,执行存储操作 IF MinuteTimer.Q AND NOT DoneFlag THEN Temp[CurrentIndex] := tempsensor; // 把当前传感器值写入数组对应位置 DoneFlag := TRUE; // 标记已处理这次触发,防止同一扫描周期重复执行 // 索引递增,到数组上限后重置(如果需要循环覆盖旧数据的话) CurrentIndex := CurrentIndex + 1; IF CurrentIndex > 5 THEN CurrentIndex := 0; END_IF; END_IF; // 定时器复位时(Q变回FALSE),清空标记,准备下一次触发 IF NOT MinuteTimer.Q THEN DoneFlag := FALSE; END_IF;
方案二:上升沿检测+取模循环索引(简化版)
如果你的PLC支持R_TRIG(上升沿检测功能块),可以简化逻辑,少用一个标记变量:
VAR_GLOBAL Temp: ARRAY[0..5] OF REAL; CurrentIndex: INT := 0; MinuteTimer: TON; TimerRise: R_TRIG; // 上升沿检测功能块 END_VAR // 启动定时器并检测上升沿 MinuteTimer(IN := TRUE, PT := T#1M); TimerRise(CLK := MinuteTimer.Q); // 上升沿触发时执行存储+索引更新 IF TimerRise.Q THEN Temp[CurrentIndex] := tempsensor; CurrentIndex := (CurrentIndex + 1) MOD 6; // 用取模运算自动循环索引(0-5) MinuteTimer.IN := FALSE; // 若你的TON需要手动复位,这里加一行复位,下一个扫描周期再设回TRUE即可 END_IF;
关键注意事项
- 绝对禁用阻塞延迟:比如
DELAY T#1M这种指令会让PLC的扫描周期变成1分钟,其他控制逻辑完全瘫痪,工业现场绝对不能这么做。 - 匹配定时器时基:不同PLC的定时器时基可能不同(比如1ms、10ms、1s),设置
PT值要对应——比如1ms时基设60000,1s时基设60。 - 数组边界检查:一定要保证
CurrentIndex不会超出数组的0-5范围,避免触发数组越界错误。
内容的提问来源于stack exchange,提问作者Mazdak Khan




