基于GD32F305实现和测试,核心层已经初步抽象出来了,方便移植,从机部分已测试通过,主机部分暂未测试。记录备份一下,以后完善。

用于配置的头文件:

#ifndef __MODBUS_CONFIG_H__
#define __MODBUS_CONFIG_H__

#include "modbus_port.h"

// Modbus通道(串口)的总数量
#define MB_CHANNEL_COUNT            1

// 每个通道的读写缓冲区大小 (字节) 应至少为64。
#define MB_BUFFER_SIZE              128

// 主站模式下,等待从站响应的超时时间 (单位: 毫秒)
#define MB_MASTER_TIMEOUT_MS        200

// 可选的定时器源类型 (用于判断帧间隔)
#define MB_TIMER_DWT                1  // 使用DWT计数器
#define MB_TIMER_HW_TIM             2  // 使用MCU的硬件外设定时器
#define MB_TIMER_SYSTICK            3  // 使用SysTick计数 (如果其他任务占用则不推荐使用)
#define MB_TIMER_IDLE               4  // 使用串口IDLE中断检测帧尾 (帧间隔为1T,而标准modbus-rtu规定为3.5T)

// 选择定时器源类型
#define MB_TIMER_SOURCE             MB_TIMER_DWT
//#define MB_TIMER_SOURCE             MB_TIMER_IDLE

/* 各通道硬件与地址配置 */
// 物理串口外设
#define MB_CHANNEL_0_USART_PERIPH   UART3
// 波特率
#define MB_CHANNEL_0_BAUD           9600
// 作为从站时的地址
#define MB_CHANNEL_0_ADDR           0x01

#endif

核心层:

#ifndef __MODBUS_CORE_H__
#define __MODBUS_CORE_H__

#include "modbus_port.h"
#include "modbus_config.h"

// Modbus API 函数返回状态码
typedef enum
{
    MB_OK = 0,                  // 操作成功
    MB_ERR_BUSY,                // 主站正忙,无法发起新请求
    MB_ERR_TIMEOUT,             // 主站等待响应超时
    MB_ERR_INVALID_RESPONSE,    // 响应的地址/功能码/CRC等无效
    MB_SUCCESS                  // 主站事务成功完成 (用于回调函数)
} eMBStatus;

// Modbus 通道工作模式
typedef enum
{
    MODE_SLAVE = 0,
    MODE_MASTER // @TODO: 主站模式暂未测试
} eMBMode;

// 内部状态机定义 (仅供内部使用)
typedef enum
{
    STATE_RX_INIT,
    STATE_RX_ING,
    STATE_RX_DONE
} eMBRxState;
typedef enum
{
    STATE_M_IDLE,
    STATE_M_WAIT_RX,
    STATE_M_DONE
} eMBMasterState;

// 主站事务完成回调函数指针类型
typedef void (*ModbusMasterCallback)(eMBStatus status, uint8_t* p_data, uint16_t len);

// Modbus 通道上下文结构体
typedef struct
{
    uint32_t                usart_periph;
    uint8_t                 slave_address;
    uint32_t                baud_rate;
    eMBMode                 mode;
    volatile eMBMasterState master_state;
    volatile eMBRxState     slave_state;
    volatile uint8_t        rx_buffer[MB_BUFFER_SIZE];
    volatile uint16_t       rx_counter;
    volatile uint8_t        tx_buffer[MB_BUFFER_SIZE];
    volatile uint16_t       tx_len_total; // 要发送的总长度
    volatile uint16_t       tx_len_sent;  // 已发送的字节计数
    volatile uint32_t       last_rx_timestamp;
    volatile uint32_t       master_tx_timestamp;
    uint32_t                t35_cycles;
    uint32_t                master_timeout_cycles;
    ModbusMasterCallback    master_callback;
} ModbusChannel;

// 初始化所有Modbus通道
void Modbus_Init(void);

// Modbus轮询函数 在主循环(while(1))中持续调用
void Modbus_Poll(void);

// 获取指定通道的上下文结构体指针
ModbusChannel *Modbus_GetChannel(uint8_t ch_idx);

// 设置指定通道的工作模式 (主站或从站)
void Modbus_SetChannelMode(uint8_t ch_idx, eMBMode mode);

// 主站主动发起异步读寄存器
eMBStatus Modbus_Master_ReadRegisters(uint8_t ch_idx, uint8_t target_slave_addr, uint16_t reg_addr, uint16_t num_of_regs, ModbusMasterCallback callback);

// 主站主动发起异步写寄存器
eMBStatus Modbus_Master_WriteRegisters(uint8_t ch_idx, uint8_t target_slave_addr, uint16_t reg_addr, uint16_t num_of_regs, uint16_t *data, ModbusMasterCallback callback);

// 供移植层ISR调用的函数
void Modbus_OnSerialReceive(uint8_t ch_idx, uint8_t data);

void Modbus_OnSerialTransmit(uint8_t ch_idx);

void Modbus_OnIdleDetected(uint8_t ch_idx);

#endif
#include "modbus_core.h"
#include "modbus_port.h"
#include "modbus_config.h"

static ModbusChannel channels[MB_CHANNEL_COUNT];
static uint32_t timer_freq;

static void Modbus_Slave_Parse(ModbusChannel* ch);
static void Modbus_Master_Parse(ModbusChannel* ch);
static uint16_t CRC16(const volatile uint8_t *pucFrame, uint16_t usLen);

ModbusChannel *Modbus_GetChannel(uint8_t ch_idx)
{
    if (ch_idx < MB_CHANNEL_COUNT)
    {
        return &channels[ch_idx];
    }

    return NULL;
}

void Modbus_Init(void)
{
    prvMBPortTimersInit(&timer_freq);

    for (uint8_t i = 0; i < MB_CHANNEL_COUNT; i++)
    {
        ModbusChannel* ch = &channels[i];
        const MBPortChConfig* port_cfg = prvMBPortGetChConfig(i);

        if (!port_cfg)
        {
            while (1);    // 获取配置失败
        }

        ch->usart_periph = port_cfg->usart_periph;
        ch->baud_rate = port_cfg->baud_rate;
        ch->slave_address = port_cfg->slave_addr;
        ch->mode = MODE_SLAVE;
        ch->slave_state = STATE_RX_INIT;
        ch->master_state = STATE_M_IDLE;
        ch->rx_counter = 0;
        ch->master_callback = NULL;

        // 标准modbus-rtu协议规定帧间隔为至少3.5个完整字符帧的时间,当波特率大于19200时,至少为1.75ms
        if (ch->baud_rate > 19200)
        {
            ch->t35_cycles = (uint32_t)(((uint64_t)timer_freq * 1750) / 1000000UL);
        }
        else
        {
            ch->t35_cycles = (uint32_t)(((uint64_t)timer_freq * 11 * 7) / (ch->baud_rate * 2));
        }

        ch->master_timeout_cycles = (uint64_t)timer_freq * MB_MASTER_TIMEOUT_MS / 1000;
        prvMBPortSerialInit(i);
        prvMBPortSerialEnable(i, TRUE, TRUE);
    }
}

void Modbus_SetChannelMode(uint8_t ch_idx, eMBMode mode)
{
    if (ch_idx < MB_CHANNEL_COUNT)
    {
        prvMBPortEnterCritical();
        channels[ch_idx].mode = mode;
        channels[ch_idx].slave_state = STATE_RX_INIT;
        channels[ch_idx].master_state = STATE_M_IDLE;
        prvMBPortExitCritical();
    }
}

void Modbus_Poll(void)
{
    for (uint8_t i = 0; i < MB_CHANNEL_COUNT; i++)
    {
        ModbusChannel* ch = &channels[i];
#if (MB_TIMER_SOURCE == MB_TIMER_IDLE)
        prvMBPortEnterCritical();
        uint8_t is_done = (ch->slave_state == STATE_RX_DONE);
        prvMBPortExitCritical();

        if (is_done)
        {
            if (ch->mode == MODE_SLAVE)
            {
                Modbus_Slave_Parse(ch);
            }
            else // MODE_MASTER
            {
                ch->master_state = STATE_M_DONE;
                Modbus_Master_Parse(ch);
            }

            // 复位状态机,并重新使能接收
            ch->rx_counter = 0;
            ch->slave_state = STATE_RX_INIT;
            ch->master_state = STATE_M_IDLE;
            prvMBPortSerialEnable(i, TRUE, TRUE);
        }
        else if (ch->mode == MODE_MASTER && ch->master_state == STATE_M_WAIT_RX)
        {
            // IDLE模式下仍然需要一个软件定时器来处理主站的响应超时 这里复用之前的DWT/SysTick逻辑
            if ((prvMBPortTimersGetTick() - ch->master_tx_timestamp) > ch->master_timeout_cycles)
            {
                if (ch->master_callback)
                {
                    ch->master_callback(MB_ERR_TIMEOUT, NULL, 0);
                }

                ch->master_state = STATE_M_IDLE;
                prvMBPortSerialEnable(i, TRUE, TRUE);
            }
        }

#else

        if (ch->mode == MODE_SLAVE)
        {
            if (ch->slave_state == STATE_RX_ING)
            {
                prvMBPortEnterCritical();

                if ((prvMBPortTimersGetTick() - ch->last_rx_timestamp) > ch->t35_cycles) // 帧间隔超时,即一帧数据接收完毕
                {
                    ch->slave_state = STATE_RX_DONE;
                    prvMBPortSerialEnable(i, TRUE, FALSE);
                }

                prvMBPortExitCritical();
            }

            if (ch->slave_state == STATE_RX_DONE) // 一帧数据接收完毕后解析并复位状态机,重新使能接收
            {
                Modbus_Slave_Parse(ch);
                ch->rx_counter = 0;
                ch->slave_state = STATE_RX_INIT;
                prvMBPortSerialEnable(i, TRUE, TRUE);
            }
        }
        else     // MODE_MASTER (主站模式未测试)
        {
            if (ch->master_state == STATE_M_WAIT_RX)
            {
                if (ch->slave_state == STATE_RX_ING)
                {
                    prvMBPortEnterCritical();

                    if ((prvMBPortTimersGetTick() - ch->last_rx_timestamp) > ch->t35_cycles)
                    {
                        ch->slave_state = STATE_RX_DONE;
                        prvMBPortSerialEnable(i, TRUE, FALSE);
                    }

                    prvMBPortExitCritical();
                }

                if (ch->slave_state == STATE_RX_DONE)
                {
                    ch->master_state = STATE_M_DONE;
                }
                else if ((prvMBPortTimersGetTick() - ch->master_tx_timestamp) > ch->master_timeout_cycles)
                {
                    if (ch->master_callback)
                    {
                        ch->master_callback(MB_ERR_TIMEOUT, NULL, 0);
                    }

                    ch->master_state = STATE_M_IDLE;
                    prvMBPortSerialEnable(i, TRUE, TRUE);
                }
            }

            if (ch->master_state == STATE_M_DONE)
            {
                Modbus_Master_Parse(ch);
                ch->rx_counter = 0;
                ch->slave_state = STATE_RX_INIT;
                ch->master_state = STATE_M_IDLE;
                prvMBPortSerialEnable(i, TRUE, TRUE);
            }
        }

#endif
    }
}

void Modbus_OnSerialReceive(uint8_t ch_idx, uint8_t data)
{
    if (ch_idx >= MB_CHANNEL_COUNT)
    {
        return;
    }

    ModbusChannel* ch = &channels[ch_idx];
    ch->last_rx_timestamp = prvMBPortTimersGetTick();

    if (ch->slave_state == STATE_RX_INIT)
    {
        ch->rx_counter = 0;
        ch->slave_state = STATE_RX_ING;
    }

    if (ch->rx_counter < MB_BUFFER_SIZE)
    {
        ch->rx_buffer[ch->rx_counter++] = data;
    }
}

void Modbus_OnSerialTransmit(uint8_t ch_idx)
{
    if (ch_idx >= MB_CHANNEL_COUNT)
    {
        return;
    }

    ModbusChannel* ch = &channels[ch_idx];

    if (ch->tx_len_sent >= ch->tx_len_total)
    {
        // 发送完毕,关闭发送中断
        prvMBPortSerialEnable(ch_idx, FALSE, FALSE);
    }
}

void Modbus_OnIdleDetected(uint8_t ch_idx)
{
    if (ch_idx >= MB_CHANNEL_COUNT)
    {
        return;
    }

    ModbusChannel* ch = &channels[ch_idx];

    // 只有在正在接收数据时,IDLE事件才有意义
    if (ch->slave_state == STATE_RX_ING)
    {
        ch->slave_state = STATE_RX_DONE;
        // 立即禁止接收中断,防止在处理期间新数据进来
        prvMBPortSerialEnable(ch_idx, TRUE, FALSE);
    }
}

// 主站主动发起读保持寄存器请求
eMBStatus Modbus_Master_ReadRegisters(
    uint8_t ch_idx, uint8_t target_slave_addr,
    uint16_t reg_addr, uint16_t num_of_regs,
    ModbusMasterCallback callback)
{
    if (ch_idx >= MB_CHANNEL_COUNT)
    {
        return MB_ERR_BUSY;
    }

    ModbusChannel* ch = &channels[ch_idx];
    prvMBPortEnterCritical();

    if (ch->mode != MODE_MASTER || ch->master_state != STATE_M_IDLE)
    {
        prvMBPortExitCritical();
        return MB_ERR_BUSY;
    }

    // 构建请求帧
    ch->tx_buffer[0] = target_slave_addr;
    ch->tx_buffer[1] = 0x03; // 功能码
    ch->tx_buffer[2] = (uint8_t)(reg_addr >> 8);
    ch->tx_buffer[3] = (uint8_t)(reg_addr & 0xFF);
    ch->tx_buffer[4] = (uint8_t)(num_of_regs >> 8);
    ch->tx_buffer[5] = (uint8_t)(num_of_regs & 0xFF);
    ch->tx_len_total = 6;
    // 计算并附加CRC
    uint16_t crc = CRC16(ch->tx_buffer, ch->tx_len_total);
    ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(crc & 0xFF);
    ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(crc >> 8);
    // 准备接收和状态转换
    ch->master_callback = callback;
    ch->slave_state = STATE_RX_INIT;
    ch->rx_counter = 0;
    ch->tx_len_sent = 0;
    ch->master_state = STATE_M_WAIT_RX;
    ch->master_tx_timestamp = prvMBPortTimersGetTick();
    prvMBPortExitCritical();
    // 启动非阻塞发送
    prvMBPortSerialTransmit(ch_idx);
    return MB_OK;
}

// 主站主动发起写保持寄存器请求
eMBStatus Modbus_Master_WriteRegisters(
    uint8_t ch_idx, uint8_t target_slave_addr,
    uint16_t reg_addr, uint16_t num_of_regs, uint16_t *data,
    ModbusMasterCallback callback)
{
    if (ch_idx >= MB_CHANNEL_COUNT)
    {
        return MB_ERR_BUSY;
    }

    ModbusChannel* ch = &channels[ch_idx];
    prvMBPortEnterCritical();

    if (ch->mode != MODE_MASTER || ch->master_state != STATE_M_IDLE)
    {
        prvMBPortExitCritical();
        return MB_ERR_BUSY;
    }

    // 构建请求帧
    ch->tx_buffer[0] = target_slave_addr;

    if (num_of_regs == 1)
    {
        ch->tx_buffer[1] = 0x06; // 功能码
    }
    else
    {
        ch->tx_buffer[1] = 0x10; // 功能码
    }

    ch->tx_buffer[2] = (uint8_t)(reg_addr >> 8);
    ch->tx_buffer[3] = (uint8_t)(reg_addr & 0xFF);
    ch->tx_buffer[4] = (uint8_t)(num_of_regs >> 8);
    ch->tx_buffer[5] = (uint8_t)(num_of_regs & 0xFF);
    ch->tx_len_total = 6;

    if (num_of_regs == 1)
    {
        ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(data[0] & 0xFF);
        ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(data[0] >> 8);
    }
    else
    {
        ch->tx_buffer[ch->tx_len_total++] = (uint8_t)num_of_regs;

        for (uint8_t i = 0; i < num_of_regs; ++i)
        {
            ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(data[i] & 0xFF);
            ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(data[i] >> 8);
        }
    }

    // 计算并附加CRC
    uint16_t crc = CRC16(ch->tx_buffer, ch->tx_len_total);
    ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(crc & 0xFF);
    ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(crc >> 8);
    // 准备接收和状态转换
    ch->master_callback = callback;
    ch->slave_state = STATE_RX_INIT;
    ch->rx_counter = 0;
    ch->tx_len_sent = 0;
    ch->master_state = STATE_M_WAIT_RX;
    ch->master_tx_timestamp = prvMBPortTimersGetTick();
    prvMBPortExitCritical();
    // 启动非阻塞发送
    prvMBPortSerialTransmit(ch_idx);
    return MB_OK;
}

// 解析从站接收到的请求帧
static void Modbus_Slave_Parse(ModbusChannel* ch)
{
    // 基本校验: 长度、地址
    if (ch->rx_counter < 4 || ch->rx_buffer[0] != ch->slave_address)
    {
        return;
    }

    // CRC校验
    uint16_t crc_calc = CRC16(ch->rx_buffer, ch->rx_counter - 2);
    uint16_t crc_recv = (ch->rx_buffer[ch->rx_counter - 1] << 8) | ch->rx_buffer[ch->rx_counter - 2];

    if (crc_calc != crc_recv)
    {
        return;
    }

    ch->tx_len_total = 0;

    switch (ch->rx_buffer[1])
    {
        case 0x03:   // 读寄存器
            {
                // 检查请求帧长度是否正确
                if (ch->rx_counter != 8)
                {
                    break;
                }

                uint16_t start_addr = (ch->rx_buffer[2] << 8) | ch->rx_buffer[3];
                uint16_t num_of_regs = (ch->rx_buffer[4] << 8) | ch->rx_buffer[5];

                // 数据校验: 数量在1-125之间
                if (num_of_regs >= 1 && num_of_regs <= 125)
                {
                    // 构建正常响应
                    ch->tx_buffer[0] = ch->slave_address;
                    ch->tx_buffer[1] = 0x03;
                    ch->tx_buffer[2] = num_of_regs * 2; // 字节数
                    uint8_t flag_break = 0;

                    for (uint16_t i = 0; i < num_of_regs; i++)
                    {
                        const uint16_t *p_value = prvMBPortGetReg(start_addr + i, MB_RO);

                        if (!p_value) // 寄存器地址非法
                        {
                            // 构建异常响应 (0x02: Illegal Data Address)
                            ch->tx_buffer[0] = ch->slave_address;
                            ch->tx_buffer[1] = ch->rx_buffer[1] | 0x80;
                            ch->tx_buffer[2] = 0x02;
                            ch->tx_len_total = 3;
                            flag_break = 1;
                            break;
                        }

                        ch->tx_buffer[3 + i * 2] = (uint8_t)(*p_value >> 8);
                        ch->tx_buffer[4 + i * 2] = (uint8_t)(*p_value & 0xFF);
                    }

                    if (flag_break)
                    {
                        break;
                    }

                    ch->tx_len_total = 3 + num_of_regs * 2;
                }
                else
                {
                    // 构建异常响应 (0x02: Illegal Data Address)
                    ch->tx_buffer[0] = ch->slave_address;
                    ch->tx_buffer[1] = ch->rx_buffer[1] | 0x80;
                    ch->tx_buffer[2] = 0x02;
                    ch->tx_len_total = 3;
                }

                break;
            }

        case 0x06:   // 写单个寄存器
            {
                // 检查请求帧长度是否正确
                if (ch->rx_counter != 8)
                {
                    break;
                }

                uint16_t start_addr = (ch->rx_buffer[2] << 8) | ch->rx_buffer[3];
                uint16_t write_value = (ch->rx_buffer[4] << 8) | ch->rx_buffer[5];
                // 构建正常响应
                ch->tx_buffer[0] = ch->slave_address;
                ch->tx_buffer[1] = 0x06;
                ch->tx_buffer[2] = ch->rx_buffer[2];
                ch->tx_buffer[3] = ch->rx_buffer[3];
                ch->tx_buffer[4] = ch->rx_buffer[4];
                ch->tx_buffer[5] = ch->rx_buffer[5];
                uint16_t *p_value = prvMBPortGetReg(start_addr, MB_RW);

                if (!p_value) // 寄存器地址非法
                {
                    // 构建异常响应 (0x02: Illegal Data Address)
                    ch->tx_buffer[0] = ch->slave_address;
                    ch->tx_buffer[1] = ch->rx_buffer[1] | 0x80;
                    ch->tx_buffer[2] = 0x02;
                    ch->tx_len_total = 3;
                    break;
                }

                *p_value = write_value;
                ch->tx_len_total = 6;
                break;
            }

        case 0x10:   // 写多个寄存器
            {
                // 检查请求帧长度是否正确
                if (ch->rx_counter < 11)
                {
                    break;
                }

                uint16_t start_addr = (ch->rx_buffer[2] << 8) | ch->rx_buffer[3];
                uint16_t num_of_regs = (ch->rx_buffer[4] << 8) | ch->rx_buffer[5];
                uint8_t num_of_bytes = ch->rx_buffer[6];

                if (num_of_bytes != 2 * num_of_regs)
                {
                    // 构建异常响应 (0x02: Illegal Data Address)
                    ch->tx_buffer[0] = ch->slave_address;
                    ch->tx_buffer[1] = ch->rx_buffer[1] | 0x80;
                    ch->tx_buffer[2] = 0x02;
                    ch->tx_len_total = 3;
                    break;
                }

                // 数据校验: 数量在1-125之间
                if (num_of_regs >= 1 && num_of_regs <= 125)
                {
                    // 构建正常响应
                    ch->tx_buffer[0] = ch->slave_address;
                    ch->tx_buffer[1] = 0x06;
                    ch->tx_buffer[2] = ch->rx_buffer[2];
                    ch->tx_buffer[3] = ch->rx_buffer[3];
                    ch->tx_buffer[4] = ch->rx_buffer[4];
                    ch->tx_buffer[5] = ch->rx_buffer[5];
                    uint8_t flag_break = 0;

                    for (uint16_t i = 0; i < num_of_regs; i++)
                    {
                        uint16_t *p_value = prvMBPortGetReg(start_addr + i, MB_RW);

                        if (!p_value) // 寄存器地址非法
                        {
                            // 构建异常响应 (0x02: Illegal Data Address)
                            ch->tx_buffer[0] = ch->slave_address;
                            ch->tx_buffer[1] = ch->rx_buffer[1] | 0x80;
                            ch->tx_buffer[2] = 0x02;
                            ch->tx_len_total = 3;
                            flag_break = 1;
                            break;
                        }

                        *p_value = (ch->rx_buffer[7 + i * 2] << 8) | ch->rx_buffer[8 + i * 2];
                    }

                    if (flag_break)
                    {
                        break;
                    }

                    ch->tx_len_total = 6;
                }
                else
                {
                    // 构建异常响应 (0x02: Illegal Data Address)
                    ch->tx_buffer[0] = ch->slave_address;
                    ch->tx_buffer[1] = ch->rx_buffer[1] | 0x80;
                    ch->tx_buffer[2] = 0x02;
                    ch->tx_len_total = 3;
                }

                break;
            }

        default:
            {
                // 非法功能码或操作,构建异常响应 (0x01: Illegal Function)
                ch->tx_buffer[0] = ch->slave_address;
                ch->tx_buffer[1] = ch->rx_buffer[1] | 0x80;
                ch->tx_buffer[2] = 0x01;
                ch->tx_len_total = 3;
                break;
            }
    }

    // 如果有响应数据,则计算CRC并非阻塞发送
    if (ch->tx_len_total > 0)
    {
        uint16_t crc_send = CRC16(ch->tx_buffer, ch->tx_len_total);
        ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(crc_send & 0xFF);
        ch->tx_buffer[ch->tx_len_total++] = (uint8_t)(crc_send >> 8);
        ch->tx_len_sent = 0;
        uint8_t ch_idx = ch - &channels[0];
        prvMBPortSerialTransmit(ch_idx);
    }
}

static void Modbus_Master_Parse(ModbusChannel* ch)
{
    if (ch->master_callback == NULL)
    {
        return;
    }

    uint16_t crc_calc = CRC16(ch->rx_buffer, ch->rx_counter - 2);
    uint16_t crc_recv = (ch->rx_buffer[ch->rx_counter - 1] << 8) | ch->rx_buffer[ch->rx_counter - 2];

    if (crc_calc != crc_recv)
    {
        if (ch->master_callback)
        {
            ch->master_callback(MB_ERR_INVALID_RESPONSE, (uint8_t*)ch->rx_buffer, ch->rx_counter);
        }
    }
    else
    {
        if (ch->master_callback)
        {
            ch->master_callback(MB_SUCCESS, (uint8_t*)ch->rx_buffer, ch->rx_counter);
        }
    }
}

static uint16_t CRC16(const volatile uint8_t *pucFrame, uint16_t usLen)
{
    uint16_t uiCRC16 = 0xFFFF;

    while (usLen--)
    {
        uiCRC16 ^= *pucFrame++;

        for (uint8_t j = 0; j < 8; ++j)
        {
            if (uiCRC16 & 0x01)
            {
                uiCRC16 = (uiCRC16 >> 1) ^ 0xA001;
            }
            else
            {
                uiCRC16 = uiCRC16 >> 1;
            }
        }
    }

    return uiCRC16;
}

移植层:

#ifndef __MODBUS_PORT_H__
#define __MODBUS_PORT_H__

#include "gd32f30x.h"
#include <stdlib.h>

// 通道硬件配置结构体
typedef struct
{
    uint32_t usart_periph; // 特定于MCU的串口外设ID/地址
    uint32_t baud_rate;    // 波特率
    uint8_t  slave_addr;   // 作为从站时的地址
} MBPortChConfig;

// 从机寄存器地址
typedef enum
{
    // 写
    P2000 = 0x2000,
    P2001,
    P2002,
    // 写
    P2100 = 0x2100,
    P2101,
    P2102,
    P2103,
    P2104,
    // 读
    P2200 = 0x2200,
    P2201,
    P2202,
    P2203,
    P2204,
    P2205,
    P2206,
    P2207,
    P2208,
    P2209,
    P220A,
    P220B,
    P220C,
    P220D,
} MBSlaveRegAddr;

// 寄存器读写权限
typedef enum
{
    MB_RO = 0,
    MB_RW
} MBSlaveRegRW;

// 从机寄存器结构体
typedef struct
{
    uint16_t address;
    MBSlaveRegRW rw;
    uint16_t *value;
} MBSlaveReg;

// 移植层需要实现的硬件接口
uint16_t *prvMBPortGetReg(uint16_t reg_addr, MBSlaveRegRW reg_rw);
// 获取指定通道的硬件配置
const MBPortChConfig *prvMBPortGetChConfig(uint8_t ch_idx);
// 定时器配置
bool prvMBPortTimersInit(uint32_t *p_timer_freq);
// 获取定时器计数值
uint32_t prvMBPortTimersGetTick(void);
// 串口初始化
bool prvMBPortSerialInit(uint8_t ch_idx);
// 串口使能
void prvMBPortSerialEnable(uint8_t ch_idx, bool is_rx, bool is_enable);
// 串口传输
void prvMBPortSerialTransmit(uint8_t ch_idx);
// 进入临界区
void prvMBPortEnterCritical(void);
// 退出临界区
void prvMBPortExitCritical(void);

#endif
#include "modbus_port.h"
#include "modbus_config.h"
#include "modbus_core.h"

uint16_t p2000 = P2000;
uint16_t p2001 = P2001;
uint16_t p2002 = P2002;

uint16_t p2100 = P2100;
uint16_t p2101 = P2101;
uint16_t p2102 = P2102;
uint16_t p2103 = P2103;
uint16_t p2104 = P2104;

uint16_t p2200 = P2200;
uint16_t p2201 = P2201;
uint16_t p2202 = P2202;
uint16_t p2203 = P2203;
uint16_t p2204 = P2204;
uint16_t p2205 = P2205;
uint16_t p2206 = P2206;
uint16_t p2207 = P2207;
uint16_t p2208 = P2208;
uint16_t p2209 = P2209;
uint16_t p220A = P220A;
uint16_t p220B = P220B;
uint16_t p220C = P220C;
uint16_t p220D = P220D;

// 寄存器数组
static const MBSlaveReg slave_registers[] =
{
    // 写
    {P2000, MB_RW, &p2000},
    {P2001, MB_RW, &p2001},
    {P2002, MB_RW, &p2002},
    // 写
    {P2100, MB_RW, &p2100},
    {P2101, MB_RW, &p2101},
    {P2102, MB_RW, &p2102},
    {P2103, MB_RW, &p2103},
    {P2104, MB_RW, &p2104},
    // 读
    {P2200, MB_RO, &p2200},
    {P2201, MB_RO, &p2201},
    {P2202, MB_RO, &p2202},
    {P2203, MB_RO, &p2203},
    {P2204, MB_RO, &p2204},
    {P2205, MB_RO, &p2205},
    {P2206, MB_RO, &p2206},
    {P2207, MB_RO, &p2207},
    {P2208, MB_RO, &p2208},
    {P2209, MB_RO, &p2209},
    {P220A, MB_RO, &p220A},
    {P220B, MB_RO, &p220B},
    {P220C, MB_RO, &p220C},
    {P220D, MB_RO, &p220D},
    {NULL, MB_RO, NULL},
};

// 硬件配置数组
static const MBPortChConfig port_ch_configs[MB_CHANNEL_COUNT] =
{
    // 通道 0 的配置
    {
        .usart_periph = MB_CHANNEL_0_USART_PERIPH,
        .baud_rate    = MB_CHANNEL_0_BAUD,
        .slave_addr   = MB_CHANNEL_0_ADDR
    }
};

uint16_t *prvMBPortGetReg(uint16_t reg_addr, MBSlaveRegRW reg_rw)
{
    for (int i = 0;; ++i)
    {
        if (!slave_registers[i].address || (reg_rw == MB_RW && slave_registers[i].rw == MB_RO))
        {
            break;
        }

        if (slave_registers[i].address == reg_addr)
        {
            return slave_registers[i].value;
        }
    }

    return NULL;
}

const MBPortChConfig *prvMBPortGetChConfig(uint8_t ch_idx)
{
    if (ch_idx < MB_CHANNEL_COUNT)
    {
        return &port_ch_configs[ch_idx];
    }

    return NULL;
}

bool prvMBPortTimersInit(uint32_t *p_timer_freq)
{
#if (MB_TIMER_SOURCE == MB_TIMER_IDLE)
    // 在IDLE模式下,仍然需要一个时间源来处理主站超时,这里使用DWT
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT = 0;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    *p_timer_freq = rcu_clock_freq_get(CK_SYS);
    return TRUE;
#elif (MB_TIMER_SOURCE == MB_TIMER_DWT)
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CYCCNT = 0;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    *p_timer_freq = rcu_clock_freq_get(CK_SYS);
    return TRUE;
#else
    // @TODO: 实现其他定时器源 (TIM, SysTick) 初始化
#error "Selected timer source is not implemented in this port."
    return FALSE;
#endif
}

uint32_t prvMBPortTimersGetTick(void)
{
#if (MB_TIMER_SOURCE == MB_TIMER_IDLE)
    // 返回备用时间源(DWT)的计数值
    return DWT->CYCCNT;
#elif (MB_TIMER_SOURCE == MB_TIMER_DWT)
    return DWT->CYCCNT;
#else
    // @TODO: 实现其他定时器源返回计数值
    return 0;
#endif
}

bool prvMBPortSerialInit(uint8_t ch_idx)
{
    const MBPortChConfig* port_cfg = prvMBPortGetChConfig(ch_idx);

    if (!port_cfg)
    {
        return FALSE;
    }

    rcu_periph_enum rcu_gpio, rcu_usart;
    uint32_t tx_port, tx_pin, rx_port, rx_pin;
    uint8_t nvic_irqn;

    switch (port_cfg->usart_periph)
    {
        case UART3:
            rcu_gpio = RCU_GPIOC;
            rcu_usart = RCU_UART3;
            tx_port = GPIOC;
            tx_pin = GPIO_PIN_10;
            rx_port = GPIOC;
            rx_pin = GPIO_PIN_11;
            nvic_irqn = UART3_IRQn;
            break;

        default:
            return FALSE;
    }

    rcu_periph_clock_enable(rcu_gpio);
    rcu_periph_clock_enable(rcu_usart);
    gpio_init(tx_port, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, tx_pin);
    gpio_init(rx_port, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, rx_pin);
    usart_deinit(port_cfg->usart_periph);
    usart_baudrate_set(port_cfg->usart_periph, port_cfg->baud_rate);
    usart_word_length_set(port_cfg->usart_periph, USART_WL_8BIT);
    usart_stop_bit_set(port_cfg->usart_periph, USART_STB_1BIT);
    usart_parity_config(port_cfg->usart_periph, USART_PM_NONE);
    usart_hardware_flow_rts_config(port_cfg->usart_periph, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(port_cfg->usart_periph, USART_CTS_DISABLE);
    usart_receive_config(port_cfg->usart_periph, USART_RECEIVE_ENABLE);
    usart_transmit_config(port_cfg->usart_periph, USART_TRANSMIT_ENABLE);
    usart_enable(port_cfg->usart_periph);
    nvic_irq_enable(nvic_irqn, 0, 0);
#if (MB_TIMER_SOURCE == MB_TIMER_IDLE)
    usart_data_receive(port_cfg->usart_periph);
    usart_interrupt_flag_clear(port_cfg->usart_periph, USART_INT_FLAG_IDLE);
    usart_interrupt_enable(port_cfg->usart_periph, USART_INT_IDLE);
#endif
    return TRUE;
}

void prvMBPortSerialEnable(uint8_t ch_idx, bool is_rx, bool is_enable)
{
    const MBPortChConfig* port_cfg = prvMBPortGetChConfig(ch_idx);

    if (!port_cfg)
    {
        return;
    }

    if (is_rx)
    {
        if (is_enable)
        {
            usart_interrupt_enable(port_cfg->usart_periph, USART_INT_RBNE);
        }
        else
        {
            usart_interrupt_disable(port_cfg->usart_periph, USART_INT_RBNE);
        }
    }
    else
    {
        if (is_enable)
        {
            usart_interrupt_enable(port_cfg->usart_periph, USART_INT_TBE);
        }
        else
        {
            usart_interrupt_disable(port_cfg->usart_periph, USART_INT_TBE);
        }
    }
}

void prvMBPortSerialTransmit(uint8_t ch_idx)
{
    ModbusChannel* ch = Modbus_GetChannel(ch_idx);

    if (!ch || ch->tx_len_total == 0)
    {
        return;
    }

    // 发送第一个字节,并使能发送中断让ISR接管
    usart_data_transmit(ch->usart_periph, ch->tx_buffer[0]);
    ch->tx_len_sent = 1;
    prvMBPortSerialEnable(ch_idx, FALSE, TRUE); // 使能TBE中断
}

void prvMBPortEnterCritical(void)
{
    __disable_irq();
}

void prvMBPortExitCritical(void)
{
    __enable_irq();
}

static void prvMBUsartIrqHandler(uint8_t ch_idx)
{
    ModbusChannel* ch = Modbus_GetChannel(ch_idx);

    if (!ch)
    {
        return;
    }

    uint32_t usart_periph = ch->usart_periph;

    if (RESET != usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_RBNE))
    {
        Modbus_OnSerialReceive(ch_idx, (uint8_t)usart_data_receive(usart_periph));
    }

#if (MB_TIMER_SOURCE == MB_TIMER_IDLE)

    if (RESET != usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_IDLE))
    {
        usart_data_receive(usart_periph);
        Modbus_OnIdleDetected(ch_idx);
    }

#endif

    if (RESET != usart_interrupt_flag_get(usart_periph, USART_INT_FLAG_TBE))
    {
        if (ch->tx_len_sent < ch->tx_len_total)
        {
            usart_data_transmit(usart_periph, ch->tx_buffer[ch->tx_len_sent++]);
        }
        else
        {
            Modbus_OnSerialTransmit(ch_idx); // 通知核心层发送完毕
        }
    }
}

void UART3_IRQHandler(void)
{
    prvMBUsartIrqHandler(0);
}

文章作者: Liccsu
本文链接:
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Liccsu's blog
喜欢就支持一下吧
打赏
微信 微信