内存区域
Darra PLC 采用 IEC 61131-3 标准内存模型,将 PLC 数据组织为四个独立的内存区域。每个区域有明确的用途和访问规则。
内存区域总览
| 区域 | 标识 | 用途 | 数据方向 | 大小 |
|---|---|---|---|---|
| I 区 | %I | 物理输入 | 从站 → PLC | 由 IO 配置决定 |
| Q 区 | %Q | 物理输出 | PLC → 从站 | 由 IO 配置决定 |
| M 区 | %M | 标记/HMI 交互 | PLC ↔ HMI/SCADA | 可配置 (默认 64KB) |
| V 区 | 内部 | 内部变量 | PLC 内部 | 自动分配 |
地址语法
格式
%<区域><大小><地址>.<位号>
| 大小标识 | 含义 | 字节数 | 示例 |
|---|---|---|---|
X | 位 | 1 位 | %IX0.0 — I 区第 0 字节第 0 位 |
B | 字节 | 1 | %IB0 — I 区第 0 字节 |
W | 字 | 2 | %IW100 — I 区第 100~101 字节 |
D | 双字 | 4 | %MD200 — M 区第 200~203 字节 |
L | 长字 | 8 | %QL0 — Q 区第 0~7 字节 |
常用地址示例
// I 区 — 物理输入
bStartButton AT %IX0.0 : BOOL; // 启动按钮 (数字量输入)
bStopButton AT %IX0.1 : BOOL; // 停止按钮
wEncoder AT %IW10 : WORD; // 编码器值 (模拟量输入)
diPosition AT %ID20 : DINT; // 位置反馈 (32位)
// Q 区 — 物理输出
bMotorOn AT %QX0.0 : BOOL; // 电机使能 (数字量输出)
bValveOpen AT %QX0.1 : BOOL; // 阀门控制
wAnalogOut AT %QW10 : WORD; // 模拟量输出 (0-10V / 4-20mA)
// M 区 — 标记 / HMI
bHmiStart AT %MX0.0 : BOOL; // HMI 启动按钮
iRecipeNo AT %MW100 : INT; // HMI 配方选择
rSetTemp AT %MD200 : REAL; // HMI 设定温度
sMessage AT %MB300 : STRING[64]; // HMI 消息文本
不同大小标识访问同一内存位置时会产生重叠。例如 %MW0 与 %MB0/%MB1 占用相同的两个字节。编译器的 IOConflictChecker 会检测并报告地址冲突。
I 区 — 物理输入
I 区存储从物理设备读取的输入数据:
- 数字量输入 (DI): 传感器、按钮、限位开关等开关信号
- 模拟量输入 (AI): 温度传感器、压力变送器、编码器等连续信号
- 数据来源: EtherCAT、Modbus、CAN、HSL 等总线从站
在每个扫描周期开始时,IO 系统自动把所有 DI/AI 数据汇入 I 区,程序看到的是周期起点的一致快照。
I 区在用户程序中为只读。写入 I 区地址会被编译器标记为错误。如需模拟输入用于调试,使用变量强制功能。
Q 区 — 物理输出
Q 区存储 PLC 写出到物理设备的输出数据:
- 数字量输出 (DO): 电机使能、电磁阀、指示灯
- 模拟量输出 (AO): 变频器速度设定、比例阀开度
在每个扫描周期末尾,程序写入 Q 区的值被 IO 系统统一下发到所有设备。
M 区 — 标记区
M 区是 PLC 内部的通用读写存储区,主要用途:
| 用途 | 说明 |
|---|---|
| HMI 交互 | SCADA/HMI 通过 OPC-UA/Modbus 读写 M 区变量 |
| 中间变量 | 跨功能块的数据传递 |
| 状态标志 | 系统状态、错误标志 |
| 通讯缓冲 | 与外部设备交换数据的缓冲区 |
M 区对 HMI、SCADA、OPC UA 客户端可读可写,适合作为界面与 PLC 逻辑之间的交换区。
V 区 — 内部变量
V 区用于存储 PLC 程序的内部变量,由编译器自动分配地址:
- 用
VAR声明的局部变量 - 功能块实例的内部数据
- 临时计算结果
V 区对外部不可见,仅在 PLC 程序内部使用。
Retain 行为
| 事件 | I 区 | Q 区 | M 区 | V 区 | Retain 变量 |
|---|---|---|---|---|---|
| PLC 停止 | 清零 | 清零/保持 (可配) | 保持 | 清零 | 保持 |
| PLC 热重启 | 刷新 | 保持 | 保持 | 保持 | 保持 |
| PLC 冷重启 | 刷新 | 清零 | 清零 | 清零 | 可选清零 |
| 电源断电 | 丢失 | 丢失 | 丢失 | 丢失 | 保持 (非易失) |
PLC 停止时 Q 区的行为可配置:
- 安全模式 (默认): 所有输出清零,防止执行器失控
- 保持模式: 保持最后输出值,用于需要维持状态的场景 (如夹爪保持)
地址优化
IDE 自动优化 IO 地址映射:
- 间隔合并: 地址间隔小于 128 字节的 IO 点自动合并为一次批量读写
- 对齐优化: 按 WORD/DWORD 边界对齐, 减少总线访问次数
- 缓存友好: 频繁访问的变量集中分配到连续地址空间
数据块 (DB) 区
数据块 (Data Block, DB) 是命名的结构化数据容器, 支持跨 POU 共享和持久化:
DATA_BLOCK DB_Recipe1 // 配方数据块
STRUCT
sName : STRING[32];
rTemperature : REAL;
rPressure : REAL;
iDurationSec : INT;
arIngredients : ARRAY[0..9] OF REAL;
END_STRUCT
END_DATA_BLOCK
// 访问
DB_Recipe1.rTemperature := 85.0;
rValue := DB_Recipe1.arIngredients[3];
// IEC 61131-3 地址形式 (兼容 SIEMENS S7)
%D10.DBW0 → DB10 第 0 字
%D10.DBD4 → DB10 第 4 字节起的双字
DB 特性:
- 每个 DB 有独立地址空间 (最多 65535 个 DB)
- 结构化字段名访问, 类型安全
- 支持整体初始化
- 可标记为 RETAIN / PERSISTENT
- 可批量导入导出 (JSON / CSV)
- HMI / SCADA 通过 OPC UA 节点直接读写
S 区 — 系统状态 (只读)
S 区暴露 PLC 运行时的系统状态, 仅可读:
| 地址 | 类型 | 内容 |
|---|---|---|
%SW0 | TIME | 当前扫描时间 (最近一次 OB1 执行耗时) |
%SW2 | INT | CPU 负载百分比 0~100 |
%SW4 | INT | 已运行小时数 |
%SW6 | DATE | 系统日期 |
%SW10 | TOD | 系统时间 |
%SW20 | INT | 任务超时计数 |
%SW22 | INT | IO 错误计数 |
%SW24 | INT | 通讯错误计数 |
%SW30 | UDINT | 累计扫描次数 |
%SW40 | INT | 风扇转速 (rpm) |
%SW42 | REAL | 主板温度 (°C) |
用户程序可读取 S 区用于诊断:
VAR
tScanCurr AT %SW0 : TIME;
iCpuLoad AT %SW2 : INT;
rBoardTemp AT %SW42 : REAL;
END_VAR
// 高温降频
IF rBoardTemp > 65.0 THEN
bReducedMode := TRUE;
END_IF;
// 扫描超长报警
IF tScanCurr > T#150ms THEN
LogWarn('扫描超长: ', TIME_TO_STRING(tScanCurr));
END_IF;
内存分配策略
默认内存布局
| 区域 | 默认大小 | 范围 | 可调 |
|---|---|---|---|
| I 区 | 由 IO 配置决定 | 0 ~ 65535 字节 | 否 (硬件决定) |
| Q 区 | 由 IO 配置决定 | 0 ~ 65535 字节 | 否 |
| M 区 | 65536 字节 (64 KB) | 0 ~ 65535 | 可扩到 1 MB |
| D 区 | 由 DB 数量决定 | 每 DB 最大 64 KB | 总量可配 |
| V 区 | 自动扩展 | 动态 | 无需配 |
| RETAIN 区 | 16 KB | 非易失 | 可扩到 256 KB |
| PERSISTENT 区 | 4 KB | 非易失 + 备份 | 可扩到 64 KB |
在项目属性 → 内存配置中调整:
| 参数 | 默认 | 最大 | 说明 |
|---|---|---|---|
M_AreaSize | 65536 | 1048576 | M 区字节数 |
RetainSize | 16384 | 262144 | RETAIN 区字节数 |
PersistentSize | 4096 | 65536 | PERSISTENT 区字节数 |
MaxDBs | 256 | 65535 | 最多数据块数量 |
非易失存储 (NVRAM)
RETAIN 和 PERSISTENT 依赖非易失存储:
- 备用电池: SRAM + 电池, 断电后 10 年保持
- 铁电存储 (FRAM): 无需电池, 10^14 次写寿命
- 闪存 (Flash): 无电池, 但写次数有限 (10^5), 需要磨损均衡
PLC 启动时自动校验 NVRAM 完整性:
- CRC 校验 → 失败则 RETAIN 区清零, 触发 OB100 冷启动
- 电池低压预警 → 状态字
%SW50位 0 置 1 - 日志记录每次 NVRAM 写入 (长寿命管理)
电池电量不足时状态字会预警。断电更换电池前先热重启一次, 确保 RETAIN 数据已写入 Flash 备份。更换过程中数据通过电容保持 5 分钟, 但超时会丢失。
IO 映像表 (Process Image)
三段式扫描依赖 IO 映像表 (双缓冲):
┌─ 硬件 IO ───┐ ┌─ 程序视角 ──┐
│ 实时抖动 │ ←采样/刷新→ │ 稳态快照 │
│ 持续变化 │ │ 周期不变 │
└──────────────┘ └──────────────┘
↑ ↓
│ 周期末尾一次性下发输出 │
│ 周期开始一次性读入输入 │
└─────────── IO 映像表 ─────────┘
映像表提供:
- 输入一致性: 程序在一个周期内看到的
%IX0.0不会变 - 输出原子性: 所有 Q 区变量在周期末一次写出
- 批量总线访问: 合并相邻地址减少 EtherCAT / Modbus 帧数
排错表
| 问题 | 原因 | 解决 |
|---|---|---|
| I 区写入编译错误 | I 区只读 | 用 VAR 中间变量 |
| Q 区意外复位 | PLC 停止时默认清零 | 配置 "保持模式" |
| RETAIN 数据丢失 | NVRAM 电池耗尽 | 更换电池 |
| 地址冲突警告 | 多变量占同一地址 | 重新分配地址 |
| 扫描时间异常 | M 区过大 | 缩减 M 区, 分段访问 |
| DB 访问越界 | DB 字段偏移错误 | 检查 DB 结构定义 |