嵌入式技术论坛
直播中

五斤麻辣油

9年用户 1353经验值
擅长:电源/新能源
私信 关注
[经验]

分享一种Agile Modbus简易从机接入接口实现方式

说明

Agile Modbus 提供了 agile_modbus_slave_callback_t 的一种实现方式,使用户能够简单方便接入。

使用示例可查看 examples/slave。

使用方式:

#include "agile_modbus.h"

#include "agile_modbus_slave_util.h"

const agile_modbus_slave_util_t slave_util = {

/* User implementation */

};

agile_modbus_slave_handle(ctx, read_len, 0, agile_modbus_slave_util_callback, &slave_util, NULL);

agile_modbus_slave_util_callback 介绍

Agile Modbus 提供的一种 agile_modbus_slave_callback_t 实现方式,需要 agile_modbus_slave_util_t 类型变量指针作为私有数据。

私有数据为 NULL,所有功能码都能响应且为成功,但寄存器数据依然为 0。

agile_modbus_slave_util_t 介绍

typedef struct agile_modbus_slave_util {

const agile_modbus_slave_util_map_t *tab_bits;                                            /**< 线圈寄存器定义数组 */

int nb_bits;                                                                              /**< 线圈寄存器定义数组数目 */

const agile_modbus_slave_util_map_t *tab_input_bits;                                      /**< 离散量输入寄存器定义数组 */

int nb_input_bits;                                                                        /**< 离散量输入寄存器定义数组数目 */

const agile_modbus_slave_util_map_t *tab_registers;                                       /**< 保持寄存器定义数组 */

int nb_registers;                                                                         /**< 保持寄存器定义数组数目 */

const agile_modbus_slave_util_map_t *tab_input_registers;                                 /**< 输入寄存器定义数组 */

int nb_input_registers;                                                                   /**< 输入寄存器定义数组数目 */

int (*addr_check)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info);       /**< 地址检查接口 */

int (*special_function)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info); /**< 特殊功能码处理接口 */

int (*done)(agile_modbus_t *ctx, struct agile_modbus_slave_info *slave_info, int ret);    /**< 处理结束接口 */

} agile_modbus_slave_util_t;

寄存器相关

用户需要实现 bits、input_bits、registers、input_registers 定义。如果某个寄存器定义为 NULL,该寄存器对应的功能码能响应且为成功,但寄存器数据都为 0。

接口调用过程

agile_modbus_slave_util_map 介绍

typedef struct agile_modbus_slave_util_map {

int start_addr;                                       /**< 起始地址 */

int end_addr;                                         /**< 结束地址 */

int (*get)(void *buf, int bufsz);                     /**< 获取寄存器数据接口 */

int (*set)(int index, int len, void *buf, int bufsz); /**< 设置寄存器数据接口 */

} agile_modbus_slave_util_map_t;

注意事项:

起始地址和结束地址决定的寄存器个数有限制。更改函数内部 map_buf 数组大小可使其变大。

bit 寄存器 < 250

register 寄存器 < 125

接口函数为 NULL,寄存器对应的功能码能响应且为成功。

get 接口

将地址域内的数据全部拷贝到 buf 中。

set 接口

index: 地址域内的偏移

len: 长度

根据 index 和 len 修改数据。

示例

以 01 功能码为例:

#include <stdint.h>

#include <pthread.h>

#include "agile_modbus.h"

#include "agile_modbus_slave_util.h"

static uint8_t _tab_bits[10] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1};

static int get_map_buf(void *buf, int bufsz)

{

uint8_t *ptr = (uint8_t *)buf;

pthread_mutex_lock(&slave_mtx);

for (int i = 0; i < sizeof(_tab_bits); i++) {

    ptr[i] = _tab_bits[i];

}

pthread_mutex_unlock(&slave_mtx);

return 0;

}

static int set_map_buf(int index, int len, void *buf, int bufsz)

{

uint8_t *ptr = (uint8_t *)buf;

pthread_mutex_lock(&slave_mtx);

for (int i = 0; i < len; i++) {

    _tab_bits[index + i] = ptr[index + i];

}

pthread_mutex_unlock(&slave_mtx);

return 0;

}

const agile_modbus_slave_util_map_t bit_maps[1] = {

{0x041A, 0x0423, get_map_buf, set_map_buf}};

原作者:Cfly

更多回帖

发帖
×
20
完善资料,
赚取积分