系统函数与库
Darra PLC 运行时提供丰富的标准库函数,涵盖类型转换、数学运算、位操作、字符串处理、日期时间、边缘检测、定时器、计数器、通讯和诊断等类别。本文档按功能域分类列出各函数的签名、说明与使用示例。
1. 类型转换函数
类型转换函数遵循 源类型_TO_目标类型 命名约定,支持所有基本数据类型间的显式转换。
整数间转换
| 函数 | 输入 | 返回 | 说明 |
|---|---|---|---|
BOOL_TO_BYTE | BOOL | BYTE | TRUE → 16#01, FALSE → 16#00 |
BOOL_TO_INT | BOOL | INT | TRUE → 1, FALSE → 0 |
BOOL_TO_DINT | BOOL | DINT | TRUE → 1, FALSE → 0 |
BYTE_TO_BOOL | BYTE | BOOL | 0 → FALSE, 非 0 → TRUE |
BYTE_TO_INT | BYTE | INT | 无符号扩展 |
BYTE_TO_DINT | BYTE | DINT | 无符号扩展 |
INT_TO_BYTE | INT | BYTE | 截断低 8 位 |
INT_TO_DINT | INT | DINT | 符号扩展 |
INT_TO_WORD | INT | WORD | 位模式不变 |
DINT_TO_INT | DINT | INT | 截断低 16 位,超出范围截断 |
DINT_TO_BYTE | DINT | BYTE | 截断低 8 位 |
DINT_TO_WORD | DINT | WORD | 截断低 16 位 |
WORD_TO_DINT | WORD | DINT | 无符号扩展 |
WORD_TO_INT | WORD | INT | 位模式不变 |
VAR
bFlag : BOOL := TRUE;
byCode : BYTE;
iValue : INT;
diValue : DINT;
wWord : WORD;
END_VAR
byCode := BOOL_TO_BYTE(bFlag); // 16#01
iValue := BYTE_TO_INT(byCode); // 1
diValue := INT_TO_DINT(iValue); // 1
wWord := INT_TO_WORD(iValue); // 16#0001
浮点与整数间转换
| 函数 | 输入 | 返回 | 说明 |
|---|---|---|---|
REAL_TO_INT | REAL | INT | 舍入到最近整数,半入 |
REAL_TO_DINT | REAL | DINT | 舍入到最近整数,半入 |
REAL_TO_STRING | REAL | STRING | 格式化为十进制字符串 |
INT_TO_REAL | INT | REAL | 整数转浮点 |
DINT_TO_REAL | DINT | REAL | 双精度整数转浮点 |
STRING_TO_REAL | STRING | REAL | 字符串解析为浮点值 |
STRING_TO_INT | STRING | INT | 字符串解析为整数 |
STRING_TO_DINT | STRING | DINT | 字符串解析为双精度整数 |
时间与日期转换
| 函数 | 输入 | 返回 | 说明 |
|---|---|---|---|
TIME_TO_DINT | TIME | DINT | 时间值转换为毫秒数 |
TIME_TO_REAL | TIME | REAL | 时间值转换为毫秒浮点数 |
DINT_TO_TIME | DINT | TIME | 毫秒数转换为时间值 |
REAL_TO_TIME | REAL | TIME | 浮点毫秒数转换为时间值 |
DATE_TO_STRING | DATE | STRING | 日期格式化为 YYYY-MM-DD |
STRING_TO_DATE | STRING | DATE | 解析 YYYY-MM-DD 格式字符串 |
TOD_TO_TIME | TOD | TIME | 时刻转换为当日偏移时长 |
TIME_TO_TOD | TIME | TOD | 时长转换为当日时刻 |
VAR
tDuration : TIME := T#2s500ms;
diMillis : DINT;
rMillis : REAL;
dToday : DATE := D#2026-04-07;
sDate : STRING[12];
todNow : TOD;
tOffset : TIME;
END_VAR
diMillis := TIME_TO_DINT(tDuration); // 2500
rMillis := TIME_TO_REAL(tDuration); // 2500.0
sDate := DATE_TO_STRING(dToday); // "2026-04-07"
tOffset := TOD_TO_TIME(todNow); // 当日偏移毫秒数
2. 数学函数
基础运算
VAR
rValue : REAL := -25.0;
rAbs : REAL;
rSqrt : REAL;
rLn : REAL;
rLog : REAL;
rExp : REAL;
rPower : REAL;
END_VAR
rAbs := ABS(rValue); // 25.0
rSqrt := SQRT(ABS(rValue)); // 5.0
rLn := LN(10.0); // 2.302585
rLog := LOG(100.0); // 2.0 (常用对数)
rExp := EXP(1.0); // 2.718282
rPower := EXPT(2.0, 8.0); // 256.0
| 函数 | 输入 | 返回 | 说明 |
|---|---|---|---|
ABS(x) | 数值 | 同输入 | 绝对值 |
SQRT(x) | REAL/LREAL | REAL/LREAL | 平方根,x ≥ 0 |
LN(x) | REAL/LREAL | REAL/LREAL | 自然对数,x > 0 |
LOG(x) | REAL/LREAL | REAL/LREAL | 常用对数(底 10),x > 0 |
EXP(x) | REAL/LREAL | REAL/LREAL | 指数函数 e^x |
EXPT(x, y) | REAL, REAL | REAL | 幂运算 x^y |
三角函数
VAR
rAngle : REAL := 1.5708; // π/2 弧度
rSin : REAL;
rCos : REAL;
rTan : REAL;
rAsin : REAL;
rAcos : REAL;
rAtan : REAL;
END_VAR
rSin := SIN(rAngle); // ≈ 1.0
rCos := COS(rAngle); // ≈ 0.0
rTan := TAN(0.7854); // ≈ 1.0
rAsin := ASIN(1.0); // 1.5708
rAcos := ACOS(0.0); // 1.5708
rAtan := ATAN(1.0); // 0.7854
| 函数 | 输入 | 返回 | 说明 |
|---|---|---|---|
SIN(x) | REAL/LREAL | REAL/LREAL | 正弦,x 为弧度 |
COS(x) | REAL/LREAL | REAL/LREAL | 余弦,x 为弧度 |
TAN(x) | REAL/LREAL | REAL/LREAL | 正切,x 为弧度 |
ASIN(x) | REAL/LREAL | REAL/LREAL | 反正弦,x ∈ [-1, 1] |
ACOS(x) | REAL/LREAL | REAL/LREAL | 反余弦,x ∈ [-1, 1] |
ATAN(x) | REAL/LREAL | REAL/LREAL | 反正切 |
舍入与截断
VAR
rValue : REAL := 3.14159;
rTrunc : REAL;
rRound : REAL;
rCeil : REAL;
rFloor : REAL;
iTrunc : INT;
END_VAR
rTrunc := TRUNC(rValue); // 3.0
rRound := ROUND(rValue); // 3.0
rCeil := CEIL(rValue); // 4.0
rFloor := FLOOR(rValue); // 3.0
iTrunc := TRUNC(rValue); // 3 (返回 INT)
| 函数 | 输入 | 返回 | 说明 |
|---|---|---|---|
TRUNC(x) | REAL | REAL 或 INT | 截断小数部分(向零舍入) |
ROUND(x) | REAL | REAL | 四舍五入到最近整数 |
CEIL(x) | REAL | REAL | 向上取整(向 +∞) |
FLOOR(x) | REAL | REAL | 向下取整(向 -∞) |
选择与限幅
VAR
rA : REAL := 10.0;
rB : REAL := 20.0;
rC : REAL := 30.0;
rSel : REAL;
rMax : REAL;
rMin : REAL;
rLimit : REAL;
iMux : INT;
bCond : BOOL := TRUE;
END_VAR
rSel := SEL(bCond, rA, rB); // 10.0 (bCond=TRUE 返回 rA)
rMax := MAX(rA, rB, rC); // 30.0
rMin := MIN(rA, rB, rC); // 10.0
rLimit := LIMIT(rA, rC, rB); // 20.0 (值 30 被限幅在 [10, 20])
iMux := MUX(1, 100, 200, 300); // 200 (K=1 返回第 2 个参数)
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
SEL(G, IN0, IN1) | BOOL, T, T | T | G=TRUE 选 IN0,G=FALSE 选 IN1 |
MAX(IN0, IN1, ...) | T, T, ... | T | 返回最大值,支持 2+ 参数 |
MIN(IN0, IN1, ...) | T, T, ... | T | 返回最小值,支持 2+ 参数 |
LIMIT(MN, IN, MX) | T, T, T | T | 限幅:MN ≤ IN ≤ MX |
MUX(K, IN0, IN1, ...) | INT, T, T, ... | T | 多路选择器,K 为通道索引 |
3. 位操作函数
移位操作
VAR
wValue : WORD := 16#00FF;
wShifted : WORD;
diValue : DINT := 16#000000FF;
diShifted : DINT;
wRotated : WORD;
END_VAR
wShifted := SHL(wValue, 4); // 16#0FF0 (左移 4 位)
wShifted := SHR(wValue, 4); // 16#000F (右移 4 位)
diShifted := SHL(diValue, 8); // 16#0000FF00
wRotated := ROL(wValue, 4); // 16#0FF0 (循环左移)
wRotated := ROR(wValue, 4); // 16#F00F (循环右移)
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
SHL(IN, N) | 任意位类型, INT | 同输入 | 逻辑左移 N 位,低位补 0 |
SHR(IN, N) | 任意位类型, INT | 同输入 | 逻辑右移 N 位,高位补 0 |
ROL(IN, N) | 任意位类型, INT | 同输入 | 循环左移 N 位 |
ROR(IN, N) | 任意位类型, INT | 同输入 | 循环右移 N 位 |
位测试
位测试通过 SEL 与掩码组合实现,Darra 扩展支持直接位索引访问:
VAR
wStatus : WORD := 16#A5A5;
bBit7 : BOOL;
wMasked : WORD;
END_VAR
// 位测试
bBit7 := (wStatus AND 16#0080) <> 0; // 读 bit7
// 位置位/清零
wStatus := wStatus OR 16#0020; // 置位 bit5
wStatus := wStatus AND NOT 16#0020; // 清零 bit5
// 位翻转
wStatus := wStatus XOR 16#0001; // 翻转 bit0
// 位域提取
wMasked := SHR(wStatus, 4) AND 16#000F; // 提取 bit4-7
4. 字符串函数
IEC 61131-3 标准字符串函数,字符串索引从 1 开始计数。
VAR
sSource : STRING[64] := 'Darra PLC 系统';
sResult : STRING[64];
sPart : STRING[32];
iLen : INT;
iPos : INT;
END_VAR
iLen := LEN(sSource); // 14
sPart := LEFT(sSource, 5); // "Darra"
sPart := RIGHT(sSource, 3); // "系统"
sPart := MID(sSource, 3, 7); // "PLC" (从位置 7 取 3 字符)
sResult := CONCAT(sSource, ' v1.0'); // "Darra PLC 系统 v1.0"
iPos := FIND(sSource, 'PLC'); // 7
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
LEN(STR) | STRING | INT | 返回字符串实际长度(不含结尾空字符) |
LEFT(STR, SIZE) | STRING, INT | STRING | 取左侧 SIZE 个字符 |
RIGHT(STR, SIZE) | STRING, INT | STRING | 取右侧 SIZE 个字符 |
MID(STR, SIZE, POS) | STRING, INT, INT | STRING | 从 POS 取 SIZE 个字符 |
CONCAT(STR1, STR2) | STRING, STRING | STRING | 拼接两个字符串 |
FIND(STR1, STR2) | STRING, STRING | INT | 返回 STR2 在 STR1 中的起始位置,未找到返回 0 |
字符串修改
VAR
sText : STRING[64] := 'Darra PLC 系统';
sResult : STRING[64];
END_VAR
sResult := INSERT(sText, '软件', 7); // "Darra 软件PLC 系统"
sResult := DELETE(sText, 6, 5); // "Darra 系统" (从位置 6 删 5 字符)
sResult := REPLACE(sText, 'Darra', '控制'); // "控制 PLC 系统"
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
INSERT(STR1, STR2, POS) | STRING, STRING, INT | STRING | 在 POS 位置插入 STR2 |
DELETE(STR, POS, LEN) | STRING, INT, INT | STRING | 从 POS 开始删除 LEN 字符 |
REPLACE(STR1, STR2, LEN, POS) | STRING, STRING, INT, INT | STRING | 从 POS 开始用 STR2 替换 LEN 字符 |
Darra 扩展字符串函数
VAR
sInput : STRING[64] := '温度,压力,流速';
sToken : STRING[32];
sReplace : STRING[64];
sTrim : STRING[64] := ' 带空格的字符串 ';
sUpper : STRING[64];
sLower : STRING[64];
sPad : STRING[64];
iCount : INT;
END_VAR
// 替换所有匹配项
sReplace := REPLACE_STR(sInput, ',', ' | '); // "温度 | 压力 | 流速"
// 去除首尾空白
sTrim := TRIM(sTrim); // "带空格的字符串"
// 大小写转换
sUpper := TO_UPPER(sInput); // "温度,压力,流速"
sLower := TO_LOWER(sInput); // "温度,压力,流速"
// 填充
sPad := LPAD('7', 4, '0'); // "0007"
sPad := RPAD('7', 4, '0'); // "7000"
// 统计子串出现次数
iCount := COUNT_STR(sInput, ','); // 2
| Darra 扩展函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
REPLACE_STR(STR, OLD, NEW) | STRING, STRING, STRING | STRING | 替换所有匹配子串 |
TRIM(STR) | STRING | STRING | 去除首尾空白字符 |
TO_UPPER(STR) | STRING | STRING | 转换为大写(ASCII 部分) |
TO_LOWER(STR) | STRING | STRING | 转换为小写(ASCII 部分) |
LPAD(STR, LEN, CH) | STRING, INT, STRING | STRING | 左侧填充至指定长度 |
RPAD(STR, LEN, CH) | STRING, INT, STRING | STRING | 右侧填充至指定长度 |
COUNT_STR(STR, SUB) | STRING, STRING | INT | 统计子串出现次数 |
字符串容量
STRING[N]未指定 N 时默认 80 字符- 超出容量的赋值会被截断,不抛异常
- 中文字符串建议用
WSTRING(UTF-16)避免编码问题 - 高频周期中避免大量字符串拼接,拷贝开销显著
5. 日期时间函数
当前时间获取
VAR
dtNow : DT;
dToday : DATE;
todNow : TOD;
tElapsed : TIME;
sDate : STRING[12];
sTime : STRING[16];
sDt : STRING[24];
diMillis : DINT;
END_VAR
dtNow := GET_DATE_TIME(); // 当前日期时间 DT#2026-04-07-14:30:00
dToday := GET_DATE(); // 当前日期 D#2026-04-07
todNow := GET_TIME_OF_DAY(); // 当前时刻 TOD#14:30:00.123
tElapsed := GET_RUN_TIME(); // 系统运行时长
| 函数 | 返回 | 说明 |
|---|---|---|
GET_DATE_TIME() | DT | 当前系统日期时间(64 位) |
GET_DATE() | DATE | 当前系统日期 |
GET_TIME_OF_DAY() | TOD | 当前时刻(当日偏移) |
GET_RUN_TIME() | TIME | 系统运行时长(毫秒精度) |
日期时间转换
VAR
dDate : DATE := D#2026-04-07;
sDate : STRING[12];
dParsed : DATE;
tOffset : TIME;
todTime : TOD;
wYear : WORD;
bMonth : BYTE;
bDay : BYTE;
wHour : WORD;
bMinute : BYTE;
bSecond : BYTE;
END_VAR
sDate := DATE_TO_STRING(dDate); // "2026-04-07"
dParsed := STRING_TO_DATE('2026-04-07'); // D#2026-04-07
tOffset := TOD_TO_TIME(TOD#14:30:00); // T#14h30m0s
todTime := TIME_TO_TOD(T#14h30m); // TOD#14:30:00
// 日期时间分解(Darra 扩展)
DECODE_DATE(dDate, wYear, bMonth, bDay); // 2026, 4, 7
DECODE_TIME(TOD#14:30:00.500, wHour, bMinute, bSecond, wMillisec); // 14, 30, 0, 500
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
DATE_TO_STRING(DATE) | DATE | STRING | 格式化为 YYYY-MM-DD |
STRING_TO_DATE(STR) | STRING | DATE | 解析 YYYY-MM-DD 格式 |
TOD_TO_TIME(TOD) | TOD | TIME | 时刻转换为当日偏移时长 |
TIME_TO_TOD(TIME) | TIME | TOD | 时长转换为当日时刻 |
DECODE_DATE(DATE) | DATE | — | 将日期分解为年、月、日(Darra 扩展) |
DECODE_TIME(TOD) | TOD | — | 将时刻分解为时、分、秒、毫秒(Darra 扩展) |
6. 边缘检测
边缘检测通过标准功能块 R_TRIG(上升沿)和 F_TRIG(下降沿)实现。
R_TRIG — 上升沿检测
FUNCTION_BLOCK R_TRIG
VAR_INPUT
CLK : BOOL; // 时钟输入
END_VAR
VAR_OUTPUT
Q : BOOL; // 上升沿脉冲输出
END_VAR
VAR
M : BOOL; // 内部状态记忆
END_VAR
Q := CLK AND NOT M;
M := CLK;
END_FUNCTION_BLOCK
F_TRIG — 下降沿检测
FUNCTION_BLOCK F_TRIG
VAR_INPUT
CLK : BOOL; // 时钟输入
END_VAR
VAR_OUTPUT
Q : BOOL; // 下降沿脉冲输出
END_VAR
VAR
M : BOOL; // 内部状态记忆
END_VAR
Q := NOT CLK AND M;
M := CLK;
END_FUNCTION_BLOCK
使用示例
VAR
rtStart : R_TRIG;
ftStop : F_TRIG;
bStartBtn : BOOL;
bStopBtn : BOOL;
bStartPulse : BOOL;
bStopPulse : BOOL;
bRun : BOOL;
END_VAR
// 上升沿检测
rtStart(CLK := bStartBtn);
bStartPulse := rtStart.Q;
// 下降沿检测
ftStop(CLK := bStopBtn);
bStopPulse := ftStop.Q;
// 应用:单按钮启停(上升沿切换)
IF bStartPulse THEN
bRun := NOT bRun;
END_IF;
| 功能块 | 输入 | 输出 | 说明 |
|---|---|---|---|
R_TRIG | CLK: BOOL | Q: BOOL | CLK 从 FALSE→TRUE 时 Q 输出一个扫描周期脉冲 |
F_TRIG | CLK: BOOL | Q: BOOL | CLK 从 TRUE→FALSE 时 Q 输出一个扫描周期脉冲 |
7. 定时器函数
标准 IEC 61131-3 定时器功能块,支持 TON、TOF、TP 和 TONR(Darra 扩展)。
TON — 接通延时
VAR
tonDelay : TON;
bTrigger : BOOL;
bElapsed : BOOL;
tElapsed : TIME;
END_VAR
tonDelay(IN := bTrigger, PT := T#5s);
bElapsed := tonDelay.Q;
tElapsed := tonDelay.ET; // 当前计时值
TOF — 关断延时
VAR
tofDelay : TOF;
bTrigger : BOOL;
bElapsed : BOOL;
END_VAR
tofDelay(IN := bTrigger, PT := T#3s);
bElapsed := tofDelay.Q;
TP — 脉冲定时
VAR
tpPulse : TP;
bTrigger : BOOL;
bPulse : BOOL;
END_VAR
tpPulse(IN := bTrigger, PT := T#500ms);
bPulse := tpPulse.Q; // 输出固定宽度 500ms 脉冲
TONR — 累计接通延时(Darra 扩展)
VAR
tonrAccum : TONR;
bTrigger : BOOL;
bReset : BOOL;
bElapsed : BOOL;
tAccum : TIME;
END_VAR
tonrAccum(IN := bTrigger, R := bReset, PT := T#1h);
bElapsed := tonrAccum.Q;
tAccum := tonrAccum.ET; // 累计计时值,R=TRUE 时清零
| 功能块 | 输入 | 输出 | 说明 |
|---|---|---|---|
TON | IN: BOOL, PT: TIME | Q: BOOL, ET: TIME | IN=TRUE 开始计时,计时到 PT 后 Q=TRUE |
TOF | IN: BOOL, PT: TIME | Q: BOOL, ET: TIME | IN=FALSE 开始计时,计时到 PT 后 Q=FALSE |
TP | IN: BOOL, PT: TIME | Q: BOOL, ET: TIME | IN 上升沿输出固定宽度脉冲 |
TONR | IN: BOOL, R: BOOL, PT: TIME | Q: BOOL, ET: TIME | 累计计时,R 复位,Darra 扩展 |
// 实际应用:电机超时保护
VAR
tonMotorGuard : TON;
bMotorOn : BOOL;
bMotorReady : BOOL;
bFault : BOOL;
END_VAR
tonMotorGuard(IN := bMotorOn, PT := T#10s);
// 电机启动后 10 秒内未就绪则报故障
IF tonMotorGuard.Q AND NOT bMotorReady THEN
bFault := TRUE;
END_IF;
8. 计数器函数
CTU — 加计数器
VAR
ctuCount : CTU;
bCountUp : BOOL;
bReset : BOOL;
bDone : BOOL;
iCount : INT;
END_VAR
ctuCount(CU := bCountUp, R := bReset, PV := 100);
bDone := ctuCount.Q; // 计数值 ≥ PV 时 Q=TRUE
iCount := ctuCount.CV; // 当前计数值
CTD — 减计数器
VAR
ctdCount : CTD;
bCountDown : BOOL;
bLoad : BOOL;
bDone : BOOL;
iCount : INT;
END_VAR
ctdCount(CD := bCountDown, LD := bLoad, PV := 50);
bDone := ctdCount.Q; // 计数值 ≤ 0 时 Q=TRUE
iCount := ctdCount.CV;
CTUD — 加减计数器(IEC 标准)
VAR
ctudCount : CTUD;
bCountUp : BOOL;
bCountDown : BOOL;
bReset : BOOL;
bLoad : BOOL;
bQu : BOOL;
bQd : BOOL;
iCount : INT;
END_VAR
ctudCount(CU := bCountUp, CD := bCountDown,
R := bReset, LD := bLoad, PV := 100);
bQu := ctudCount.QU; // 加计数到 PV 以上
bQd := ctudCount.QD; // 减计数到 0 以下
iCount := ctudCount.CV;
| 功能块 | 输入 | 输出 | 说明 |
|---|---|---|---|
CTU | CU: BOOL, R: BOOL, PV: INT | Q: BOOL, CV: INT | 加计数器,CV ≥ PV 时 Q=TRUE |
CTD | CD: BOOL, LD: BOOL, PV: INT | Q: BOOL, CV: INT | 减计数器,CV ≤ 0 时 Q=TRUE |
CTUD | CU, CD, R, LD: BOOL, PV: INT | QU, QD: BOOL, CV: INT | 加减双向计数器 |
// 实际应用:产品计数
VAR
ctuProduct : CTU;
bSensor : BOOL; // 传感器信号(上升沿)
bResetCount : BOOL;
iTotal : INT;
bBatchFull : BOOL;
END_VAR
ctuProduct(CU := bSensor, R := bResetCount, PV := 500);
iTotal := ctuProduct.CV;
bBatchFull := ctuProduct.Q; // 满 500 件
9. 系统信息函数
获取系统信息
VAR
sSysInfo : STRING[128];
tCycle : TIME;
iTask : INT;
wIoState : WORD;
sPlcName : STRING[64];
sVersion : STRING[32];
diUptime : DINT;
rCpuLoad : REAL;
wMemFree : WORD;
END_VAR
sSysInfo := GET_SYS_INFO(SYS_INFO_PLC_NAME); // 返回 PLC 名称
tCycle := GET_CYCLE_TIME(); // 当前扫描周期(ms)
iTask := GET_TASK_INDEX(); // 当前 OB 索引号
wIoState := GET_IO_STATE(); // IO 模块状态位图
// Darra 扩展系统信息函数
sPlcName := GET_SYS_INFO(SYS_INFO_PLC_NAME); // 设备名称
sVersion := GET_SYS_INFO(SYS_INFO_VERSION); // 固件版本
diUptime := GET_SYS_INFO(SYS_INFO_UPTIME); // 运行秒数
rCpuLoad := GET_SYS_INFO(SYS_INFO_CPU_LOAD); // CPU 负载 0.0-100.0
| 函数 | 返回 | 说明 |
|---|---|---|
GET_SYS_INFO(SELECTOR) | 取决于选择器 | 获取系统信息,选择器见下表 |
GET_CYCLE_TIME() | TIME | 返回当前扫描周期时间 |
GET_TASK_INDEX() | INT | 返回当前执行的组织块索引号 |
GET_IO_STATE() | WORD | 返回 IO 模块状态位图 |
系统信息选择器常量
| 常量名 | 返回类型 | 说明 |
|---|---|---|
SYS_INFO_PLC_NAME | STRING | 设备名称 |
SYS_INFO_VERSION | STRING | 固件版本号 |
SYS_INFO_UPTIME | DINT | 运行秒数 |
SYS_INFO_CPU_LOAD | REAL | CPU 负载百分比 |
SYS_INFO_MEM_FREE | WORD | 剩余内存百分比 |
SYS_INFO_CYCLE_MIN | TIME | 最小扫描周期 |
SYS_INFO_CYCLE_MAX | TIME | 最大扫描周期 |
SYS_INFO_TASK_COUNT | INT | 当前活跃任务数 |
扫描周期监控
VAR
tCycle : TIME;
tCycleMin : TIME := T#1000ms;
tCycleMax : TIME := T#0ms;
tWatchdog : TIME;
bCycleFault : BOOL;
END_VAR
tCycle := GET_CYCLE_TIME();
// 记录扫描周期极值
IF tCycle < tCycleMin THEN tCycleMin := tCycle; END_IF;
IF tCycle > tCycleMax THEN tCycleMax := tCycle; END_IF;
// 扫描周期超限检测
IF tCycle > T#100ms THEN
bCycleFault := TRUE;
DIAG_LOG('扫描周期超限', tCycle);
END_IF;
10. 通讯函数
Darra 扩展通讯函数,用于与外部设备和服务进行数据交换。
OPC UA 通讯
VAR
bResult : BOOL;
rValue : REAL;
sError : STRING[64];
END_VAR
// 写入 OPC UA 变量
bResult := OPC_UA_WRITE(
NodeId := 'ns=2;s=电机1.转速',
Value := 1500.0,
Error := sError
);
// 读取 OPC UA 变量
bResult := OPC_UA_READ(
NodeId := 'ns=2;s=电机1.转速',
Value := rValue,
Error := sError
);
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
OPC_UA_WRITE(NODE_ID, VALUE, ERROR) | STRING, ANY, REF_TO STRING | BOOL | 写入 OPC UA 变量节点 |
OPC_UA_READ(NODE_ID, VALUE, ERROR) | STRING, REF_TO ANY, REF_TO STRING | BOOL | 读取 OPC UA 变量节点 |
Modbus 通讯
VAR
bResult : BOOL;
aiRegs : ARRAY[0..9] OF INT;
sError : STRING[64];
END_VAR
// Modbus 读保持寄存器
bResult := MODBUS_READ(
Port := 'COM1',
SlaveId := 1,
FuncCode := 3,
Addr := 100,
Count := 10,
Data := aiRegs,
Error := sError
);
// Modbus 写单个线圈
bResult := MODBUS_WRITE(
Port := 'COM1',
SlaveId := 1,
FuncCode := 5,
Addr := 0,
Value := TRUE,
Error := sError
);
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
MODBUS_READ(PORT, SLAVE_ID, FUNC, ADDR, COUNT, DATA, ERROR) | 见上 | BOOL | 读取 Modbus 从站数据 |
MODBUS_WRITE(PORT, SLAVE_ID, FUNC, ADDR, VALUE, ERROR) | 见上 | BOOL | 写入 Modbus 从站数据 |
HTTP 请求
VAR
bResult : BOOL;
sResponse : STRING[1024];
sError : STRING[64];
END_VAR
// 发送 HTTP POST 请求
bResult := HTTP_POST(
Url := 'http://192.168.1.100:5000/api/data',
Headers := 'Content-Type: application/json',
Body := '{"temperature": 25.5, "pressure": 101.3}',
Response := sResponse,
Timeout := T#5s,
Error := sError
);
// 简化版 GET 请求
bResult := HTTP_GET(
Url := 'http://192.168.1.100:5000/api/status',
Response := sResponse,
Timeout := T#3s,
Error := sError
);
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
HTTP_POST(URL, HEADERS, BODY, RES, TIMEOUT, ERR) | 见上 | BOOL | 发送 HTTP POST 请求 |
HTTP_GET(URL, RES, TIMEOUT, ERR) | 见上 | BOOL | 发送 HTTP GET 请求 |
HTTP_PUT(URL, HEADERS, BODY, RES, TIMEOUT, ERR) | 见上 | BOOL | 发送 HTTP PUT 请求(Darra 扩展) |
DarraLink 内部通讯
VAR
bResult : BOOL;
sResponse : STRING[1024];
sError : STRING[64];
END_VAR
// 向同一 Darra 网络内的另一个 PLC 发送数据
bResult := DARRA_SEND(
TargetId := '192.168.1.200',
Port := 18821,
Data := '{"command": "start", "value": 1}',
Response := sResponse,
Timeout := T#2s,
Error := sError
);
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
DARRA_SEND(TARGET, PORT, DATA, RESP, TIMEOUT, ERR) | 见上 | BOOL | 通过 DarraLink 协议发送数据到另一 PLC |
11. 诊断函数
诊断日志
VAR
bResult : BOOL;
diEventId : DINT;
tTimestamp : TIME;
END_VAR
// 写入诊断日志
bResult := DIAG_LOG(
Category := '温度监控',
Message := '电机 1 温度超限',
Severity := DIAG_WARNING
);
// 带上下文信息
bResult := DIAG_LOG(
Category := '通讯',
Message := 'Modbus 从站 1 超时',
Severity := DIAG_ERROR,
Context := 'COM1, 19200bps'
);
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
DIAG_LOG(CATEGORY, MESSAGE, SEVERITY, ...) | STRING, STRING, INT, ... | BOOL | 写入诊断日志条目 |
诊断严重度级别
| 常量 | 值 | 说明 |
|---|---|---|
DIAG_INFO | 0 | 信息性消息 |
DIAG_WARNING | 1 | 警告,不影响运行 |
DIAG_ERROR | 2 | 错误,功能受限 |
DIAG_CRITICAL | 3 | 严重错误,需立即处理 |
报警管理
VAR
bResult : BOOL;
diAlarmId : DINT;
sAlarmText : STRING[128];
END_VAR
// 触发报警
bResult := DIAG_ALARM(
AlarmId := 1001,
Message := '急停按钮被按下',
Severity := DIAG_CRITICAL,
AutoAck := FALSE
);
// 确认报警
bResult := DIAG_ALARM_ACK(AlarmId := 1001);
// 清除报警
bResult := DIAG_ALARM_CLR(AlarmId := 1001);
// 查询报警状态
bResult := DIAG_ALARM_QUERY(
AlarmId := 1001,
Active := bActive,
Timestamp := tTimestamp,
Text := sAlarmText
);
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
DIAG_ALARM(ID, MSG, SEV, AUTOACK) | 见上 | BOOL | 触发报警 |
DIAG_ALARM_ACK(ID) | DINT | BOOL | 确认报警 |
DIAG_ALARM_CLR(ID) | DINT | BOOL | 清除报警 |
DIAG_ALARM_QUERY(ID, ACTIVE, TS, TEXT) | 见上 | BOOL | 查询报警当前状态 |
跟踪与性能分析
VAR
bResult : BOOL;
rTraceData : ARRAY[0..1023] OF REAL;
iCount : INT;
END_VAR
// 开始性能跟踪
bResult := DIAG_TRACE(
Name := 'PID_循环',
Enable := TRUE,
Interval := T#10ms,
MaxSamples := 1024
);
// 写入跟踪点
bResult := DIAG_TRACE_POINT(
Name := 'PID_循环',
Value := rProcessValue
);
// 停止并读取跟踪数据
bResult := DIAG_TRACE_READ(
Name := 'PID_循环',
Data := rTraceData,
Count := iCount
);
| 函数 | 参数 | 返回 | 说明 |
|---|---|---|---|
DIAG_TRACE(NAME, ENABLE, INTERVAL, MAX) | 见上 | BOOL | 配置诊断跟踪 |
DIAG_TRACE_POINT(NAME, VALUE) | STRING, REAL | BOOL | 写入跟踪采样点 |
DIAG_TRACE_READ(NAME, DATA, COUNT) | STRING, ARRAY, REF_TO INT | BOOL | 读取已采集的跟踪数据 |
系统诊断综合示例
PROGRAM Diagnostics
VAR
tCycle : TIME;
rCpuLoad : REAL;
bCommOk : BOOL;
bAlarmActive : BOOL;
diAlarmId : DINT;
sMsg : STRING[128];
END_VAR
// 扫描周期监控
tCycle := GET_CYCLE_TIME();
IF tCycle > T#100ms THEN
DIAG_LOG('性能', '扫描周期超限', DIAG_WARNING, TIME_TO_DINT(tCycle));
END_IF;
// CPU 负载监控
rCpuLoad := GET_SYS_INFO(SYS_INFO_CPU_LOAD);
IF rCpuLoad > 85.0 THEN
DIAG_LOG('性能', 'CPU 负载过高', DIAG_WARNING, rCpuLoad);
END_IF;
// 通讯状态监控
bCommOk := MODBUS_READ('COM1', 1, 3, 0, 1, aiTemp, sError);
IF NOT bCommOk THEN
DIAG_ALARM(2001, 'Modbus 通讯中断', DIAG_ERROR, FALSE);
END_IF;
END_PROGRAM
12. 函数调用速查表
| 类别 | 函数 / FB | 说明 |
|---|---|---|
| 类型转换 | BOOL_TO_BYTE, INT_TO_DINT, DINT_TO_REAL, REAL_TO_STRING, STRING_TO_REAL, WORD_TO_DINT | 数据类型间转换 |
| 数学 | ABS, SQRT, LN, LOG, EXP, EXPT, SIN, COS, TAN, ASIN, ACOS, ATAN | 标准数学运算 |
| 舍入 | TRUNC, ROUND, CEIL, FLOOR | 数值舍入与截断 |
| 选择 | SEL, MAX, MIN, LIMIT, MUX | 条件选择与限幅 |
| 位操作 | SHL, SHR, ROL, ROR | 移位与循环移位 |
| 字符串 | LEN, LEFT, RIGHT, MID, CONCAT, FIND, INSERT, DELETE, REPLACE | 标准字符串操作 |
| 字符串扩展 | REPLACE_STR, TRIM, TO_UPPER, TO_LOWER, LPAD, RPAD, COUNT_STR | Darra 扩展字符串操作 |
| 日期时间 | GET_DATE_TIME, GET_DATE, GET_TIME_OF_DAY, GET_RUN_TIME, DATE_TO_STRING, STRING_TO_DATE, TOD_TO_TIME, TIME_TO_TOD | 时间获取与转换 |
| 边缘检测 | R_TRIG, F_TRIG | 上升沿 / 下降沿检测 |
| 定时器 | TON, TOF, TP, TONR | 接通延时、关断延时、脉冲、累计 |
| 计数器 | CTU, CTD, CTUD | 加、减、加减双向计数 |
| 系统信息 | GET_SYS_INFO, GET_CYCLE_TIME, GET_TASK_INDEX, GET_IO_STATE | 系统状态查询 |
| 通讯 | OPC_UA_WRITE, OPC_UA_READ, MODBUS_READ, MODBUS_WRITE, HTTP_POST, HTTP_GET, DARRA_SEND | 外部通讯接口 |
| 诊断 | DIAG_LOG, DIAG_ALARM, DIAG_ALARM_ACK, DIAG_ALARM_CLR, DIAG_TRACE | 日志、报警、跟踪 |