CODESYS V3.5在车载显示终端上做二次开发:几个踩过的坑

最近在一台车载显示终端上做CODESYS V3.5 SP16的二次开发,把原来跑在主控制器里的一小段逻辑挪到屏幕上,顺便用屏幕的8枚物理按键做画面切换。记录几个踩过的坑,给后面做同类项目的同学参考。

背景

设备是一台工程车辆的驾驶室HMI,7寸800×480液晶屏,电容触摸 + 8个物理按键,双路CAN,一路J1939接发动机,一路CANopen接自研控制器。主控跑嵌入式Linux,上面起CODESYS Runtime。

坑一:按键事件和PLC扫描周期对不上

最开始我把物理按键的状态直接绑到一个全局变量 bKey1,然后在PLC里这样写:

IF bKey1 THEN
    ePage := ePage + 1;
END_IF

结果按一次键,画面跳两三页。原因很简单:PLC扫描周期是10ms,按键按下的时间有几百毫秒,等于在这段时间里 bKey1 一直为TRUE,ePage 被加了几十次。

解决办法是在HMI侧做按键消抖和"按下沿"检测,只把脉冲事件传给PLC:

// HMI侧伪代码:检测下降沿(按下瞬间)
if (raw_key1 == 0 && prev_key1 == 1) {
    send_can_event(KEY1_PRESSED);
}
prev_key1 = raw_key1;

PLC侧收到的是"事件"而不是"电平",逻辑就稳了。

坑二:CANopen PDO映射里的REAL字段

自研控制器有一个动臂压力信号,发过来是4字节浮点。我在CODESYS里直接建了个REAL变量映射到PDO,结果读出来全是离谱的数字。

抓了CAN报文才发现,控制器发的是大端(Motorola),而CODESYS默认按小端解析。改成数组拼接:

// 错误示范
// pressure AT %QD1.0 : REAL;

// 正确做法
pressure_bytes AT %QB1..%QB4 : ARRAY[0..3] OF BYTE;
pressure := DWORD_TO_REAL(
    BYTE_TO_DWORD(pressure_bytes[0]) * 16777216 +
    BYTE_TO_DWORD(pressure_bytes[1]) * 65536 +
    BYTE_TO_DWORD(pressure_bytes[2]) * 256 +
    BYTE_TO_DWORD(pressure_bytes[3])
);

不同设备厂商的字节序真的要在文档里写死,不要假设。

坑三:Retain变量掉电后没保存

累计工时这个参数,我放在了Retain变量里,调试时发现每次重新上电都归零。查了一下,CODESYS的Retain默认是依赖Runtime的持久化机制,但在嵌入式Linux上,如果没有在工程里显式配置Retain文件路径,Runtime重启时会把Retain区当普通RAM清掉。

在CODESYS的设备树里,找到Runtime的Persistent Settings,把Retain存储路径指到eMMC上一个固定文件,再把掉电保存做成主动调用 PERSISTENT_SAVE(),问题就解决了。

坑四:视频输入和可视化画面的层级

接倒车摄像头时,希望挂倒挡自动弹出视频画面,并且视频是叠加层,不挡住原来的车速表。一开始把视频窗口当成一个普通可视化控件,结果视频延迟大,而且CODESYS画面重绘时视频会闪。

实际做法是视频输入走硬件叠加层(Linux的framebuffer overlay或DRM plane),CODESYS只在上面画一个半透明的距离提示框和"R挡"图标。挂倒挡的信号从CAN报文里来,PLC检测到后通知HMI切叠加层显隐。

坑五:Wi-Fi调试时把生产CAN总线搞崩

开发阶段为了方便,用Wi-Fi连CODESYS在线调试,一边下程序一边看CAN报文。有次下程序时Runtime重启,CAN控制器跟着复位,正在跑的设备突然报通信故障,吓出一身冷汗。

后来定了条规矩:在线调试必须在停车、熄火、发动机待机状态下做,Wi-Fi调试口只在工程模式开启,量产固件默认关Wi-Fi,只留USB本地升级。

小结

车载HMI的CODESYS开发,坑大多不在语法,而在"事件 vs 电平""字节序""持久化""硬件叠加层"这几个和硬件强相关的地方。我用的这台机器是SCP700-070A,双路CAN和物理按键的硬件设计把这些坑的暴露面缩小了不少,但软件侧的工程习惯还是得自己立住。

posted @ 2026-10-22 16:02  Brock_bky  阅读(2)  评论(0)    收藏  举报