跳到主要内容

第一个 PLC 程序

本节以工业最经典的"电机启停"为例, 带您走通从变量定义到在线监视的完整链路。 我们会分别用 结构化控制语言 (SCL)梯形图 (LD) 写两遍同一个逻辑, 这样您能直观感受 IEC 61131-3 各语言之间的等价关系。

目标

  • 掌握 VAR / VAR_INPUT / VAR_OUTPUT 变量块
  • 会用 SCL 和 LD 实现同一逻辑
  • 会按 F7 编译, 看懂编译报告
  • 会按 F5 启动仿真, 用变量监视看运行结果

前置条件

业务描述

经典的点动 + 自锁电机启停:

  • 按下 Start 按钮 → 电机运转 (Motor = TRUE)
  • 按下 Stop 按钮 → 电机停转 (Motor = FALSE)
  • Stop 优先级高于 Start (按住 Stop 时 Start 无效)
  • Start 松开后电机仍保持运转 (自锁)
  • 电机运转时累积运行秒数 (RunSec)

步骤 1 - 创建全局变量

  1. 在解决方案资源管理器中双击 设备 → PLC_1 → 变量 → GlobalVars
  2. 变量表打开后, 点击空白行开始添加变量
  3. 参考下表填写:
名称类型初值地址说明
StartBOOLFALSE%IX0.0启动按钮 DI
StopBOOLFALSE%IX0.1停止按钮 DI (常闭型硬件可取反)
MotorBOOLFALSE%QX0.0电机接触器 DO
RunningBOOLFALSE运行中标志 (HMI 指示灯用)
RunSecDINT0累积运行秒数
tSecTON1 秒节拍定时器
  1. Ctrl+S 保存

截图: 第一个程序 — 步骤1 变量定义

地址说明
  • %IX — 数字输入位 (DI)
  • %QX — 数字输出位 (DO)
  • %IW/%QW — 字 (16 bit) 输入 / 输出
  • %MB/%MW/%MD — 内部存储器 (M 区)
  • 0.0 表示字节 0 的位 0

step-1: 全局变量表 TODO

步骤 2a - 用 SCL 写一遍

  1. 右键 程序新建程序
  2. 名称填 MotorCtrl_ST, 语言选 SCL (结构化控制语言), 确定
  3. 在编辑器里输入完整代码:
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 (梯形图) 是电气工程师最熟悉的语言。让我们用它实现同一个逻辑:

  1. 右键 程序新建程序
  2. 名称 MotorCtrl_LD, 语言选 LD (梯形图)
  3. 在图形编辑器里画出三条梯级:

梯级 1: 自锁启停

| Start   Stop                       Motor |
|--| |----|/|----+-----------------( )----|
| | |
| Motor | |
|--| |-----------+ |

操作:

  1. 从左母线拖入一个 常开触点, 绑定 Start
  2. 串联一个 常闭触点, 绑定 Stop
  3. 后面接 线圈 (Output Coil), 绑定 Motor
  4. Start 处画一条并联支路, 加 常开触点 绑定 Motor (实现自锁)

梯级 2: 运行指示

| Motor                              Running |
|--| |----------------------------( )----|

梯级 3: 秒计时

需要一个 TON 功能块和加计数:

|                      +-------+             |
| Motor | TON | |
|--| |----------IN ---+| tSec | |
| T#1s -+| PT |Q+---+ |
| +-------+ | |
| | |
| +----+ | |
| | ADD| | |
| RunSec+--IN1| | |
| 1 +--IN2|OUT---RunSec |
| +----+ | |

具体通过 插入功能块 → TON 实现。

截图: 第一个程序 — 步骤2 梯形图

LD 小贴士
  • 常开触点 = 当变量 TRUE 时接通 (类似按钮接触)
  • 常闭触点 = 当变量 FALSE 时接通 (带 /)
  • 线圈 = 把左侧逻辑结果写入变量
  • 上升沿 / 下降沿触点用于沿检测

step-2b: 梯形图编辑器 TODO

步骤 3 - 在主程序调用

  1. 打开 程序 → Main
  2. 写入:
PROGRAM Main
VAR
END_VAR

(* 选一种实现运行, 另一种注释掉 *)
MotorCtrl_ST();
(* MotorCtrl_LD(); *)

END_PROGRAM

步骤 4 - 编译

  1. F7 或菜单 项目 → 编译
  2. 输出 窗口查看结果:
[编译] 开始编译 DemoLine01 ...
[编译] GlobalVars → 40 字节
[编译] MotorCtrl_ST → 62 条指令
[编译] Main → 4 条指令
[编译] 总计 66 条指令, 0 错误, 0 警告
[编译] 耗时 120 ms

截图: 编译成功结果

编译错误速查
  • E1001 变量未声明 → GlobalVars 里缺变量, 或忘了 VAR_EXTERNAL
  • E1015 类型不匹配 → 如 INT 赋给 BOOL
  • E2003 地址冲突 → 多个变量绑同一 %QX
  • E3002 循环引用 → FB 互相递归调用
  • 双击错误行可跳转到代码

步骤 5 - 启动仿真

  1. F5 或工具栏 仿真运行
  2. 状态栏变绿, 显示 扫描周期 4.000 ms / 平均 3.987 ms / 最大 4.210 ms
  3. 打开 视图 → 变量监视, 把 Start / Stop / Motor / RunSec 拖进监视列表

步骤 6 - 在线监视与强制写入

PLC 没有断点/单步调试的概念, 调试靠在线监视 + 强制写入:

  1. 在监视列表中右键 Start强制为 TRUE → 观察 Motor 变 TRUE
  2. 右键 Start解除强制 → Motor 保持 TRUE (自锁生效)
  3. 右键 Stop强制为 TRUE → Motor 立即 FALSE
  4. 观察 RunSec 每秒递增 1

step-6: 变量监视 + 强制 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 触发自动拉起。

下一步