移植nanomodbus到STM32f103c8t6 的个人笔记

目录
可参考文章:
nanomodbus下载:
nanoMODBUS:A compact MODBUS RTU/TCP C library for embedded/microcontrollers - AtomGit | GitCode
库移植:
只需要俩个文件就能移植nanomodbus库了:
就是nanomodbus.c 和 nanomodbus.h
直接复制到keil的工程,别忘了添加路径就行
使用参考:
协议传输层主要参考port.c和port.h:
这里的应用很简单,其实只要
调用一个自己写的函数去初始化
调用库中的函数循环执行就行
编写初始化文件:
初始化函数是需要自己编写的,这里我直接写了一个文件#include "nanomodbus_config.h"
来存初始化函数以及它链接的一系列回调函数
回调函数也是需要自己写的,这里大部分都是抄的port.c的内容
定义modbus实例:
这俩就是定义的实例结构体,这里的初始化是作为从机的实例
nmbs_server中的
.id就是从机地址
.coils 和.regs就是不同类型的寄存器实际值的存放点
.regs就是保持寄存器,用0x03功能码就能读到
cppnmbs_t nmbs_slave; // 实例 nmbs_server_t nmbs_server = { .id = 0x02, .coils = { 0, }, .regs = { 0, }, };他们会在初始化函数以及poll中被调用
编写初始化函数:
最开头初始化 需要调用 自定义写好的 初始化函数
我这里的初始化是作为从机的实例
这个初始化函数主要定义并初始化了一些结构体,并链接了各个回调函数
回调函数也需要自己写,一般可以先抄写port.c的例子,有需要再自己改细节
需要注意的是:
nmbs_platform_conf_create(); 和 nmbs_callbacks_create();作用是清空结构体(准确讲应该是初始化,把所有链接成默认值,就比如它的crc函数就有自己默认的)
cpp//初始化 从机 nmbs_error nmodbus_rtu_slave_init(nmbs_t* nmbs, nmbs_server_t* _server) { nmbs_platform_conf platform; // 平台配置 nmbs_callbacks callbacks; // 从机回调 //先初始化清空结构体 nmbs_platform_conf_create(&platform); nmbs_callbacks_create(&callbacks); server = _server; platform.transport = NMBS_TRANSPORT_RTU; // RTU platform.read = uart_modbus_read; // 串口读取函数 platform.write = uart_modbus_write; // 串口发送函数 platform.crc_calc = nmbs_crc_calc; // CRC (nanomodbus 库中的 原生函数) //platform.crc_calc = Modbus_CRC16; // CRC16(我的) // 绑定读写寄存器 回调函数 callbacks.read_coils = server_read_coils; callbacks.read_holding_registers = server_read_holding_registers; callbacks.write_single_coil = server_write_single_coil; callbacks.write_multiple_coils = server_write_multiple_coils; callbacks.write_single_register = server_write_single_register; callbacks.write_multiple_registers = server_write_multiple_registers; nmbs_error status = nmbs_server_create(nmbs, server->id, &platform, &callbacks); if (status != NMBS_ERROR_NONE) { return status; } nmbs_set_byte_timeout(nmbs, 100); nmbs_set_read_timeout(nmbs, 1000); //nmbs_server_create(&nmbs_slave, 1, &platform, &callbacks); nmbs_set_platform_arg(&nmbs_slave, &huart1); return NMBS_ERROR_NONE; }
编写回调函数:
回调函数基本都是抄的port.c的例子,下面会随着整个文件一块贴出了
nanomodbus_config.h
cpp
#ifndef __nanomodbus_config_H__
#define __nanomodbus_config_H__
#include "stm32f1xx_hal.h"
#include "Uart.h"
#include "nanomodbus.h"
#include "string.h"
#define MB_UART huart1
#define MB_RX_BUF_SIZE 256
#define COIL_BUF_SIZE 1024
#define REG_BUF_SIZE 2048
typedef struct tNmbsServer {
uint8_t id;
uint8_t coils[COIL_BUF_SIZE];
uint16_t regs[REG_BUF_SIZE];
} nmbs_server_t;
extern nmbs_t nmbs_slave;
extern nmbs_server_t nmbs_server;
//extern nmbs_platform_conf platform;
//extern uint16_t nmbs_holding_regs[];
nmbs_error nmodbus_rtu_slave_init(nmbs_t* nmbs, nmbs_server_t* _server);//初始化 从机
#endif
nanomodbus_config.c
cpp
#include "nanomodbus_config.h"
static nmbs_server_t* server;
nmbs_t nmbs_slave; // 实例
//nmbs_t nmbs;
nmbs_server_t nmbs_server = {
.id = 0x02,
.coils =
{
0,
},
.regs =
{
0,
},
};
int32_t uart_modbus_read(uint8_t* buf, uint16_t count, int32_t byte_timeout_ms,void* arg);
int32_t uart_modbus_write(const uint8_t* buf, uint16_t count, int32_t byte_timeout_ms,void* arg);
//uint16_t Modbus_CRC16(const uint8_t* data, uint32_t length,void* arg);
static nmbs_error server_read_coils(uint16_t address, uint16_t quantity, nmbs_bitfield coils_out, uint8_t unit_id,void* arg);
static nmbs_error server_read_holding_registers(uint16_t address, uint16_t quantity, uint16_t* registers_out,uint8_t unit_id, void* arg);
static nmbs_error server_write_single_coil(uint16_t address, bool value, uint8_t unit_id, void* arg);
static nmbs_error server_write_multiple_coils(uint16_t address, uint16_t quantity, const nmbs_bitfield coils,uint8_t unit_id, void* arg);
static nmbs_error server_write_single_register(uint16_t address, uint16_t value, uint8_t unit_id, void* arg);
static nmbs_error server_write_multiple_registers(uint16_t address, uint16_t quantity, const uint16_t* registers,uint8_t unit_id, void* arg);
//初始化 从机
nmbs_error nmodbus_rtu_slave_init(nmbs_t* nmbs, nmbs_server_t* _server)
{
nmbs_platform_conf platform; // 平台配置
nmbs_callbacks callbacks; // 从机回调
//先初始化清空结构体
nmbs_platform_conf_create(&platform);
nmbs_callbacks_create(&callbacks);
server = _server;
platform.transport = NMBS_TRANSPORT_RTU; // RTU
platform.read = uart_modbus_read; // 串口读取函数
platform.write = uart_modbus_write; // 串口发送函数
platform.crc_calc = nmbs_crc_calc; // CRC (nanomodbus 库中的 原生函数)
//platform.crc_calc = Modbus_CRC16; // CRC16(我的)
// 绑定读写寄存器 回调函数
callbacks.read_coils = server_read_coils;
callbacks.read_holding_registers = server_read_holding_registers;
callbacks.write_single_coil = server_write_single_coil;
callbacks.write_multiple_coils = server_write_multiple_coils;
callbacks.write_single_register = server_write_single_register;
callbacks.write_multiple_registers = server_write_multiple_registers;
nmbs_error status = nmbs_server_create(nmbs, server->id, &platform, &callbacks);
if (status != NMBS_ERROR_NONE)
{
return status;
}
nmbs_set_byte_timeout(nmbs, 100);
nmbs_set_read_timeout(nmbs, 1000);
//nmbs_server_create(&nmbs_slave, 1, &platform, &callbacks);
nmbs_set_platform_arg(&nmbs_slave, &huart1);
return NMBS_ERROR_NONE;
}
int32_t uart_modbus_read(uint8_t* buf, uint16_t count, int32_t byte_timeout_ms, void* arg)
{
HAL_StatusTypeDef status = HAL_UART_Receive(&MB_UART, buf, count, byte_timeout_ms);
if (status == HAL_OK) {
return count;
}
else {
return 0;
}
}
int32_t uart_modbus_write(const uint8_t* buf, uint16_t count, int32_t byte_timeout_ms,void* arg)
{
HAL_StatusTypeDef status = HAL_UART_Transmit(&MB_UART, buf, count, byte_timeout_ms);
if (status == HAL_OK) {
return count;
}
else {
return 0;
}
}
static nmbs_server_t* get_server(uint8_t id) {
if (id == server->id) {
return server;
}
else {
return NULL;
}
}
static nmbs_error server_read_coils(uint16_t address, uint16_t quantity, nmbs_bitfield coils_out, uint8_t unit_id,
void* arg) {
nmbs_server_t* server = get_server(unit_id);
for (size_t i = 0; i < quantity; i++) {
if ((address >> 3) > COIL_BUF_SIZE) {
return NMBS_ERROR_INVALID_REQUEST;
}
nmbs_bitfield_write(coils_out, address, nmbs_bitfield_read(server->coils, address));
address++;
}
return NMBS_ERROR_NONE;
}
static nmbs_error server_read_holding_registers(uint16_t address, uint16_t quantity, uint16_t* registers_out,
uint8_t unit_id, void* arg) {
nmbs_server_t* server = get_server(unit_id);
for (size_t i = 0; i < quantity; i++) {
if (address > REG_BUF_SIZE) {
return NMBS_ERROR_INVALID_REQUEST;
}
registers_out[i] = server->regs[address++];
}
return NMBS_ERROR_NONE;
}
static nmbs_error server_write_single_coil(uint16_t address, bool value, uint8_t unit_id, void* arg) {
uint8_t coil = 0;
if (value) {
coil |= 0x01;
}
return server_write_multiple_coils(address, 1, &coil, unit_id, arg);
}
static nmbs_error server_write_multiple_coils(uint16_t address, uint16_t quantity, const nmbs_bitfield coils,
uint8_t unit_id, void* arg) {
nmbs_server_t* server = get_server(unit_id);
for (size_t i = 0; i < quantity; i++) {
if ((address >> 3) > COIL_BUF_SIZE) {
return NMBS_ERROR_INVALID_REQUEST;
}
nmbs_bitfield_write(server->coils, address, nmbs_bitfield_read(coils, i));
address++;
}
return NMBS_ERROR_NONE;
}
static nmbs_error server_write_single_register(uint16_t address, uint16_t value, uint8_t unit_id, void* arg) {
uint16_t reg = value;
return server_write_multiple_registers(address, 1, ®, unit_id, arg);
}
static nmbs_error server_write_multiple_registers(uint16_t address, uint16_t quantity, const uint16_t* registers,
uint8_t unit_id, void* arg) {
nmbs_server_t* server = get_server(unit_id);
for (size_t i = 0; i < quantity; i++) {
if (address > REG_BUF_SIZE) {
return NMBS_ERROR_INVALID_REQUEST;
}
server->regs[address++] = registers[i];
}
return NMBS_ERROR_NONE;
}
/*!< CRC calculation function pointer. Optional */
//uint16_t Modbus_CRC16(const uint8_t* data, uint32_t length,void* arg)
//{
// unsigned short crc = 0xFFFF,i=0;
//
// for (i = 0; i < length; i++) {
// crc ^= data[i];
// for (unsigned char j = 0; j < 8; j++)
// {
// if (crc & 0x0001) {
// crc >>= 1;
// crc ^= 0xA001;
// } else {
// crc >>= 1;
// }
// }
// }
// return crc;
//}
使用:
初始化
cppnmodbus_rtu_slave_init(&nmbs_slave, &nmbs_server);
循环调用( 可以放在直接 while( 1 )中 )
cppnmbs_server_poll(&nmbs_slave);
NMBS_DEBUG_PRINT函数宏:
如果你没有为其链接打印函数,那它就是个空语句,不会执行任何动作,不会卡死程序
这里我就没给他链接任何语句
中断接收冲突问题:
不能同时开 HAL_UART_Receive_IT 和阻塞 HAL_UART_Receive
两者不能同时用,STM32 串口开了 IT,再调用阻塞 Receive 会直接卡死在 HAL 内部。
我的串口是中断方式传输数据的,本来我在搭框架时就 写好了缓存处理的逻辑:后来发现与uart_modbus_read 函数的接收冲突,就注释了前者:












