Modbus 多传感器组网:STM32H5 主控访问多 F030 从机传感器(485 总线)
目录
- 一、前言
- 二、组网架构:H5 主控 + 多 F030 从机传感器
- 三、H5 主控程序设计:多任务 + Modbus 主站
- 四、LCD 互斥保护:避免多任务绘图花屏
- 五、功能验证:多传感器数据采集与显示
- 六、总结
- 七、结尾
一、前言
在完成开关量、环境监测、温湿度三类 F030 传感器的 Modbus 从机程序开发后,本次实现多传感器组网通信:将三类 F030 传感器的 485 接口接入 485 HUB,STM32H5 主控通过 485 HUB 与各传感器通信,作为 Modbus 主站读取三类传感器的核心数据(按键状态、光强、温湿度等),并在 LCD 屏幕上集中显示,同时实现对传感器 LED 的远程控制。
二、组网架构:H5 主控 + 多 F030 从机传感器
-
硬件连接:F030 开关量传感器、环境监测传感器、温湿度传感器的 485 接口均接入 485 HUB;H5 主控的 485 接口与 HUB 相连,分为 CH1、CH2 两个通信通道。
-
任务规划:
- 任务 1(CH1):访问开关量传感器(地址 01H)、环境监测传感器(地址 02H),读取按键状态、ADC 值(光强 / 可调电阻)并控制 LED 闪烁,数据显示在 LCD;
- 任务 2(CH2):访问温湿度传感器(地址 03H),读取温湿度数据并控制 LED 闪烁,数据显示在 LCD。
-
关键注意:两个任务均操作 LCD,需添加互斥保护机制,避免多任务同时绘图导致 LCD 花屏。
三、H5 主控程序设计:多任务 + Modbus 主站
1. 任务创建
基于 FreeRTOS 创建两个 Modbus 客户端任务,分别对应 CH1、CH2 通信通道:
// 创建CH1客户端任务:访问开关量、环境监测传感器
xTaskCreate(
LibmodbusCH1ClientTask,
"LibmodbusCH1ClientTask",
200, // 任务栈大小
NULL,
osPriorityNormal, // 任务优先级
NULL);
// 创建CH2客户端任务:访问温湿度传感器
xTaskCreate(
LibmodbusCH2ClientTask,
"LibmodbusCH2ClientTask",
200,
NULL,
osPriorityNormal,
NULL);
2. 基础 Modbus 客户端函数(参考模板)
以下是基于 FreeRTOS 和 libmodbus 实现的基础 Modbus 主站任务函数,核心逻辑为读取从站寄存器、LCD 显示、改写寄存器值,作为后续修改的模板:
// 基础Modbus RTU客户端(主站)任务函数
// 功能:读取从站保持寄存器1的值→LCD显示→自增后写回保持寄存器2
static void LibmodbusClientTask( void *pvParameters )
{
// Modbus RTU上下文
modbus_t *ctx;
// 函数返回值,判断操作是否成功
int rc;
// 存储寄存器读取值
uint16_t val;
// 读取/写入的寄存器数量
int nb = 1;
// 创建USB虚拟串口的Modbus RTU上下文:波特率115200、无校验、8数据位、1停止位
ctx = modbus_new_st_rtu("usb", 115200, 'N', 8, 1);
// 设置从机地址为1
modbus_set_slave(ctx, 1);
// 建立Modbus RTU连接
rc = modbus_connect(ctx);
if (rc == -1) {
//fprintf(stderr, "Unable to connect %s\n", modbus_strerror(errno));
modbus_free(ctx);
vTaskDelete(NULL);; // 连接失败则删除任务
}
// 无限循环:读取→显示→改写寄存器
for (;;) {
/* 读取保持寄存器1的值 */
rc = modbus_read_registers(ctx, 1, nb, &val);
if (rc != nb) // 读取失败则跳过本次循环
continue;
/* 在LCD上显示数值(坐标0,0,红色) */
Draw_Number(0, 0, val, 0xff0000);
/* 数值自增 */
val++;
/* 将自增后的值写入保持寄存器2 */
rc = modbus_write_registers(ctx, 2, nb, &val);
}
/* 释放资源(实际循环不会执行到此处) */
modbus_close(ctx);
modbus_free(ctx);
vTaskDelete(NULL);
}
3. CH1 客户端任务(开关量 + 环境监测传感器)
基于基础模板修改,实现 CH1 通道对两台传感器的访问,读取按键状态、ADC 值并控制 LED 闪烁:
// CH1客户端任务:访问开关量传感器(01H)、环境监测传感器(02H)
static void LibmodbusCH1ClientTask( void *pvParameters )
{
// Modbus RTU上下文
modbus_t *ctx;
// 函数返回值
int rc;
// 存储ADC/温湿度等值(16位寄存器)
uint16_t vals[10];
// 寄存器读取数量
int nb = 1;
// 存储开关量/线圈状态(8位)
uint8_t bits[10];
// LCD显示字符串缓冲区
uint8_t buf[100];
// LED状态(1-亮,0-灭),用于闪烁控制
int led_status = 1;
// 创建串口2的Modbus RTU上下文:对应CH1 485通道
ctx = modbus_new_st_rtu("uart2", 115200, 'N', 8, 1);
// 第一步:访问开关量传感器(从机地址01H)
modbus_set_slave(ctx, 1);
// 建立Modbus连接
rc = modbus_connect(ctx);
if (rc == -1) {
//fprintf(stderr, "Unable to connect %s\n", modbus_strerror(errno));
modbus_free(ctx);
vTaskDelete(NULL);;
}
// 无限循环:采集数据+控制LED
for (;;) {
/* 1. 读取开关量传感器(01H):KEY1/KEY2/KEY3状态(DI寄存器0-2) */
modbus_set_slave(ctx, 1);
rc = modbus_read_input_bits(ctx, 0, 3, bits); // 读取3个离散输入位
if (rc == 3) // 读取成功则显示
{
// 拼接按键状态字符串,显示在LCD第0行
sprintf(buf, "SWITCH keys: %d %d %d", bits[0], bits[1], bits[2]);
Draw_String(0, 0, buf, 0xff0000, 0);
}
// 控制开关量传感器LED1闪烁(改写DO寄存器2)
rc = modbus_write_bit(ctx, 2, led_status);
/* 2. 读取环境监测传感器(02H):两路ADC值(AI寄存器0-1) */
modbus_set_slave(ctx, 2);
rc = modbus_read_input_registers(ctx, 0, 2, vals); // 读取2个输入寄存器
if (rc == 2) // 读取成功则显示
{
// 拼接ADC值字符串,显示在LCD第1行(16像素偏移)
sprintf(buf, "ENV Sensor : opti 0x%x, res 0x%x ", vals[0], vals[1]);
Draw_String(0, 16, buf, 0xff0000, 0);
}
// 控制环境监测传感器LED1闪烁(改写DO寄存器2)
rc = modbus_write_bit(ctx, 2, led_status);
// 翻转LED状态,实现500ms闪烁
led_status = !led_status;
// 延时500ms,控制采集/刷新频率
vTaskDelay(500);
}
/* 释放资源(实际循环不会执行到此处) */
modbus_close(ctx);
modbus_free(ctx);
vTaskDelete(NULL);
}
4. CH2 客户端任务(温湿度传感器)
采用与 CH1 一致的流程,实现 CH2 通道对温湿度传感器的访问,读取温湿度数据并控制 LED 闪烁:
// CH2客户端任务:访问温湿度传感器(03H)
static void LibmodbusCH2ClientTask( void *pvParameters )
{
// Modbus RTU上下文
modbus_t *ctx;
// 函数返回值
int rc;
// 存储温湿度值(16位寄存器)
uint16_t vals[10];
// 寄存器读取数量
int nb = 1;
// 存储线圈状态(备用)
uint8_t bits[10];
// LCD显示字符串缓冲区
uint8_t buf[100];
// LED状态,用于闪烁控制
int led_status = 1;
// 创建串口4的Modbus RTU上下文:对应CH2 485通道
ctx = modbus_new_st_rtu("uart4", 115200, 'N', 8, 1);
// 设置从机地址为3(温湿度传感器)
modbus_set_slave(ctx, 3);
// 建立Modbus连接
rc = modbus_connect(ctx);
if (rc == -1) {
//fprintf(stderr, "Unable to connect %s\n", modbus_strerror(errno));
modbus_free(ctx);
vTaskDelete(NULL);;
}
// 无限循环:采集温湿度+控制LED
for (;;) {
/* 读取温湿度传感器(03H):温度、湿度值(AI寄存器0-1) */
rc = modbus_read_input_registers(ctx, 0, 2, vals);
if (rc == 2) // 读取成功则显示
{
// 拼接温湿度字符串(单位0.1℃/0.1%RH),显示在LCD第2行(32像素偏移)
sprintf(buf, "TEM/HUM Sensor : temp %d.%d, humi %d.%d ", vals[0]/10, vals[0]%10, vals[1]/10, vals[1]%10);
Draw_String(0, 32, buf, 0xff0000, 0);
}
// 控制温湿度传感器LED1闪烁(改写DO寄存器2)
rc = modbus_write_bit(ctx, 2, led_status);
// 翻转LED状态
led_status = !led_status;
// 延时500ms
vTaskDelay(500);
}
/* 释放资源(实际循环不会执行到此处) */
modbus_close(ctx);
modbus_free(ctx);
vTaskDelete(NULL);
}
四、LCD 互斥保护:避免多任务绘图花屏
由于两个任务同时操作 LCD,需在 LCD 驱动文件(draw.c)中添加互斥量保护,确保同一时间只有一个任务执行绘图操作:
1. 创建互斥量
在 LCD 初始化函数中创建互斥量:
// 定义LCD绘图互斥量(静态全局变量,仅draw.c可见)
static SemaphoreHandle_t g_spi_lcd_lock;
// LCD初始化函数
void Draw_Init(void)
{
/* 创建互斥量:保护LCD绘图操作,避免多任务冲突 */
g_spi_lcd_lock = xSemaphoreCreateMutex();
// 获取LCD分辨率信息(原有逻辑)
LCD_GetInfo(&g_lcd_width, &g_lcd_height);
}
2. 使用互斥量保护绘图核心函数
在 LCD 区域绘制函数中,先获取互斥量再绘图,完成后释放:
// LCD区域绘制核心函数(添加互斥保护)
static void Draw_Region(uint32_t x, uint32_t y, P_BitMap ptBitMap)
{
/* 获得互斥量:阻塞等待直到获取成功(portMAX_DELAY) */
xSemaphoreTake(g_spi_lcd_lock, portMAX_DELAY);
/* 原有绘图逻辑:设置显示区域→切换数据模式→发送像素数据 */
// 设置要显示的矩形区域
LCD_SetWindows(x, y, x + ptBitMap->width - 1, y + ptBitMap->height - 1);
// 设置D/C引脚为数据模式(后续发送像素数据)
LCD_SetDataLine();
// 发送像素数据(RGB565格式,2字节/像素)
LCD_WriteDatas(ptBitMap->datas, ptBitMap->height * ptBitMap->width * 2);
/* 释放互斥量:允许其他任务访问LCD */
xSemaphoreGive(g_spi_lcd_lock);
}
五、功能验证:多传感器数据采集与显示
完成程序编译烧录后,H5 主控可通过 485 HUB 同时访问三类 F030 传感器,LCD 屏幕上清晰显示各传感器数据:
- 开关量传感器:KEY1/KEY2/KEY3 的按下状态;
- 环境监测传感器:光敏电阻(光强)、可调电阻的 ADC 值;
- 温湿度传感器:温度(单位 0.1℃)、湿度(单位 0.1% RH);
- 三类传感器的 LED 均按 500ms 周期闪烁,验证远程控制功能有效。
实际测试效果如下:

六、总结
- 采用 485 HUB 实现多 F030 传感器组网,H5 主控作为 Modbus 主站通过不同通道 / 地址区分传感器;
- 基于 FreeRTOS 多任务调度,每个 485 通道对应独立任务,保障多传感器数据采集的并行性;
- 通过 FreeRTOS 互斥量保护 LCD 绘图操作,解决多任务同时访问导致的花屏问题;
- Modbus 主站程序通过切换从机地址,可在同一通道访问多个传感器,降低硬件成本。
七、结尾
本次完成了 Modbus 多传感器组网的核心开发,实现了 H5 主控对三类 F030 传感器的集中访问、数据采集与远程控制,这套组网方案可直接复用至工业多传感器监测场景。掌握多任务调度 + Modbus 主从通信 + 外设互斥保护的设计思路,是实现复杂工业监测系统的关键。感谢各位的阅读,持续关注本系列笔记,一起探索更多工业级 Modbus 组网与嵌入式系统开发的实用技巧!
更多推荐
所有评论(0)