c - 如何在 MISRAC-2004-complaint C 中实现 modbus RTU?
问题描述
我正在开发一个带有 32 位 MCU 的 modbus RTU 从设备。设备的运行取决于许多参数。因此,设备应支持参数读写的modbus功能码。支持哪些具体功能码由我自己设计。
modbus 主设备在特定地址读取或写入从设备的寄存器。所以,我需要将参数映射到带有地址的寄存器。我想出了这种方法:使用一个或多个保持寄存器来表示一个参数。(保持寄存器是具有读写访问权限的 16 位变量。)使用以下联合在参数和寄存器之间建立连接:用于参数的结构体和用于寄存器的 uint16_t 数组。
typedef union{
uint16_t holding_register[PARAMETER_STRUCT_SIZE];
struct the_parameters{
float parameter1,parameter2,parameter3;
uint8_t parameter4,parameter5;
};
}modbus_union;
当 modbus 主设备想要访问某个地址的寄存器时,它可以访问数组中索引处的元素。可以在文档中维护某个寄存器的含义。
等效地,可以使用 uint16_t 指针指向 struct the_parameters。而在modbus协议中,它可以只是作为一个数组来处理。
问题是,我的代码应该符合 MISRAC-2004 标准才能通过安全测试。相关的 MISRAC 规则是:
规则 18.4(强制):不得使用工会。
规则 17.1(必需):指针运算只能应用于寻址数组或数组元素的指针。
如何在 MISRAC-2004-complaint C 中实现 modbus RTU?
解决方案
您应该将参数序列化为使用位移位和掩码手动发送的字节。
这可以通过创建在您的类型和字节数组之间转换的函数来完成。
在您当前的示例中,结果取决于微控制器的字节顺序,以及编译器如何选择将值打包到结构中。
在这种情况下,您可能会特别遇到问题,因为许多微控制器都是小端序的,但是构成 modbus 字的字节是大端序的(尽管某些实现仍然这样做/期望否则),如果您的参数跨越多个字,那么您应该正确记录您选择的字节顺序组合。
例如,minimalmodbus python 包允许你在
- 大端(摩托罗拉)高位字节优先(ABCD)
- 带字节交换的大端 (BADC)
- 带字节交换的小端 (CDAB)
- Little endian (Intel) 低位字节优先 (DCBA)
- https://minimalmodbus.readthedocs.io/en/stable/modbusdetails.html#byte-order-for-data-stored-in-serveral-registers
使用联合来打包数据是 misra 标准的后续版本中描述的例外情况之一是否合法地写入联合中的字节数组并从 int 中读取以转换 MISRA C 中的值?但是,您应该正确记录您偏离标准的原因,并在理想情况下放置一些静态断言,以在编译时检查字节顺序和打包等。
推荐阅读
- java - 增强循环不打印我所期望的
- javascript - 使用 Papa Parse 将 JSON 导出为 CSV
- openlayers-5 - 如何在openlayers中为静态图像(使用光栅数据和画布绘制)绘制轴(x轴和y轴)?
- docusignapi - DocuSign - 更新信封 - 添加或更新自定义文本字段
- c++ - 将二维向量传递给 CPP 中的函数
- java - Quarkus:如何将方法从命令式更改为反应式
- javascript - Socket.io 节点服务器无法向电子应用程序发出事件
- python - Pytest,Flask,Celery - Celery NoneType 错误
- pandas - 壁虎的最佳时间间隔,熊猫移位的问题
- java - 我目前正在使用 3 个 for 循环,有什么方法可以减少它们或提高效率