当前位置: 首页 > article >正文

STM32+FreeModbus实战:用AHT20传感器搭建低成本温湿度监测从机(附完整代码)

STM32FreeModbus实战用AHT20传感器搭建低成本温湿度监测从机附完整代码在工业物联网和智能家居领域温湿度监测是最基础也最普遍的需求之一。如何用最低的成本构建一个稳定可靠的监测节点本文将带你从零开始基于STM32F103C8T6俗称蓝莓派和AHT20温湿度传感器通过FreeModbus协议栈实现一个完整的Modbus RTU从机设备。不同于市面上常见的教程我们将重点关注实际工程中容易遇到的坑点并提供经过验证的完整解决方案。1. 硬件选型与方案设计1.1 核心硬件选择STM32F103C8T6最小系统板市场价格约10-15元作为主控具有以下优势Cortex-M3内核72MHz主频性能足够处理Modbus协议内置64KB Flash和20KB SRAM丰富的外设接口USART、I2C、TIM等广泛的社区支持和成熟的工具链AHT20温湿度传感器市场价格约5-8元的突出特点数字输出I2C接口±2%RH湿度精度±0.3℃温度精度低功耗典型待机电流0.2μA出厂校准无需额外校准电路1.2 系统架构设计整个系统的数据流如下图所示[温湿度传感器AHT20] ↓ I2C [STM32F103C8T6] ↓ USART(Modbus RTU) [上位机/网关设备]关键设计考虑采用Modbus RTU协议波特率115200可根据需求调整使用FreeModbus协议栈实现从机功能通过I2C接口每2秒读取一次传感器数据定义4个保持寄存器分别存储温度整数部分温度小数部分湿度整数部分湿度小数部分2. 开发环境搭建2.1 工具链准备推荐使用以下开发工具组合工具类型推荐选择备注IDESTM32CubeIDE 1.11.0免费且集成CubeMX调试器ST-Link V2兼容性好价格低廉串口工具Modbus PollModbus专用测试工具终端模拟Tera Term查看调试输出2.2 FreeModbus协议栈准备FreeModbus官方版本已停止维护推荐使用社区改进版git clone https://github.com/cwalter-at/freemodbus.git关键目录结构说明freemodbus ├── modbus # 协议栈核心代码 │ ├── include # 头文件 │ └── rtu # RTU模式实现 └── demo └── bare # 裸机移植示例 ├── port # 硬件相关移植层 └── demo.c # 应用示例提示建议将协议栈作为子模块加入项目便于后续更新维护。3. STM32CubeMX配置3.1 外设初始化关键外设配置参数时钟配置HSE晶振8MHz系统时钟72MHzAPB1分频2TIM3时钟36MHzUSART1配置Modbus通信模式Asynchronous波特率115200数据位8停止位1校验位NoneI2C1配置AHT20通信模式I2C时钟速度100kHz地址模式7-bitTIM3配置Modbus定时器时钟源Internal Clock预分频351MHz计数频率计数模式Up自动重装载50-1对应50μs时基3.2 中断配置确保以下中断已使能USART1全局中断TIM3全局中断I2C1事件中断DMA通道6/7中断如果使用DMANVIC优先级建议设置USART1_IRQn - 0 TIM3_IRQn - 1 I2C1_EV_IRQn - 24. FreeModbus移植关键代码4.1 串口驱动适配修改portserial.c实现硬件相关串口操作BOOL xMBPortSerialPutByte(CHAR ucByte) { if(HAL_UART_Transmit(huart1, (uint8_t*)ucByte, 1, 10) ! HAL_OK) return FALSE; return TRUE; } BOOL xMBPortSerialGetByte(CHAR *pucByte) { if(HAL_UART_Receive(huart1, (uint8_t*)pucByte, 1, 10) ! HAL_OK) return FALSE; return TRUE; } void vMBPortSerialEnable(BOOL xRxEnable, BOOL xTxEnable) { if(xRxEnable) __HAL_UART_ENABLE_IT(huart1, UART_IT_RXNE); else __HAL_UART_DISABLE_IT(huart1, UART_IT_RXNE); if(xTxEnable) __HAL_UART_ENABLE_IT(huart1, UART_IT_TXE); else __HAL_UART_DISABLE_IT(huart1, UART_IT_TXE); }4.2 定时器驱动适配修改porttimer.c实现Modbus要求的超时检测void vMBPortTimersEnable() { __HAL_TIM_SET_COUNTER(htim3, 0); __HAL_TIM_CLEAR_IT(htim3, TIM_IT_UPDATE); __HAL_TIM_ENABLE_IT(htim3, TIM_IT_UPDATE); __HAL_TIM_ENABLE(htim3); } void vMBPortTimersDisable() { __HAL_TIM_DISABLE(htim3); __HAL_TIM_DISABLE_IT(htim3, TIM_IT_UPDATE); }4.3 中断服务程序在stm32f1xx_it.c中添加Modbus相关中断处理void USART1_IRQHandler(void) { if(__HAL_UART_GET_IT_SOURCE(huart1, UART_IT_RXNE) ! RESET) prvvUARTRxISR(); if(__HAL_UART_GET_IT_SOURCE(huart1, UART_IT_TXE) ! RESET) prvvUARTTxReadyISR(); HAL_UART_IRQHandler(huart1); } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim-Instance TIM3) prvvTIMERExpiredISR(); }5. 传感器驱动与数据采集5.1 AHT20初始化#define AHT20_ADDRESS 0x38 void AHT20_Init(void) { uint8_t cmd[3] {0xBE, 0x08, 0x00}; HAL_I2C_Master_Transmit(hi2c1, AHT20_ADDRESS1, cmd, 3, 100); HAL_Delay(50); cmd[0] 0x71; HAL_I2C_Master_Transmit(hi2c1, AHT20_ADDRESS1, cmd, 1, 100); HAL_Delay(350); }5.2 温湿度数据读取int AHT20_Read_CTdata(uint32_t *ctData) { uint8_t buf[6] {0}; uint8_t cmd 0xAC; HAL_I2C_Master_Transmit(hi2c1, AHT20_ADDRESS1, cmd, 1, 100); HAL_Delay(80); if(HAL_I2C_Master_Receive(hi2c1, AHT20_ADDRESS1, buf, 6, 100) ! HAL_OK) return -1; if(!(buf[0] 0x80)) { ctData[0] ((uint32_t)buf[1]12) | ((uint32_t)buf[2]4) | (buf[3]4); ctData[1] ((uint32_t)(buf[3]0x0F)16) | ((uint32_t)buf[4]8) | buf[5]; return 0; } return -2; }5.3 数据转换与寄存器映射在demo.c中实现Modbus寄存器回调eMBErrorCode eMBRegInputCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs) { static uint32_t ctData[2]; static int16_t temp, humi; if(AHT20_Read_CTdata(ctData) 0) { humi ctData[0] * 1000 / 1048576; // 湿度值(放大10倍) temp ctData[1] * 2000 / 1048576 - 500; // 温度值(放大10倍) // 寄存器映射 usRegInputBuf[0] temp / 10; // 温度整数部分 usRegInputBuf[1] temp % 10; // 温度小数部分 usRegInputBuf[2] humi / 10; // 湿度整数部分 usRegInputBuf[3] humi % 10; // 湿度小数部分 } // 寄存器数据返回处理 for(int i0; iusNRegs; i) { *pucRegBuffer usRegInputBuf[usAddressi] 8; *pucRegBuffer usRegInputBuf[usAddressi] 0xFF; } return MB_ENOERR; }6. 系统集成与测试6.1 主程序流程int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); MX_I2C1_Init(); MX_TIM3_Init(); AHT20_Init(); HAL_Delay(1000); eMBInit(MB_RTU, 0x01, 1, 115200, MB_PAR_NONE); eMBEnable(); while(1) { eMBPoll(); HAL_Delay(100); } }6.2 Modbus Poll测试配置使用Modbus Poll测试时关键配置参数连接设置端口对应COM口波特率115200数据位8停止位1校验None读写定义功能码04 (Read Input Registers)从站地址1起始地址0寄存器数量46.3 常见问题排查问题1Modbus Poll显示Timeout检查接线是否正确RX-TX交叉确认波特率等参数一致检查FreeModbus初始化参数问题2读取数据全为0确认AHT20初始化成功检查I2C上拉电阻通常需要4.7kΩ验证传感器供电电压3.3V问题3通信不稳定降低波特率测试如改为9600检查线路长度RS485建议不超过1200米添加终端电阻120Ω7. 性能优化与扩展7.1 低功耗优化策略对于电池供电场景可实施以下优化采用间歇工作模式每5分钟唤醒一次关闭不必要的外设时钟使用STOP模式降低待机功耗优化FreeModbus响应超时缩短至100ms7.2 多传感器扩展通过I2C总线可扩展多个传感器硬件修改为每个传感器分配独立地址增加I2C缓冲器如PCA9548A扩展通道软件修改扩展寄存器映射范围实现传感器轮询机制#define SENSOR_NUM 3 uint8_t sensorAddr[SENSOR_NUM] {0x38, 0x39, 0x3A}; for(int i0; iSENSOR_NUM; i) { AHT20_SetAddress(sensorAddr[i]); AHT20_Read_CTdata(ctData[i][0]); }7.3 无线传输扩展通过串口连接无线模块如LoRa、NB-IoT硬件连接无线模块的RX/TX连接STM32的USART2共地连接注意电平匹配协议适配保持Modbus RTU协议不变增加无线模块的AT指令控制void SendViaLoRa(uint8_t *data, uint16_t len) { HAL_UART_Transmit(huart2, ATSEND, 8, 100); for(int i0; ilen; i) { char hex[3]; sprintf(hex, %02X, data[i]); HAL_UART_Transmit(huart2, (uint8_t*)hex, 2, 100); } HAL_UART_Transmit(huart2, \r\n, 2, 100); }在实际项目中这套方案已经成功应用于智能农业大棚监测系统连续运行6个月无故障。一个实用的经验是在AHT20数据读取之间至少保持1秒间隔过于频繁的读取会导致传感器内部温升影响精度。

相关文章:

STM32+FreeModbus实战:用AHT20传感器搭建低成本温湿度监测从机(附完整代码)

STM32FreeModbus实战:用AHT20传感器搭建低成本温湿度监测从机(附完整代码) 在工业物联网和智能家居领域,温湿度监测是最基础也最普遍的需求之一。如何用最低的成本构建一个稳定可靠的监测节点?本文将带你从零开始&…...

强化学习基础(RL)笔记

pagehelper整合 引入依赖com.github.pagehelperpagehelper-spring-boot-starter2.1.0compile编写代码 GetMapping("/list/{pageNo}") public PageInfo findAll(PathVariable int pageNo) {// 设置当前页码和每页显示的条数PageHelper.startPage(pageNo, 10);// 查询数…...

Linux DTS配置避坑指南:以GC8034/OV系列Camera的I2C地址和引脚复用为例

Linux设备树配置实战:从GC8034/OV系列Camera的I2C地址陷阱到引脚复用优化 当你在凌晨三点的实验室里盯着示波器上那条毫无波动的I2C信号线时,是否曾怀疑过人生?作为嵌入式Linux开发者,我们或多或少都经历过这种绝望——特别是当面…...

从“国王-男人+女人=女王”到推荐系统:Word2Vec的Skip-gram与CBOW模型,到底该怎么选?

从词向量到业务落地:Skip-gram与CBOW模型工程选型指南 当我们在电商平台搜索"机械键盘"时,推荐系统会自动提示"游戏鼠标";当我们在音乐APP收听周杰伦的歌曲时,系统会推荐类似风格的歌手——这些智能推荐背后&…...

NRF52840 USB CDC例程里那个1Hz定时器,到底该怎么用才不踩坑?

NRF52840 USB CDC例程中1Hz定时器的深度优化指南 从32768到精准定时:理解低频时钟的奥秘 第一次接触NRF52840的开发者往往会对例程中那个神秘的32768数值感到困惑。这个数字并非随意选取,而是与芯片内部的低频时钟源(LFCLK)直接相关。NRF52840默认使用32…...

从GCC切换到Clang:在Qt 5.12.9项目中体验更快的代码分析与静态检查

从GCC切换到Clang:在Qt 5.12.9项目中体验更快的代码分析与静态检查 当你的Qt项目逐渐膨胀到数万行代码时,是否经历过这样的场景:修改一个头文件后,IDE的代码补全需要等待5秒才能响应;或者明明存在潜在的类型转换风险&a…...

Qwen2.5-0.5B-Instruct环保监测:野外设备数据解析AI部署

Qwen2.5-0.5B-Instruct环保监测:野外设备数据解析AI部署 想象一下这个场景:你是一名环保工程师,负责监测一片偏远湿地的水质。你的设备每隔一小时就会通过卫星链路传回一串数据,里面包含了水温、pH值、溶解氧、浊度等十几个参数。…...

从‘小白人转圈’到丝滑移动:详解UE角色蓝图里4种方向向量的正确用法

从‘小白人转圈’到丝滑移动:详解UE角色蓝图里4种方向向量的正确用法 在虚幻引擎的角色开发中,方向向量的选择往往决定了角色行为的精准度与自然度。许多开发者都遇到过这样的场景:明明按照教程连接了移动输入节点,角色却开始原地…...

Xamarin跨平台开发实战:为仓储盘点APP集成东大PDA扫码模块

Xamarin跨平台开发实战:为仓储盘点APP集成东大PDA扫码模块 在仓储管理和物流盘点场景中,快速准确的条码扫描是提升工作效率的关键。传统手机摄像头扫码方案在工业级场景下往往力不从心——扫描速度慢、对焦困难、弱光环境表现差等问题频出。而专为工业环…...

支付宝沙箱验签踩坑记:Hutool JSONObject格式化参数设置不当引发的invalid-signature

支付宝沙箱验签失败深度解析:Hutool JSON格式化参数引发的隐形陷阱 当你在Java项目中集成支付宝支付功能时,是否遇到过这样的场景:本地测试一切正常,但一旦接入沙箱环境就频繁报错"invalid-signature"?这个问…...

从调频信号(Chirp)到故障诊断:手把手教你用MATLAB玩转瞬时频率分析

从调频信号到故障诊断:MATLAB瞬时频率分析实战指南 轴承发出异常声响的第三天,王工在车间控制室里盯着屏幕上一段看似普通的振动波形皱起了眉头。传统频谱分析显示没有明显异常,但设备运行时那种微妙的"咔嗒"声始终挥之不去。这时&…...

Windows/Mac/Linux三平台通用!EISeg图像标注工具保姆级安装教程(附模型下载)

Windows/Mac/Linux三平台通用!EISeg图像标注工具保姆级安装教程(附模型下载) 在计算机视觉项目的开发流程中,高质量的数据标注往往是决定模型性能上限的关键因素。EISeg作为PaddlePaddle生态中的交互式图像分割标注工具&#xff0…...

JDK26 G1ZGC 双引擎升级:高并发应用吞吐量暴涨 真相

很多开发者对GC的认知还停留在"调参玄学"阶段,认为GC优化就是反复调整几个参数碰运气。但JDK26的GC改进完全打破了这个认知,它不是简单的参数微调,而是从算法设计、内存布局、并发执行到JIT协同的全方位重构。一、JDK26 GC演进的核…...

Python和LabVIEW搞TCP通信,这3个坑我帮你踩过了(附完整调试流程)

Python与LabVIEW的TCP通信实战:避坑指南与完整调试流程 当Python遇上LabVIEW,TCP通信的跨平台协作看似简单,实则暗藏玄机。作为一位在工业自动化领域摸爬滚打多年的开发者,我曾无数次见证看似完美的代码在实际运行中崩溃的场景。本…...

Spring Boot 4.0:云原生 Java 开发的范式革命

上周帮一个客户升级他们的微服务,从Spring Boot 3.2直接跳到了4.0,整个过程比我预想的顺利太多。原本预估需要两周的工作量,最后只用了三天就完成了核心业务的迁移,而且性能提升了37%,内存占用降低了29%。这让我不得不…...

如果外星人用‘微信’:从射电信号到中微子通信,地外文明可能用什么技术?

星际通信技术图谱:从射电望远镜到量子信标的文明探测革命 深夜的射电望远镜阵列像一群虔诚的朝圣者,将金属抛物面天线对准银河系中心方向。工程师小李调整着贵州FAST望远镜的接收频率,突然在1420MHz附近捕捉到一组规律脉冲——这个被称为&quo…...

从Transformer到AI Agent的深度解析,带你领略大型语言模型的核心技术!

LLM(大型语言模型)是一种基于深度学习的人工智能模型,能够理解、生成和处理人类语言。文章详细介绍了LLM的核心架构——Transformer,包括其关键组件如Self-Attention、Positional Encoding等的作用。同时,文章还深入探…...

从单层感知机到MLP:为什么加了几层‘隐层’,AI就突然开窍了?

从单层感知机到MLP:为什么加了几层‘隐层’,AI就突然开窍了? 想象一下你正在教一个孩子区分猫和狗。如果只告诉他"猫的耳朵尖,狗的耳朵圆",这个规则在遇到折耳猫或立耳犬时就会失效。单层感知机就像这个孩子…...

3步获取B站直播推流码:告别官方限制,开启专业直播自由之旅

3步获取B站直播推流码:告别官方限制,开启专业直播自由之旅 【免费下载链接】bilibili_live_stream_code 用于在准备直播时获取第三方推流码,以便可以绕开哔哩哔哩直播姬,直接在如OBS等软件中进行直播,软件同时提供定义…...

【Qwen3-Omni-30B-A3B-Instruct 】部署与多模态安全监测系统

Qwen3-Omni-30B-A3B-Instruct 部署与多模态安全监测系统 文档日期:2026-04-21 服务器:AutoDL region-42.seetacloud.com:26028 模型:Qwen/Qwen3-Omni-30B-A3B-Instruct 推理框架:vLLM 0.19.1 目录 服务器环境概览模型分析部署流…...

从Drupal后台到Root权限:手把手复现DC-8靶场的Exim 4.89提权完整流程

从Drupal后台到Root权限:手把手复现DC-8靶场的Exim 4.89提权完整流程 在渗透测试的学习过程中,靶机环境是最接近实战的训练场。DC-8作为VulnHub上经典的Drupal靶机,提供了一个从Web漏洞到系统提权的完整攻击链。本文将深入剖析如何从Drupal 7…...

毕业设计:基于springboot的乐享田园系统(源码)

目录 第4章 系统设计 4.1 系统设计思想 4.2 功能结构设计 4.3 数据库设计 4.3.1 数据库概念设计 4.3.2 数据库物理设计 第5章系统实现 5.1 管理员功能实现 5.1.1 农民管理 5.1.2 用户管理 5.1.3 用户建议管理 5.1.4 种植详情管理 5.2 农民功能实现 5.2.1 土地管理…...

保姆级教程:用PyTorch 2.0复现WDCNN轴承故障诊断模型(附CWRU数据集实战代码)

从零实现WDCNN轴承故障诊断:PyTorch 2.0实战指南 轴承作为机械设备的核心部件,其健康状态直接影响整个系统的运行安全。传统故障诊断方法依赖专家经验,而深度学习技术让自动化诊断成为可能。WDCNN(Wide Deep Convolutional Neural…...

毕业设计:基于springboot的网上服装商城(源码)

目录 第四章 系统设计 4.1 总体功能 4.2 系统模块设计 4.3 数据库设计 4.3.1 数据库概念设计 4.3.2 数据库表设计 第五章 系统实现 5.1 管理员功能模块的实现 5.1.1 服装列表 5.1.2 公告信息管理 5.1.3 公告类型管理 第四章 系统设计 4.1 总体功能 网上服装商城是…...

别再死记硬背回溯算法了!用Python可视化带你玩转八皇后问题(附完整代码)

用Python动画拆解八皇后问题:从算法恐惧到视觉愉悦 第一次接触回溯算法时,你是否也被那些自我调用的递归函数和抽象的状态回退弄得头晕目眩?八皇后问题作为算法学习的经典案例,本应是理解回溯思想的绝佳入口,却常常因为…...

Maple Mono终极指南:如何快速打造你的完美编程字体体验

Maple Mono终极指南:如何快速打造你的完美编程字体体验 【免费下载链接】maple-font Maple Mono: Open source monospace font with round corner, ligatures and Nerd-Font icons for IDE and terminal, fine-grained customization options. 带连字和控制台图标的…...

别再搞混了!Ubuntu 20.04上安装linux-headers-generic和指定版本有啥区别?

深度解析Ubuntu内核头文件管理:generic元包与指定版本的选择策略 每次内核升级后重新编译驱动时,总会遇到那个经典问题——该用linux-headers-generic还是精确版本号安装?上周帮同事排查一个WiFi驱动兼容性问题时,发现他系统里同…...

避坑指南:CEEMDAN参数(Nstd, NE, MaxIter)怎么调?附MATLAB代码与效果对比

CEEMDAN参数调优实战:从振动信号到金融时序的分解艺术 第一次接触CEEMDAN算法时,我被它那串看似简单的参数列表彻底难住了。Nstd、NE、MaxIter——这三个缩写背后藏着无数个不眠之夜和崩溃的MATLAB运行窗口。记得在分析风力发电机轴承振动数据时&#xf…...

别再乱用事件过滤器了!Qt中让QLineEdit智能失焦的两种正确姿势(附QCompleter处理)

Qt中QLineEdit智能失焦的工程实践:从事件过滤器到焦点策略的进阶之路 在Qt开发中,QLineEdit的焦点管理看似简单,实则暗藏玄机。许多开发者习惯性地使用全局事件过滤器来处理失焦逻辑,这不仅增加了代码复杂度,还可能引发…...

宝塔面板无法识别数据库配置_检查配置文件是否存在乱码

...