资讯动态

STM32+BC260Y+DHT11温湿度上报OneNET全流程实战

发布时间:2026/9/2 3:38:41 来源:尧图企业网站定制
简介一套面向STM32与NB-IoT物联网初学者的完整工程实践源码围绕意法半导体STM32F103C8T6微控制器、中国移动BC260Y NB-IoT模块与低成本DHT11温湿度传感器完整演示如何通过MQTT协议将采集到的温湿度数据上报至OneNET云端实现从传感器采集、MCU处理到NB-IoT无线传输的端到端数据链路。压缩包内共151个文件、3.42MB以C语言源代码.c/.h为主体辅以Keil工程配置uvprojx/uvoptx、编译链接产物axf/hex/map、依赖与配置辅助文件.d/.crf/.ini及少量说明文档txt/htm文件类型覆盖源码阅读、工程编译、烧录与运行验证等多个环节目录划分清晰便于直接打开工程学习。目前已有1433人学习下载。工程覆盖MCU串口驱动、BC260Y模块AT指令交互、DHT11单总线时序读取等关键代码同时涉及OneNET设备接入、MQTT发布/订阅、低带宽高可靠性传输机制等物联网核心知识点读者可对照硬件连接与代码注释梳理完整数据链路并在此基础上快速移植到自己的温湿度监测、智能家居或环境采集项目中是嵌入式与物联网入门及课程设计颇具参考价值的实战资料。 最近整理项目笔记把手头这套基于STM32BC260YDHT11上报温湿度到OneNET的流程完整梳理了一遍。这套结构在物联网毕设、产品原型和环境监测节点里非常常见单片机采集传感器数据NB-IoT模组负责联网最终把数据送到云平台。链路看似简单但从硬件接线、传感器时序、模组AT指令到MQTT报文每一步都有不少细节很多朋友卡在中间某一段往往是因为只看了孤立教程没有把整条链路串起来。这篇文章就以实际项目为背景从方案选型、电路设计、驱动代码、云平台配置到问题排查完整走一遍流程适合正在做NB-IoT数据上报、用OneNET做毕业设计或工业采集节点的开发者参考。1. 整体方案选型与核心链路拆解1.1 为什么选BC260Y而不是WiFi模组这个项目里很多人会问既然要上云为什么不用ESP8266这种WiFi模块成本低、资料也多。核心原因是应用场景。这套方案针对的是农业大棚、消防通道、仓库、户外管井这类没有稳定WiFi覆盖、或者不方便布线的位置。BC260Y是移远的NB-IoT模组工作在授权频谱一张SIM卡就能接入运营商网络覆盖距离远、穿墙能力强、单点功耗低非常适合分散式低速率传感器节点。从成本角度看NB-IoT模组比WiFi模块贵但比4G Cat.1模组便宜而且功耗优势明显。BC260Y支持PSM和eDRX两种低功耗模式上报完数据后能深度睡眠用锂亚电池供电跑一年以上是常见操作。对于不需要实时长连接、每隔几分钟上报一次温湿度的场景这是比WiFi更合理的方案。1.2 数据从传感器到云端的完整路径整条数据链路由四段组成DHT11采集温湿度通过单总线协议把40bit数据发给STM32STM32做主控把原始温度、湿度值解析出来缓存到变量中BC260Y通过串口与STM32通信STM32发AT指令让模组附着网络、建立MQTT连接OneNET平台上创建产品、设备和数据流BC260Y按MQTT协议把JSON格式的温湿度数据发布到平台上这里需要先想清楚BC260Y不跑应用代码它只负责“传输管道”。所有业务的逻辑都放在STM32里包括传感器读取、数据格式化、AT指令流程控制、异常重试。选择这样的分工是因为NB-IoT模组的定位就是“可靠的无线modem”把数据塞给它它负责送到云端业务复杂度集中在MCU侧开发调试更方便。2. 硬件准备与DHT11驱动编写2.1 硬件清单与接线方式这一套的硬件非常简洁核心器件如下器件型号/规格数量主控板STM32F103C8T6最小系统板1NB-IoT模组移远BC260Y-CN含NB SIM卡1温湿度传感器DHT11蓝色模块1电平转换模块3.3V与1.8V双向电平转换视模组评估板而定可选稳压/供电3.6V锂电池或USB供电1天线NB-IoT外置天线1接线也很直接DHT11的DATA引脚接STM32任意普通GPIO比如PA0VCC接3.3VGND共地。BC260Y模组的UART_TX接STM32的USART2_RXUART_RX接USART2_TX电平匹配问题放在后面说。注意BC260Y的IO电平是1.8VSTM32的IO电平是3.3V。如果是用移远的评估板或者已经集成电平转换的模组底板可以直接对接如果是自己画的板子直连模组建议在UART线上加电平转换芯片比如TXB0104或分立MOS管方案否则长时间运行容易出现随机乱码。2.2 DHT11时序原理单总线怎么读DHT11是单总线传感器一根数据线既要主机发命令又要从机回数据时序必须严格卡微秒级别。熟悉I2C的人上手很快但DHT11更简单没有地址和寄存器概念每次通信就一次完整的数据交换。完整时序分四步主机拉低总线保持至少18ms然后释放并延时20~40us这代表“请求采集”DHT11检测到起始信号后拉低总线80us响应再拉高80us表示准备发送数据DHT11连续发送40bit数据高位在前每位以50us低电平开始后续高电平长度决定该bit是0还是1数据格式是8bit湿度整数8bit湿度小数8bit温度整数8bit温度小数8bit校验和判断bit的逻辑很关键26~28us的高电平表示“0”70us左右的高电平表示“1”。很多驱动写不好就是因为在读取时只用简单的延时判断没有处理好GPIO输入输出方向切换。2.3 HAL库下的DHT11驱动代码工程用STM32CubeMX生成选择F103C8T6时钟配置为内部或外部晶振均可主要用HAL_GPIO操作。DHT11引脚配置为开漏输出外部接4.7k上拉电阻到3.3V这样在读取时可以直接切换为浮空输入模式省去反复改GPIO配置的麻烦。微秒级延时是DHT11驱动的关键HAL_Delay只支持毫秒必须自己实现us延时。我习惯用DWT寄存器不需要额外定时器void delay_us(uint32_t us) { CoreDebug-DEMCR | CoreDebug_DEMCR_TRCENA_Msk; DWT-CTRL | DWT_CTRL_CYCCNTENA_Msk; DWT-CYCCNT 0; uint32_t target us * (SystemCoreClock / 1000000U); while (DWT-CYCCNT target); }读取一个字节的核心代码static uint8_t DHT11_ReadByte(void) { uint8_t val 0; for (int i 0; i 8; i) { while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_RESET); delay_us(40); if (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET) { val (val 1) | 0x01; while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET); } else { val val 1; } } return val; }完整读取函数需要先拉低总线18ms然后释放、延时20us左右再检测响应信号。DHT11从机上电后需要一个稳定时间所以驱动里最好加一个1秒钟的初始化延时否则首次上电读数据容易失败。3. BC260Y初始化与OneNET的MQTT接入3.1 BC260Y上电与网络注册操作BC260Y用AT指令控制STM32通过串口发送带\r\n结尾的AT命令并等待模组返回OK或特定响应。上电后第一步是确认模组工作正常发AT返回OK然后发ATCGMM查看模组型号。NB-IoT网络注册是整个项目里最容易卡住的地方因为它比WiFi连路由慢得多。WiFi模块上电几秒就能拿到IPNB-IoT模组上电后搜索小区、鉴权、附着网络整个过程可能耗时10到60秒在地下室或信号弱的地方更久。网络注册操作分两步ATCGATT1 // 打开网络附着 ATCEREG? // 查询网络注册状态返回 CEREG: 0,1 表示注册成功其中CEREG: 0,1里的“1”代表已注册到网络“5”代表已注册并 roaming。如果返回0或2说明还没找到网络。注册成功后再查IP地址用ATCGPADDR1能返回一个IP就说明网络通道已经建立。3.2 OneNET平台侧准备接下来是OneNET平台配置。登录OneNET后在控制台创建产品选择“多协议接入”中的MQTT协议。这里要提醒一句OneNET经过几次改版新用户可能进入的是新版OneNET Studio界面界面逻辑和老版差异很大。老版“多协议接入”适合本项目的经典接入方式设备IDAPIKeytopic使用$dp直接上报数据流。创建完产品后在产品下添加设备记录三个关键参数设备ID、APIKey、产品ID。老版MQTT接入里设备鉴权只需要设备ID和APIKey连接服务器地址是183.230.40.40端口6002。如果是新版OneNETMQTT接入域名是mqtts.heclouds.com:1883鉴权方式使用token签名需要计算res、et、sign等参数流程相对复杂。建议做毕设或快速原型时优先找“多协议接入”老版入口整体开发成本低很多。3.3 MQTT登录与数据上报报文BC260Y自带MQTT协议栈不需要在STM32上移植MQTT客户端只需通过AT指令配置即可。MQTT连接分两步先打开网络ATQMTOPEN0,183.230.40.40,6002返回OK后再查是否真正打开成功会看到QMTOPEN: 0,0第二个0表示成功。然后连接OneNETATQMTCONN0,设备ID,设备ID,APIKey这里容易懵MQTT的clientId、username、password到底填什么OneNET老版MQTT的规则是clientId填设备IDusername也填设备IDpassword填APIKey。和普通MQTT服务器username是账号、password是密码完全不同直接用设备ID当用户名容易混淆但平台就是这么要求的。连接成功会返回QMTCONN: 0,0,0。然后发布数据ATQMTPUB0,0,0,0,$dp,28回车后模组会返回此时输入payload内容并补一个十六进制的0x1A作为结束。topic是$dppayload是JSON格式{datastreams:[{id:temp,datapoints:[{value:26}]},{id:humi,datapoints:[{value:58}]}]}发布成功返回QMTPUB: 0,0,0。整个流程里topic和JSON格式必须严格正确尤其JSON里键名不能带单引号value必须是数字不能是字符串否则平台不报错但数据就是进不来。4. 主程序整合与数据采集状态机4.1 子模块初始化的顺序细节STM32上电后初始化顺序会影响整个系统的稳定性。我的习惯是先初始化时钟和串口再初始化GPIO和传感器最后才操作BC260Y模组。原因很简单NB-IoT模组启动时间最长如果一开始就阻塞等待模组响应会耽误传感器准备。实际流程是初始化HAL库、系统时钟初始化调试串口用于打印日志与BC260Y通信串口初始化DHT11引脚并延时1秒让传感器稳定向BC260Y发送AT等待模组就绪配置APN、附着网络、建立MQTT连接进入主循环定时读取DHT11并上报BC260Y建议在首次上电时等待模组返回“RDY”或者通过AT指令轮询就绪状态。有些固件上电后会主动上报乱码不一定是故障串口调试时别紧张先忽略这些主动消息直到能够稳定响应OK。4.2 数据上报周期与功耗设计NB-IoT模组的功耗特性决定了数据上报周期不能设计得太随意。BC260Y的PSM模式有个特点数据上报完成后模组进入深睡此时网络侧会有一段时间不主动下发数据如果频繁在PSM和活跃态之间切换反而更耗电。我的项目里设置的是每5分钟上报一次温湿度这比较适合环境监测场景。主循环用HAL_Delay或者定时器中断计时采集前先唤醒模组、保持连接然后读取DHT11、拼接JSON、发布数据发布完成之后如果暂时不需要下行控制就进入睡眠等待下一个周期。需要特别注意的是DHT11本身的采样周期。DHT11数据手册明确要求两次读取间隔不得小于1秒即便驱动代码再快也不能突破这个限制。我在调试时曾经在这个问题上栽过跟头把读取间隔压缩到200ms结果数据经常跳变或校验失败后来查资料才发现DHT11内部的AD转换需要1秒左右完成。4.3 主循环核心代码结构主程序的核心逻辑可以整理成一个简易状态机避免程序阻塞在某一个环节while (1) { switch (state) { case STATE_READ_SENSOR: if (DHT11_Read(temperature, humidity) DHT11_OK) { state STATE_UPLOAD; } else { state STATE_RETRY; } break; case STATE_UPLOAD: snprintf(payload, sizeof(payload), {\datastreams\:[{\id\:\temp\,\datapoints\:[{\value\:%d}]},{\id\:\humi\,\datapoints\:[{\value\:%d}]}]}, temperature, humidity); if (send_qmtpub(payload) SUCCESS) { state STATE_SLEEP; } else { state STATE_RETRY; } break; case STATE_SLEEP: HAL_Delay(300000); state STATE_READ_SENSOR; break; case STATE_RETRY: reconnect_nbiot(); state STATE_READ_SENSOR; break; default: state STATE_READ_SENSOR; break; } }状态机相比纯顺序执行有个很大优势如果模组网络暂时掉线不需要整个程序卡死可以在重试状态里做网络重连同时把传感器数据保留在缓存里等网络恢复后补报而不是直接丢数据。5. 常见问题与排查技巧实录5.1 问题排查速查表做这个项目时大家最常卡住的问题集中在网络注册和MQTT连接两个环节。这里整理一个排查速查表按现象直接定位现象可能原因处理方法串口发AT无响应波特率不对、模组未上电、串口TX/RX接反确认BC260Y默认波特率检查串口引脚ATCEREG?返回0或2SIM卡未插好、天线松动、信号弱重新插卡装外置天线到窗边测试ATCGATT1返回ERRORAPN配置错误、卡未激活配置ATCGDCONT1,IP,cmiotQMTOPEN成功但QMTCONN失败设备ID或APIKey错误核对OneNET设备参数区分大小写QMTCONN成功但发布失败主题错误、MQTT连接失效确认使用$dp主题并检查返回码DHT11校验和错误上拉电阻缺失、接线过长、采集间隔过短加4.7k上拉缩短杜邦线确保间隔大于1秒平台数据流无数据JSON格式错误、数据流名不一致先用串口工具手工发布payload验证5.2 我在实际调试中踩过的坑第一个坑是发送ATQMTPUB时payload长度算错。length字段指的是整个JSON字符串的字节数不包含引号和结束符。有次我多算了一个字节模组一直没反应平台端也收不到数据。后来用串口工具反复试才发现长度必须和实际字符串完全一致差一个字节都不行。解决办法很简单在STM32代码里用strlen(payload)动态计算长度不要手写。第二个坑是模组的主动上报消息干扰了程序解析。BC260Y在某些固件版本上电后会主动上报^MODE: 2、^SYSSTART等URC消息如果STM32只发AT指令却不处理这些主动消息接收缓冲区会堆积导致后续指令的响应和URC消息混在一起。代码里做AT响应解析时要跳过以^开头的行或者发送指令前先清空接收缓冲区。第三个坑是电平匹配问题。早期用杜邦线直接连接STM32和BC260Y评估板当时评估板已经做了电平转换没问题但后来换成裸模组把3.3V信号直接怼到1.8V IO上短时间能工作长时间跑下来偶尔会通信失败。改成电平转换模块后问题消失。所以自己画板子时务必看清模组硬件手册的IO电平要求。最后提一个关于天线的小建议NB-IoT频段比WiFi低波长更长天线的尺寸和走线对信号影响很大。用裸模组时如果不用外置天线靠着PCB天线或者一段飞线信号强度会有明显差异表现为网络注册慢、连接不稳定。建议无论做原型还是量产天线部分都按模组厂商的参考设计来做别省这个成本。这套方案整体跑通之后后面如果要扩展可以在OneNET上增加数据流、报警规则或者在STM32端接更多传感器比如土壤湿度、光照强度代码框架不用大改只要把JSON payload里的数据流增加字段就行。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价