STM32F103开发板上移植Agile Modbus库的详细指南

STM32F103开发板上移植Agile Modbus库的详细指南

在嵌入式开发中,Modbus协议是工业自动化和物联网应用中常用的通信协议之一。Agile Modbus是一个轻量级、纯C语言编写的Modbus库,支持Modbus RTU和Modbus TCP协议,且完全脱离硬件,非常适合在各种平台上移植。本文将详细介绍如何在STM32F103开发板上移植Agile Modbus库,实现Modbus RTU通信。

一、Agile Modbus简介

Agile Modbus是一个开源的Modbus库,其核心代码完全用C语言编写,不依赖于任何特定硬件平台,因此可以轻松移植到任何支持C语言的微控制器上。它支持Modbus RTU和Modbus TCP两种通信模式,本文主要介绍Modbus RTU的移植。

GitHub源码地址:[Agile Modbus GitHub]

二、准备工作

(一)硬件准备

• STM32F103开发板:确保开发板正常工作,所有引脚连接良好。

• RS485模块:用于实现Modbus RTU通信,连接到STM32F103的UART接口。

• ModbusPoll和ModbusSlaver:分别用于调试和测试Modbus从机和主机通信。

(二)软件准备

• STM32CubeMX:用于生成初始化代码。

• STM32CubeIDE:用于编写和编译代码。

• Agile Modbus源码:从GitHub下载Agile Modbus库的源码。

三、移植步骤

(一)添加Agile Modbus源码到项目中

• 下载Agile Modbus源码:从GitHub下载Agile Modbus库的源码,解压后找到agile_modbus/incagile_modbus/srcagile_modbus/util三个文件夹。

• 导入源码到项目:在STM32CubeIDE中创建一个新的STM32项目,将上述三个文件夹中的所有文件添加到项目中。

(二)初始化Modbus RTU句柄

在STM32F103开发板上,我们需要初始化Modbus RTU句柄,配置发送和接收缓冲区,并设置从机地址。

c 复制代码
#include "agile_modbus.h"

static uint8_t mb_send_buf[256]; // 发送缓冲区
static uint8_t mb_recv_buf[256]; // 接收缓冲区
agile_modbus_rtu_t mb_rtu = {0}; // Modbus RTU句柄

void Modbus_Init(void)
{
    // 初始化Modbus RTU句柄
    agile_modbus_rtu_init(&mb_rtu, mb_send_buf, sizeof(mb_send_buf), mb_recv_buf, sizeof(mb_recv_buf));
    // 设置从机地址(根据实际情况修改)
    agile_modbus_set_slave(&mb_rtu._ctx, 0x01);
}

(三)配置UART接口

在STM32CubeMX中配置UART接口,用于与RS485模块通信。以下是关键配置步骤:

• 选择UART接口:例如选择USART1。

• 配置波特率:根据Modbus协议的要求,通常设置为9600。

• 配置数据位、停止位和校验位:设置为8位数据位、1位停止位、无校验位。

• 启用DMA接收:为了提高通信效率,建议启用DMA接收功能。

生成代码后,确保在MX_USART1_UART_Init()函数中正确配置了UART参数。

(四)实现发送和接收函数

Agile Modbus库需要用户提供发送和接收函数。以下是基于STM32 HAL库的实现:

c 复制代码
#include "usart.h"

// 发送函数
int MB_Transmit(uint8_t *buf, int len)
{
    HAL_UART_Transmit(&huart1, buf, len, HAL_MAX_DELAY);
    return len;
}

// 接收函数
int MB_Receive(uint8_t *buf, int len)
{
    int recv_len = HAL_UART_Receive(&huart1, buf, len, HAL_MAX_DELAY);
    return recv_len;
}

(五)实现Modbus主站功能

以下是一个简单的Modbus主站任务,用于读取从机的输入寄存器。

c 复制代码
#include "agile_modbus.h"
#include "usart.h"

void Modbus_Master_Task(void)
{
    int send_len = 0, recv_len = 0;
    uint16_t reg_data[10] = {0}; // 存储读取的寄存器数据

    while (1)
    {
        // 清空接收缓冲区
        memset(mb_recv_buf, 0, sizeof(mb_recv_buf));

        // 组包并发送读取输入寄存器请求
        send_len = agile_modbus_serialize_read_input_registers(&mb_rtu._ctx, 0x00, 5);
        if (send_len > 0)
        {
            MB_Transmit(mb_send_buf, send_len); // 发送请求
        }

        // 接收从机响应
        recv_len = MB_Receive(mb_recv_buf, sizeof(mb_recv_buf));
        if (recv_len > 0)
        {
            // 解包响应数据
            int data_count = agile_modbus_deserialize_read_input_registers(&mb_rtu._ctx, recv_len, reg_data);
            if (data_count > 0)
            {
                // 打印读取的寄存器数据
                for (int i = 0; i < data_count; i++)
                {
                    printf("Reg[%d] = %d\r\n", i, reg_data[i]);
                }
            }
        }

        HAL_Delay(1000); // 延时1秒
    }
}

(六)实现Modbus从机功能

以下是一个简单的Modbus从机任务,用于响应主站的读取请求。

c 复制代码
#include "agile_modbus.h"
#include "usart.h"

// 输入寄存器映射
typedef struct
{
    uint16_t reg0;
    uint16_t reg1;
    uint16_t reg2;
    uint16_t reg3;
    uint16_t reg4;
} InputRegs;

static InputRegs input_regs = {1, 2, 3, 4, 5};

// 获取输入寄存器数据
static int Get_Input_Regs(void *buf, int bufsz)
{
    memcpy(buf, &input_regs, sizeof(input_regs));
    return 0;
}

// 输入寄存器映射表
agile_modbus_slave_util_map_t input_map =
{
    0x00,
    sizeof(input_regs),
    Get_Input_Regs,
    NULL
};

// 从机工具结构体
const agile_modbus_slave_util_t slave_util =
{
    NULL,
    0x00,
    NULL,
    0x00,
    NULL,
    0x00,
    &input_map,
    sizeof(input_regs)
};

void Modbus_Slave_Task(void)
{
    int recv_len = 0, send_len = 0;

    while (1)
    {
        // 接收主站请求
        recv_len = MB_Receive(mb_recv_buf, sizeof(mb_recv_buf));
        if (recv_len > 0)
        {
            // 处理请求并生成响应
            send_len = agile_modbus_slave_handle(&mb_rtu._ctx, recv_len, 1, agile_modbus_slave_util_callback, &slave_util, NULL);
            if (send_len > 0)
            {
                // 发送响应
                MB_Transmit(mb_send_buf, send_len);
            }
        }
    }
}

四、测试与验证

• 硬件连接:将RS485模块连接到STM32F103的USART1接口,并确保RS485模块的DE(数据使能)引脚正确控制发送/接收模式。

• 编译与烧录:将上述代码编译并烧录到STM32F103开发板上。

• 启动ModbusSlaver:设置波特率为9600,观察Modbus主机通信的发送和接收数据。

• 测试主站功能:运行主站任务,观察是否能正确读取从机的输入寄存器数据。

• 启动ModbusPoll:设置波特率为9600,观察Modbus从机通信的发送和接收数据。

• 测试从机功能:运行从机任务,观察是否能正确响应主站的读取请求。

五、总结

通过上述步骤,我们成功在STM32F103开发板上移植了Agile Modbus库,实现了Modbus RTU主站和从机的功能。Agile Modbus库的轻量级特性和良好的移植性使其非常适合在STM32等嵌入式平台上使用。希望本文能为你的Modbus项目提供帮助!

相关推荐
沐欣工作室_lvyiyi1 小时前
基于单片机的用电器功率监测报警系统设计(论文+源码)
单片机·嵌入式硬件·功率监测
贝塔实验室1 小时前
Altium Designer原理图编辑基础
单片机·嵌入式硬件·硬件工程·信息与通信·射频工程·基带工程·嵌入式实时数据库
hazy1k1 小时前
MSPM0L1306 从零到入门:第二章 GPIO 从入门到精通 —— 点亮你的第一颗LED
stm32·单片机·嵌入式硬件·esp32·ti·mspm0
Qoitech 中国1 小时前
Otii 应用场景系列:使用 Otii Arc和Otii Ace进行差分测量
嵌入式硬件·物联网·自动化·集成测试·智能硬件
d111111111d1 小时前
STM32外设学习--PWR电源控制
笔记·stm32·单片机·嵌入式硬件·学习
小柯博客3 小时前
从零开始打造 OpenSTLinux 6.6 Yocto 系统 - STM32MP2(基于STM32CubeMX)(三)
stm32·嵌入式硬件·开源·嵌入式·yocto·st·stm32mp2
就是蠢啊3 小时前
51单片机——I2C-EEPROM 实验(一)
单片机·嵌入式硬件·51单片机
阿容1234563 小时前
stm32两轮平衡车-01
stm32·单片机·嵌入式硬件
up向上up3 小时前
基于STM32单片机智能红外遥控跟随小车设计
stm32·单片机·嵌入式硬件