如何在 MISRAC-2004-complaint C 中实现 modbus RTU?

问题描述

我正在开发带有 32 位 MCU 的 modbus RTU 从设备。设备的操作取决于许多参数。因此,设备应支持 modbus 功能码进行参数读写。具体支持哪些功能代码由我自己设计。

一个 modbus 主设备读取或写入特定地址的从设备的寄存器。所以,我需要将参数映射到带有地址的寄存器。我想出了这种方法:使用一个或多个保持寄存器来表示一个参数。 (保持寄存器是具有读写访问权限的 16 位变量。)使用以下联合在参数和寄存器之间建立连接:struct 用于参数,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 包允许您选择

使用联合来打包数据是misra 标准Is it legal write to a byte array in a union and read from an int to convert values in MISRA C? 后续版本中描述的例外之一并在编译时打包。