第一个 PLC 程序
本节以工业最经典的"电机启停"为例, 带您走通从变量定义到在线监视的完整链路。 我们会分别用 结构化控制语言 (SCL) 和 梯形图 (LD) 写两遍同一个逻辑, 这样您能直观感受 IEC 61131-3 各语言之间的等价关系。
目标
- 掌握
VAR / VAR_INPUT / VAR_OUTPUT变量块 - 会用 SCL 和 LD 实现同一逻辑
- 会按 F7 编译, 看懂编译报告
- 会按 F5 启动仿真, 用变量监视看运行结果
前置条件
- 已完成 创建第一个项目, 有一台
PLC_1设备 - 解决方案处于"仿真"运行模式
业务描述
经典的点动 + 自锁电机启停:
- 按下 Start 按钮 → 电机运转 (Motor = TRUE)
- 按下 Stop 按钮 → 电机停转 (Motor = FALSE)
- Stop 优先级高于 Start (按住 Stop 时 Start 无效)
- Start 松开后电机仍保持运转 (自锁)
- 电机运转时累积运行秒数 (
RunSec)
步骤 1 - 创建全局变量
- 在解决方案资源管理器中双击 设备 → PLC_1 → 变量 → GlobalVars
- 变量表打开后, 点击空白行开始添加变量
- 参考下表填写:
| 名称 | 类型 | 初值 | 地址 | 说明 |
|---|---|---|---|---|
Start | BOOL | FALSE | %IX0.0 | 启动按钮 DI |
Stop | BOOL | FALSE | %IX0.1 | 停止按钮 DI (常闭型硬件可取反) |
Motor | BOOL | FALSE | %QX0.0 | 电机接触器 DO |
Running | BOOL | FALSE | — | 运行中标志 (HMI 指示灯用) |
RunSec | DINT | 0 | — | 累积运行秒数 |
tSec | TON | — | — | 1 秒节拍定时器 |
- 按 Ctrl+S 保存

地址说明
%IX— 数字输入位 (DI)%QX— 数字输出位 (DO)%IW/%QW— 字 (16 bit) 输入 / 输出%MB/%MW/%MD— 内部存储器 (M 区)0.0表示字节 0 的位 0
TODO
步骤 2a - 用 SCL 写一遍
- 右键 程序 → 新建程序
- 名称填
MotorCtrl_ST, 语言选 SCL (结构化控制语言), 确定 - 在编辑器里输入完整代码:
PROGRAM MotorCtrl_ST
VAR_EXTERNAL
Start : BOOL;
Stop : BOOL;
Motor : BOOL;
Running : BOOL;
RunSec : DINT;
tSec : TON;
END_VAR
VAR
bLastStart : BOOL := FALSE; (* 上升沿检测 *)
END_VAR
(* 启停逻辑: Stop 优先, Start 有自锁 *)
IF Stop THEN
Motor := FALSE;
ELSIF Start AND NOT bLastStart THEN
(* 上升沿启动, 防连按 *)
Motor := TRUE;
END_IF;
bLastStart := Start;
(* 输出状态 *)
Running := Motor;
(* 累积运行秒数: 1 秒节拍定时器 *)
tSec(IN := Motor, PT := T#1s);
IF tSec.Q THEN
RunSec := RunSec + 1;
tSec(IN := FALSE, PT := T#1s); (* 清零, 下一个周期重新计时 *)
END_IF;
END_PROGRAM
SCL 要点
VAR_EXTERNAL声明对全局变量的引用, 不重复分配内存(* ... *)是 IEC 标准注释, 也支持 C 风格// ...T#1s是时间字面量, 单位 ms/s/m/h- 每条语句必须以
;结尾
步骤 2b - 用 LD 写一遍
LD (梯形图) 是电气工程师最熟悉的语言。让我们用它实现同一个逻辑:
- 右键 程序 → 新建程序
- 名称
MotorCtrl_LD, 语言选 LD (梯形图) - 在图形编辑器里画出三条梯级:
梯级 1: 自锁启停
| Start Stop Motor |
|--| |----|/|----+-----------------( )----|
| | |
| Motor | |
|--| |-----------+ |
操作:
- 从左母线拖入一个 常开触点, 绑定
Start - 串联一个 常闭触点, 绑定
Stop - 后面接 线圈 (Output Coil), 绑定
Motor - 在
Start处画一条并联支路, 加 常开触点 绑定Motor(实现自锁)
梯级 2: 运行指示
| Motor Running |
|--| |----------------------------( )----|
梯级 3: 秒计时
需要一个 TON 功能块和加计数:
| +-------+ |
| Motor | TON | |
|--| |----------IN ---+| tSec | |
| T#1s -+| PT |Q+---+ |
| +-------+ | |
| | |
| +----+ | |
| | ADD| | |
| RunSec+--IN1| | |
| 1 +--IN2|OUT---RunSec |
| +----+ | |
具体通过 插入功能块 → TON 实现。

LD 小贴士
- 常开触点 = 当变量 TRUE 时接通 (类似按钮接触)
- 常闭触点 = 当变量 FALSE 时接通 (带
/) - 线圈 = 把左侧逻辑结果写入变量
↑上升沿 /↓下降沿触点用于沿检测
TODO
步骤 3 - 在主程序调用
- 打开 程序 → Main
- 写入:
PROGRAM Main
VAR
END_VAR
(* 选一种实现运行, 另一种注释掉 *)
MotorCtrl_ST();
(* MotorCtrl_LD(); *)
END_PROGRAM
步骤 4 - 编译
- 按 F7 或菜单 项目 → 编译
- 在 输出 窗口查看结果:
[编译] 开始编译 DemoLine01 ...
[编译] GlobalVars → 40 字节
[编译] MotorCtrl_ST → 62 条指令
[编译] Main → 4 条指令
[编译] 总计 66 条指令, 0 错误, 0 警告
[编译] 耗时 120 ms

编译错误速查
E1001 变量未声明→ GlobalVars 里缺变量, 或忘了 VAR_EXTERNALE1015 类型不匹配→ 如 INT 赋给 BOOLE2003 地址冲突→ 多个变量绑同一%QX位E3002 循环引用→ FB 互相递归调用- 双击错误行可跳转到代码
步骤 5 - 启动仿真
- 按 F5 或工具栏 仿真运行
- 状态栏变绿, 显示
扫描周期 4.000 ms / 平均 3.987 ms / 最大 4.210 ms - 打开 视图 → 变量监视, 把
Start / Stop / Motor / RunSec拖进监视列表
步骤 6 - 在线监视与强制写入
PLC 没有断点/单步调试的概念, 调试靠在线监视 + 强制写入:
- 在监视列表中右键
Start→ 强制为 TRUE → 观察 Motor 变 TRUE - 右键
Start→ 解除强制 → Motor 保持 TRUE (自锁生效) - 右键
Stop→ 强制为 TRUE → Motor 立即 FALSE - 观察
RunSec每秒递增 1
TODO
趋势曲线
变量监视里右键变量 → 加入趋势, 打开 视图 → 趋势, 可以看到 Motor 波形和 RunSec 折线, 类似示波器效果, 比单点数值更直观。
完整 SCL 代码 (复制即用)
(* ==========================================
MotorCtrl_ST - 电机启停 (SCL 版)
输入: Start (%IX0.0), Stop (%IX0.1)
输出: Motor (%QX0.0)
辅助: Running / RunSec
========================================== *)
PROGRAM MotorCtrl_ST
VAR_EXTERNAL
Start : BOOL;
Stop : BOOL;
Motor : BOOL;
Running : BOOL;
RunSec : DINT;
tSec : TON;
END_VAR
VAR
bLastStart : BOOL := FALSE;
END_VAR
IF Stop THEN
Motor := FALSE;
ELSIF Start AND NOT bLastStart THEN
Motor := TRUE;
END_IF;
bLastStart := Start;
Running := Motor;
tSec(IN := Motor, PT := T#1s);
IF tSec.Q THEN
RunSec := RunSec + 1;
tSec(IN := FALSE, PT := T#1s);
END_IF;
END_PROGRAM
常见问题
Start 按下后 Motor 立即又变 FALSE
原因: Stop 常闭线未接通 (硬件), 或 %IX0.1 取反方向反了。
解决: 变量表中把 Stop 类型改为 BOOL ! 或在 IO 映射里加"取反"标志。
RunSec 不递增
原因: tSec 的 IN 始终为 FALSE, 或编译未启用计时器扫描。
排查: 监视 tSec.IN / tSec.ET / tSec.Q, 看 Q 每秒是否跳一次。
编译报 "E1001 未声明的变量 Start"
原因: 没写 VAR_EXTERNAL Start : BOOL; END_VAR, 或 GlobalVars 里还没添加 Start。
解决: 回步骤 1 检查全局变量表, 并在程序里写 VAR_EXTERNAL 引用。
F5 启动报 "Service 未连接"
原因: Darra PLC Service 后台进程没起来。
解决: 任务管理器 → 服务 → 找到 Darra PLC Service → 启动; 或重启 IDE 触发自动拉起。
下一步
- 第一个机器人程序 — 在 PLC 里加一台 6 轴臂
- 第一个 HMI 工程 — 给电机做一个启停面板
- 部署到运行时 — 把程序下到真工控机
- PLC 变量与数据类型 (深入)
- 在线监视与强制 (深入)