用户配置文件

重点

协议栈对功能的裁剪和配置应当是很容易的事情,以控制软件包的资源用量。

common/include 下有 MBx_user_sample.h 文件,将其复制一份并且重命名为 MBx_user.h ,加入可被 include 找到的路径。

在编译全局 define 增加 MBX_INCLUDE_USER_DEFINE_FILE ,这样库内就会使用 MBx_user.h 的各自定义而非默认。

由于配置文件符合 CMSIS Configuration Wizard Annotations,可以使用 vscode 的插件或者其他方式对 MBx_user.h 配置进行渲染,进行更直观的配置,推荐的方法就是 vscodeArm CMSIS Solution 插件

安装完成,打开 MBx_user.h 文件后,点击右上角的 "Open Preview" 图标,即可渲染配置文件进行图形化配置。

配置细则

MBX_SLAVE_ENABLE

默认 1

从机功能是否开启 1则开启 0则裁剪去掉从机功能

MBX_MASTER_ENABLE

默认 1

主机功能是否开启 1则开启 0则裁剪去掉主机功能

MBX_MODULE_TCP_MASTER_ENABLE

默认 1

如果使用 modbus TCP 的主机功能需要将这个宏置为 1,否则推荐是置 0,会明显减少资源的占用(主要是 RAM)。

MBX_MASTER_REQUEST_QUEUE_MAX

默认 40

主机请求队列的最大寄存条数,用于连续读写请求,寄存并自动发送处理。此条会显著影响 RAM 占用。

MBX_MASTER_MULTI_REG_MAX

默认 127

主机读写多个寄存器的最大个数,用于设定库发出的连续读或连续写指令,最多可指定多少个寄存器,此条会显著影响 RAM 占用。

MBX_EXTEN_REG_HANDLE_ENABLE

默认 0

注意到在库内给出的例程,所有不同的映射变量,需要独立且尽可能唯一的处理函数。

如果需要在某一个处理函数中处理来自不同的 modbus 虚拟地址的请求,那么这个宏应该置为 1。这个宏置 1 后需要更改映射表的条目(每个条目增加了一个传参集),并且每个写时回调应该以新的方式编写,后面会详细介绍。

一个明显的适用场景是,作为 modbus 从机,但这个从机只是中间件,需要控制多个完全相同的模块实例,那么这个宏的开启将极大缩减工作量并降低维护难度。针对这样的应用场景有如下的实践案例。

原本的部分映射表如下,这三个地址分别控制了三个完全一样的模块,

{.Addr = 0x2001, .Memory = &(Powerflag[0]), .Type = MBX_REG_TYPE_U8,    .Handle = ModbusModulePower1,},
{.Addr = 0x2011, .Memory = &(Powerflag[1]), .Type = MBX_REG_TYPE_U8,    .Handle = ModbusModulePower2,}, 
{.Addr = 0x2021, .Memory = &(Powerflag[2]), .Type = MBX_REG_TYPE_U8,    .Handle = ModbusModulePower3,}, 

需要编写三个几乎一致的回调,类似如下。虽然可以使用宏生成函数等其他手段,但仍然是难以统一维护的。

uint32_t ModbusModulePower1(void *value)
{
    uint8_t ValueGet = (*(uint8_t *)value);

    if(ValueGet > 0)
    {
        /* 忽略一些开机操作 */
        Powerflag[0] = 1;
    }
    else
    {
        /* 忽略一些关机操作 */
        Powerflag[0] = 1;
    }

    return MBX_API_RETURN_DEFAULT;
}

而开启这个宏后,需要更新这部分映射表如下

const _MBX_REG_HANDLE_PARA       MBXPara1 = {.Para1 = 1, .Para2 = 1};
const _MBX_REG_HANDLE_PARA       MBXPara2 = {.Para1 = 2, .Para2 = 2};
const _MBX_REG_HANDLE_PARA       MBXPara3 = {.Para1 = 3, .Para2 = 3};
......
{.Addr = 0x2001, .Memory = &(Powerflag[0]), .Type = MBX_REG_TYPE_U8, .Handle = ModbusModulePower, .Para = &MBXPara1},
{.Addr = 0x2011, .Memory = &(Powerflag[1]), .Type = MBX_REG_TYPE_U8, .Handle = ModbusModulePower, .Para = &MBXPara2}, 
{.Addr = 0x2021, .Memory = &(Powerflag[2]), .Type = MBX_REG_TYPE_U8, .Handle = ModbusModulePower, .Para = &MBXPara3}, 

这里增加了三个全局静态量,作为参数集,同时每个映射条目需要增加 .Para 部分的绑定,这个参数集会传递给写时处理函数,这样使得三个完全一模一样的模块不必定义三个几乎一样的处理函数,而可以调用同一个,所以处理函数的定义需要更新为如下

uint32_t ModbusModulePower(void *value, _MBX_REG_HANDLE_PARA *para)
{
    uint8_t ValueGet = (*(uint8_t *)value);

    if(ValueGet > 0)
    {
        /* 执行 para->Para1 编号模块的开机操作 */
        Powerflag[para->Para1 - 1] = 1;
    }
    else
    {
        /* 执行 para->Para1 编号模块的关机操作 */
        Powerflag[para->Para1 - 1] = 1;
    }

    return MBX_API_RETURN_DEFAULT;
}

对于不使用这个传参的条目,最佳方法是将 .Para = &DefaultPara 这个 DefaultPara 是一个开启宏后会产生的静态量,避免野指针。