博途DB块使用详解
“我明明新建了输入映射DB和输出映射DB,为什么我不能直接写它们的值?”
“为什么我在程序里想给输入DB里的某个点赋值为1,却报错或者没效果?”
🧠 一、首先要明确概念:输入映射DB ≠ 输入区(I区)
当你自己新建一个全局DB,比如:
DB_InputMap
:用来保存输入信号(IO映射)DB_OutputMap
:用来保存输出信号(IO映射)
它们只是普通的内存变量集合,并不和 PLC 实际的输入输出硬件(I、Q区)直接关联。
也就是说:
项目 | 系统自动IO区 | 你新建的全局DB |
---|---|---|
I区 | 硬件输入寄存器,PLC每扫描周期自动刷新 | ❌ 你自己新建的DB不会自动刷新 |
Q区 | 硬件输出寄存器,PLC每扫描周期自动写出 | ❌ 你自己新建的DB不会自动输出 |
👉 因此,如果你新建的 DB_InputMap
中变量是人工写的,比如:
DB_InputMap ├── Start_Button : Bool ├── Stop_Button : Bool
你直接在程序里写:
DB_InputMap.Start_Button := TRUE;
如图所示对输入点"I42.5"的物理节做了映射,此时如果对"Input.DI1001FCFT"进行赋值 ,虽然语法没错,但逻辑上这是在改“内存变量”,不是改真实输入点。
所以它不会影响实际的输入信号,也不会影响逻辑运算中“自动更新”的部分。
⚙️ 二、为什么你不能(或不应该)去改它
在实际工程中,“输入映射DB” 通常是设计成只读的,原因有三点:
1️⃣ 输入信号来自现场硬件(I区),不应该被程序随意更改。
它反映的是外部真实状态,比如按钮、传感器、开关等。
2️⃣ 在扫描周期开始时,PLC自动从I区读入输入映像区,如果你中途强制改值,下一周期又会被硬件刷新掉。因为在主函数"main"中是一直调用"IO映射"函数的,人为写入"Input.DI1001FCFT"进行赋值会被下一周期硬件刷新掉。
3️⃣ 人为写入会造成逻辑混乱,可能导致程序与现场状态不一致。
🔄 三、输入输出映射DB的正确使用方式
这种“映射DB”结构是对程序进行解耦和规范化设计的常见方法,但必须分两步用:
✅ 第一步:映射硬件 → DB变量(输入映射)
// 在主程序开头,将I区输入信号赋值给DB变量 DB_InputMap.Start_Button := I0.0; DB_InputMap.Stop_Button := I0.1; DB_InputMap.Sensor_OK := I0.2;
🧩 说明:
- DB_InputMap 是输入映射区,如"IO映射的Input块";
- 它的值在每个扫描周期开始时从 I 区读入;
- 程序内部所有逻辑都使用 DB_InputMap 中的变量,如使用"IO映射的Input块"中的变量,不再直接用 I 区。
✅ 第二步:DB变量 → 输出区(输出映射)
// 在主程序末尾,将输出映射DB变量写到Q区 Q0.0 := DB_OutputMap.Motor_Run; Q0.1 := DB_OutputMap.Alarm_Light;
🧩 说明:
- 程序中所有控制逻辑(FB、FC等)都只操作 DB_OutputMap,如"Output块数据";
- 最后统一将结果映射回真实的 Q 区。
🧰 四、这样设计的优点
优点 | 说明 |
---|---|
✅ 解耦硬件与逻辑 | 当你更换IO模块、改地址时,只需修改映射区,不用改逻辑程序 |
✅ 方便仿真 | 你可以在不接真实硬件时,手动修改DB_InputMap中的值进行模拟 |
✅ 清晰易读 | 逻辑层只用 DB_InputMap.Start_Button ,一目了然 |
⚠️ 五、如果你想手动改输入值做测试怎么办?
你可以这样做:
方法1️⃣:在线监控手动强制
在TIA Portal在线状态下:
- 打开监控表;
- 对
DB_InputMap.Start_Button
强制(Force)为 TRUE; - 运行逻辑程序;
- 取消强制后恢复硬件输入。
方法2️⃣:用测试模式逻辑赋值
例如:
IF Test_Mode THEN DB_InputMap.Start_Button := TRUE; END_IF;
这样你就可以在测试时模拟输入信号,而不改真实硬件。
🧾 六、总结(你现在的情况的根因)
现象 | 原因 | 解决方法 |
---|---|---|
新建的输入DB不能直接改 | 它不是真实I区,只是内存变量 | 应从I区赋值过来 |
新建的输出DB不能立即生效 | 它不是真实Q区,只是内存变量 | 程序末尾统一赋值到Q区 |
想测试时赋1但没反应 | 输入DB是设计成只读映射 | 用Force或测试逻辑 |
✅ 七、正确结构示例(推荐)
// ========== 输入映射区 ========== DB_InputMap.Start := I0.0; DB_InputMap.Stop := I0.1; // ========== 程序逻辑 ========== IF DB_InputMap.Start AND NOT DB_InputMap.Stop THEN DB_OutputMap.Motor_Run := TRUE; ELSE DB_OutputMap.Motor_Run := FALSE; END_IF; // ========== 输出映射区 ========== Q0.0 := DB_OutputMap.Motor_Run;
✅ 八、或在程序首次运行时(如OB100启动组织块)中手动赋值。
- 在项目树打开 Program blocks → OB100(Startup block)。如果 OB100 不存在就新建一个(语言选择 SCL 推荐)。
- 在 OB100 中写初始化代码(示例假设 DB 名为
DB_Init
,数组MyArray : ARRAY[0..9] OF INT
):
// OB100 (SCL) 示例 —— 将数组全部置 0 VAR i : INT; END_VAR FOR i := 0 TO 9 DO DB_Init.MyArray[i] := 0; END_FOR;
说明:
- 如果你的数组下界不是 0(例如
[1..10]
),就把循环范围改为对应的下/上界。 - 如果你要按规则填充(比如每个元素等于索引值或某计算结果),在循环体内写相应表达式即可:
DB_Init.MyArray[i] := i * 2;
等。
- 编译(Compile)OB100 与 DB,确保没有编译错误。
- 下载 OB100 和 DB 到 PLC(Download all required blocks)。
- 为使 OB100 执行:在在线界面对 PLC 做 Cold start / Restart(冷启动),OB100 会在启动时执行一次(Startup OB)。在调试时你也可以先停止 PLC 再启动以触发该 OB。