news 2026/9/16 14:58:48

NB-IoT+STM32光照度采集上云实战:从方案选型到低功耗落地

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
NB-IoT+STM32光照度采集上云实战:从方案选型到低功耗落地

简介:基于窄带物联网(NB-IoT)与STM32的光照度采集上云项目资源包,面向物联网应用开发初学者、嵌入式爱好者以及正在备战物联网实训或毕业设计的学员,也适合作为高校物联网课程的配套案例。项目以STM32为控制核心读取光照度传感器数据,经NB-IoT模块传输至腾讯云,再通过微信小程序展示实时数值,完整覆盖硬件采集、网络通信、云端接入和移动端呈现的链路。资源包共5个文件,集成约4.04MB,包含两套STM32工程源码(分别适配标准库与Pro版开发环境)、项目简介与搭建步骤HTML文档、善学坊官方学习指南HTML文档以及License许可说明;源码、配置和文档分层放置,既有可直接运行的固件,也有逐步搭建指引。当前已有643人浏览学习。通过该资源可系统掌握STM32的ADC采样与光照传感器驱动、NB-IoT模块的AT指令控制、腾讯云设备接入与数据流转、微信小程序API对接等关键环节,同时了解嵌入式、通信、云端和移动端协同开发的完整思路,便于后续扩展温湿度、GPS等更多传感器应用。

1. 用 NB-IoT 把光照度传到腾讯云,比 WiFi 方案多出来的三件事

光照度采集这种项目,最常见的第一版是用 STM32 加 ESP8266 走 WiFi,上云快、调试简单,但真放到室外绿化带、农业大棚或者厂房采光井里,WiFi 覆盖和功耗两个问题立刻浮现。NB-IoT 走运营商授权频谱,单点覆盖能穿两层楼,一个基站扛几万个终端,上报一条 100 字节的 JSON 报文,平均电流能做到微安到毫安级——这正是光照度这类低速率、小报文、长时间待机的数据最舒服的传输方式。下面按“方案选型、腾讯云平台配置、STM32 采集与上报、链路排错、低功耗落地”这条线,把基于 NB-IoT+STM32 实现采集光照度到腾讯云的一套可复现做法讲清楚,适合准备毕业设计、物联网竞赛或要快速出 NB-IoT 落地 demo 的嵌入式工程师。

2. NB-IoT + STM32 光照度采集系统的方案选型与数据链路

2.1 为什么光照度这类低速率小报文适合走 NB-IoT

2.1.1 NB-IoT 的特性边界

室内光照度采集的报文通常是“设备编号、时间戳、lux 值、信号强度”,一条不超过几十字节。NB-IoT 的设计目标就是这类业务:上行速率约 20-60kbps,下行更窄,但覆盖增益比 LTE 高 20dB,能钻到地下室和管道井里。3GPP 给 NB-IoT 定义了 PSM 和 eDRX 两种节电机制,设备可以长时间“睡觉”,睡醒后只上报一个数据包又睡回去。相比之下,WiFi 模组待机电流在毫安级,还要维护 TCP keepalive,在无人维护的现场很不划算。

需要注意边界:NB-IoT 不适合实时性要求高的双向控制,时延通常在 1-6 秒,命令下发是低频次的。如果后面要做自动补光灯的毫秒级控制,正确做法是让 STM32 本地判断,云端只做记录和远程策略调整。这个定位想清楚,后边腾讯云上的数据模板和 Topic 设计才不会跑偏。

2.1.2 与 Cat.1 和 LoRa 的取舍

如果数据量不大但要求实时响应,4G Cat.1 更合适;如果园区里自己布网关、不上运营商网络,LoRa 更合适,但要自己维护网关和频点合规问题。NB-IoT 的优势是直接用运营商存量基站,不用自建网关,一张卡一年流量很少也够用。选 NB-IoT 的场景一般是位置分散、数量多、没有本地 WiFi、又不希望自己维护网络设备的项目。这个逻辑也决定了腾讯云那边选产品时要按“设备-密钥”直接配,而不是按“网关-子设备”的拓扑配。

2.2 硬件选型:BH1750 传感器与 NB-IoT 模组的搭配

光照度采集传感器常用两种:光敏电阻加 ADC 电路,或者数字光照度传感器。光敏电阻成本低,但需要自己校准分压电阻和 ADC 参考电压,不同批次的器件一致性差,工程上标定很烦。BH1750 是 I2C 接口的数字传感器,量程 1-65535 lx,内部有光电二极管和 ADC,直接输出 lux 值,精度对农业补光和室内照明监测够用。I2C 只需要两根线,STM32 的硬件 I2C 或 GPIO 模拟 I2C 都能驱动。要注意 BH1750 的 ADDR 引脚电平决定设备地址是 0x23 还是 0x5C,多路采集时可以用不同地址挂同一条总线。

NB-IoT 模组常见的有移远 BC26/BC35-G、中移 M5310-A,以及国产的利尔达、有人物联网模组。选型主要看三件事:是否有支持 MQTT 的 AT 固件、PSM 功耗参数能不能通过 AT 指令配置、串口波特率是否方便直接接 STM32 的 USART。大部分模组默认波特率 9600 或 115200,在 STM32 初始化串口时先对上,调试阶段别一上来就开流控。拿到模组后先接 USB 转串口在电脑上验证一遍网络注册,指令会话大概是这样的:

AT OK AT+CSQ +CSQ: 22,99 OK AT+CEREG? +CEREG: 0,1 OK

这里+CSQ: 22,99表示信号强度 22(0-31,越大越好),第二个参数 99 表示误码率未知,先不管。+CEREG: 0,1里第二个 1 表示已注册上网络。这两条能过,再谈连云。

2.3 数据上腾讯云的三种路径,MQTT 直连为什么是首选

这里有个关键决定:数据怎么从 NB-IoT 模组到达腾讯云。常见做法有三条路。

路径组件优点缺点
MQTT 直连模组内置 MQTT AT 固件 + IoT Explorer链路最短,平台可管理模组固件要支持 MQTT
UDP + 云网关模组 UDP 上报 + 自建云转发报文最省流量要自己维护服务器并适配
运营商平台转发通过运营商物联网平台转接到腾讯云适合存量平台设备多一跳,配置复杂

我一般建议优先走 MQTT 直连,因为它正好用上腾讯云 IoT Explorer 的设备管理、数据模板和规则引擎。设备端只要把 JSON 报文发到固定的 Topic,平台自动解析并显示在控制台,不用自己搭后端。对毕业设计和快速验证来说这是最稳妥的路径。后面章节的代码默认也是模组使用支持云平台接入的 MQTT AT 固件,如果手上的模组固件不带 MQTT,需要先用串口或 DFU 方式升级模组固件。

3. 腾讯云 IoT Explorer 的产品创建与 MQTT 连接参数

3.1 创建产品和设备时要确定的 4 个关键配置

在控制台选“物联网开发平台 IoT Explorer”,新建产品时,有四个配置会影响后面代码的写法。

配置项取值示例作用
节点类型设备(不是网关)决定是否走子设备拓扑
数据协议MQTT与模组 AT 指令对接
认证方式密钥认证决定 MQTT 密码生成规则
产品名称stm32-lux-sensor建议拼音或英文,避免 URL 编码问题

节点类型选“设备”,不要选“网关”;数据协议选“MQTT”;认证方式选“密钥认证”。认证方式决定了设备侧最终连接时 MQTT 密码的生成规则,这是最容易让新手卡住的地方,下面专门讲。创建完产品后,在设备列表里点“添加设备”,会得到一个三元组:产品 ID、设备名称、设备密钥。产品 ID 是一串字母数字,设备名称是自己填的英文标识,设备密钥是 24 位左右的密文,这三样会被烧进 STM32 的代码里。

提示:设备密钥相当于设备在云端的登录口令,调试日志里不要再打印出来,调试完记得把相关打印关掉。

3.2 设备三元组与 MQTT 连接参数的对应关系

腾讯云 IoT Explorer 的 MQTT 连接参数不是随便填的。clientId 和 username 都是用产品 ID 加设备名拼接,password 是对时间戳用设备密钥做 HMAC-SHA1 生成的签名。常见做法是先取当前 UTC 时间戳(秒),把设备密钥作为 HMAC 的 key,时间戳作为消息内容,得到签名后拼成“时间戳;签名”。用 Python 可以这样生成签名:

import hmac import hashlib import time device_secret = "你的设备密钥" ts = str(int(time.time())) sign = hmac.new(device_secret.encode(), ts.encode(), hashlib.sha1).hexdigest() print("timestamp:", ts) print("password:", f"{ts};{sign}")

这个脚本每次运行生成的都是新签名,原因是 timestamp 直接参与 HMAC 计算,云端用相同规则验签,设备端时间偏差超过一定范围会连接失败。所以设备侧也要维护一个能拿到当前 Unix 时间戳的时钟源,常见做法是上电时通过模组的取网络时间指令(不同模组指令名不同,如 AT+QLTS)同步一次。如果设备上没有 RTC 校准,直接把固定签名烧进去,只能在签名有效期内连接,时间一长必然掉线重连失败。

另外,不同版本控制台上的调试工具会直接生成一份 MQTT 连接参数供参考。第一次调不通时,把工具生成的参数和代码算出来的逐字符对比,比反复猜快得多。

3.3 Topic 设计:属性上报与事件上报的差别

IoT Explorer 的数据模板生成后,会有两类 Topic:属性上报$thing/up/property/{productId}/{deviceName},事件上报$thing/up/event/{productId}/{deviceName}。光照度建议用属性上报,因为属性会持续记录,可以直接在控制台看到实时曲线;事件适合告警,比如光照度持续低于阈值触发“光照不足”事件。

上报的报文格式是 JSON,method 取 report,params 里写字段名和值。字段名必须和数据模板里的标识符一致。

{"method":"report","clientToken":"123456","params":{"lux":852.3,"rssi":-71}}

clientToken 是用于透传去重的字符串,可以用 STM32 的毫秒 tick 或自增计数代替。字段类型在数据模板里定义成浮点或整型,上报的值会做类型校验,类型不匹配会在平台侧解析失败,这个在第 5 章排错部分还会看到。

3.4 在腾讯云开发者后台确认设备在线

在控制台的设备详情页可以看到“在线/离线”。设备上线意味着 MQTT 连接成功,此时还没有任何业务数据,只代表云平台这个产品下对应的设备完成了认证。如果设备显示在线但你发的属性没有更新,去“设备调试”和“消息日志”页面查看上报记录,消息日志里能看到原始报文、解析结果和失败原因。这里建议养成习惯:每次改完代码先看消息日志,再回来看设备是否在线,不然容易被表面在线的假象带偏。

4. STM32 HAL 库读取 BH1750 并通过 NB-IoT 模组上报腾讯云

4.1 BH1750 的 I2C 读取与光照度换算

用 CubeMX 生成工程时,把 I2C1 设为 I2C 模式,速率选 100kHz 或 400kHz 都行,BH1750 最大支持 400kHz。下面这段用 HAL 库读取 BH1750 的代码比较常用:

// bh1750_driver.c #define BH1750_ADDR_W 0x46 // ADDR 接低电平时7位地址0x23,左移1位得到写地址 #define BH1750_ADDR_R 0x47 #define BH1750_PWR_ON 0x01 // 上电指令 #define BH1750_CONT_H 0x10 // 连续高分辨率模式,分辨率1lx uint16_t bh1750_read_lux(I2C_HandleTypeDef *hi2c) { uint8_t cmd = BH1750_PWR_ON; HAL_I2C_Master_Transmit(hi2c, BH1750_ADDR_W, &cmd, 1, 100); cmd = BH1750_CONT_H; HAL_I2C_Master_Transmit(hi2c, BH1750_ADDR_W, &cmd, 1, 100); HAL_Delay(180); // 高分辨率模式测量时间约120ms,留足余量 uint8_t buf[2]; HAL_I2C_Master_Receive(hi2c, BH1750_ADDR_R, buf, 2, 100); return (uint16_t)((buf[0] << 8) | buf[1]); }

HAL_I2C_Master_Transmit 最后一个参数是超时时间 100ms,超过会返回 HAL_TIMEOUT,实际使用中最好检查返回值。测量结果是 16 位原始值,连续高分辨率模式下要除以 1.2 得到 lux。很多网上代码把原始值直接当 lux 用,会导致光照度整体偏大,实际采集时建议拿照度计或手机 App 对比校准。

4.2 NB-IoT 模组开机到连云的 AT 指令序列

模组上电后先做网络注册,再打开 MQTT 上下文,最后连接腾讯云。以移远 BC35-G/BC26 这类模组的 AT 指令为例,整个流程可以抽象成下面这张表:

阶段AT 指令预期返回说明
自检ATOK串口通信正常
开射频AT+CFUN=1OK打开射频功能
附着网络AT+CGATT=1OK数据业务附着
查询注册AT+CEREG?+CEREG: 0,1第二位为1表示已注册
信号强度AT+CSQ+CSQ: 25,99第一位越大越好,99表示无信号
打开连接AT+QMTOPEN=0,"接入点域名",1883OK指向腾讯云 MQTT 接入点
建立连接AT+QMTCONN=0,"clientId","username","password"OK三个参数按第 3 章规则生成

连接成功后,模组会返回+QMTCONN: 0,0。失败时返回错误码,常见的是 -3,表示 MQTT 层连接被拒,优先检查 password 签名和时间偏差。接入点域名在控制台“设备调试”页面能看到,常见是iot-mqtts.pvt.tencent.com,端口 1883。注意有些老固件要求填 IP 而不是域名,遇到解析失败先看固件版本。

4.3 在 STM32 里拼接 MQTT 报文并处理返回

连接建立后,上报一条属性报文只需要三步:拼接 Topic,拼接 JSON,发送。代码如下:

// mqtt_report.c char topic[128]; char payload[160]; char at_cmd[256]; snprintf(topic, sizeof(topic), "$thing/up/property/%s/%s", product_id, device_name); snprintf(payload, sizeof(payload), "{\"method\":\"report\",\"clientToken\":\"s%lu\",\"params\":{\"lux\":%.1f,\"rssi\":%d}}", (unsigned long)HAL_GetTick(), lux, rssi); snprintf(at_cmd, sizeof(at_cmd), "AT+QMTPUB=0,0,1,0,\"%s\",%d\r\n%s", topic, (int)strlen(payload), payload);

QMTPUB 的第二个参数是 msgid,填 0 让模组自动生成;第三个参数 qos 填 1,表示至少一次,光照度上报丢一条可以接受,但 qos 太低不利于排查问题;第四个参数 retain 填 0,云端不需要保留旧值。整条 AT 指令通过 USART 发给模组,模组返回 OK 表示指令已接受,返回+QMTPUB: 0,0表示发布完成。注意不要在上一条 AT 响应返回前就发下一条,实际代码里可以用状态机或串口中断标志位来串行化。

4.4 用串口把上报链路完整打印出来

调试阶段常见的做法是把 USART2 接 STM32 的 printf 重定向,USART1 接 NB-IoT 模组,两条串口分开,避免 AT 响应和调试日志混在一起。串口调试时要打印的内容其实不多:模组每次 URC 响应、QMTPUB 完成标志、本地的 lux 原始值和换算后的值。printf 重定向用半主机模式或者直接写 ITM 都可以,MCU 资源紧张时优先用 ITM,不占串口。

光照度数据变化很快,上一秒 800 lx 下一秒被手挡住变成 50 lx,如果每次都上报会导致模组频繁发射,功耗和流量都受影响。常见做法是加上“变化超过阈值才上报”的本地判断,这条优化留到最后一章讲,它比改 PSM 参数更容易被忽略。

5. 从 SIM 卡到腾讯云日志:排查光照度不上云的顺序

5.1 第一步确认 NB-IoT 网络注册:AT+CEREG 和 AT+CSQ

上报失败先别急着改代码,先确认网络层是否就绪。AT+CEREG? 返回的第二位是注册状态:0 未注册、1 已注册、2 正在注册、3 被拒绝、5 已注册但漫游。看到 3 或 100 之类的错误码,优先怀疑 SIM 卡没有开通 NB-IoT 套餐,或者模组频段和当地基站不匹配。CSQ 返回第一项是信号强度,数值范围 0 到 31,10 以下基本别指望稳定连接,20 以上才算正常,99 表示没读到信号。

NB-IoT 测试最好的做法是准备一张已激活的测试卡,先插到 USB 转串口模块上用电脑手动敲指令,确认网络层和 MQTT 都能通,再接 STM32。这样能快速切分是设备问题还是网络问题。

提示:给设备换过 SIM 卡后,务必重新执行 AT+CFUN=1 和 AT+CGATT=1,某些模组不会自动重新附着。

5.2 第二步用 AT 指令自测 MQTT 与上报链路

模组接电脑时,还可以直接绕过 STM32 手动发一条测试报文。这个自测可以判定是模组侧 MQTT 问题还是 STM32 侧代码问题。常见的错误包括:AT+QMTCONN 返回错误码说明认证信息错了,返回 -3 基本可以断定是 clientId/username/password 拼法问题。另一点容易踩的是 Topic 里的产品 ID 和控制台显示的产品名称不是一回事,上报 Topic 里用的是产品 ID,不要混用。

发布时如果 QMTPUB 返回 ERROR,先检查 Topic 字符串是否完整。很多嵌入式代码把 snprintf 的目标缓冲区设成 64 字节,Topic 加 JSON 一长就截断了,返回的 ERROR 信息很误导人。把缓冲区放大到 160 字节以上,问题往往直接消失。

5.3 第三步在腾讯云控制台消息日志里定位问题

设备能连上但属性不更新,十有八九是数据模板字段名或 JSON 格式不一致。控制台“消息日志”里会显示每条上行消息的解析结果,解析失败时能看到字段级别的原因,比如“lux 字段类型不匹配”或“找不到产品 ID”。这里有个使用习惯:先在控制台“在线调试”发一条模拟数据,确认平台解析正常,再用设备发真实数据,这样就能知道是平台模板配置问题还是设备报文问题。

另外,clientToken 在线调试里是必填项,设备端用自增计数也能通过。若你看到消息日志里有数据但设备详情面板无曲线,检查数据模板里有没有把 lux 的“展示”开关打开,数据模板定义了字段但不展示,平台上就不会画曲线,这不是设备问题。

5.4 常见坑:芯片包、晶振电容与电平匹配

刚接触 STM32 工程的人最容易卡在开发环境。Keil5 安装 STM32 芯片包时,如果 Pack 版本和 CubeMX 生成的代码版本不一致,编译会报各种奇怪的未定义错误。建议先装齐对应系列的 Device Pack,再打开 CubeMX 生成的工程,别用旧工程硬改芯片型号。如果你用的是国产替代芯片,APM32 这类型号可以直接吃 STM32 的工程,但记得在魔术棒里改一下 Device 选项,否则烧录时报烧录算法错误。

硬件上还有两个细节容易忽略。第一是晶振电容,STM32 外部 8M 晶振的负载电容一般按晶振规格书选 18pF 到 22pF,但走线电容和芯片引脚电容会改变实际谐振频率,焊接后最好用示波器量一下系统时钟,万用表量不出来,错配会导致串口波特率偏差,模组 AT 指令时通时不通。第二是 NB-IoT 模组的串口电平,不少模组是 1.8V 电平,STM32 的 USART 引脚默认 3.3V,直接连接容易损坏模组或收不到数据,最稳妥的做法是加电平转换芯片,或者选用 3.3V 电平兼容的模组型号。如果调试时发现 HAL_Delay 偶尔卡死,多半是 SysTick 中断优先级被改动或调用位置在中断上下文里,把 I2C 和串口中断优先级理一遍再看。

6. 把光照度采集系统的待机功耗压下来的两个落地技巧

6.1 用 PSM 和 eDRX 控制 NB-IoT 射频的休眠时机

NB-IoT 待机功耗的大头在射频,不配置 PSM 时模组会保持监听,几十毫安级别的电流一直放。PSM(Power Saving Mode)允许设备在空闲一段时间后进入深度休眠,休眠期间网络侧认为设备不可达,但已注册的信息保留,醒来后不用重新附着,可以直接发数据。常见配置是用 AT+CPSMS 打开,并指定 T3324(活跃定时器)和 T3412(周期性注册更新定时器):

// T3324=60秒进入PSM,T3412=30分钟唤醒一次做周期性更新 AT+CPSMS=1,,,"00000101","00111000"

这两个值都用 8 位二进制表示定时器编码,具体 bit 含义在模组 AT 手册里有表格,不同模组微有差异。eDRX 则可以看成轻量休眠,适合需要保持可达性的场景,用 AT+CEDRXS=1 配置。光照度采集通常一小时上报一次,PSM 比 eDRX 更合适,因为上报间隙不需要接收下行。

6.2 设备端加一层本地阈值过滤,比调参更值钱

STM32 上电后先读一次 BH1750,光照度只有变化超过设定阈值才组装 MQTT 报文,否则只更新本地缓存。阈值按场景设:室内照明监控可以设 20 lx,农业补光跟踪可以设当前值的 10%。判断代码很短,但对流量和功耗影响很明显:

float new_lux = bh1750_read_lux(&hi2c1); if (fabsf(new_lux - last_lux) > LUX_THRESHOLD) { report_to_tencent(new_lux); last_lux = new_lux; }

上报完后调用 STM32 的 HAL_PWR_EnterSTOPMode 进入停止模式,并把 NB-IoT 模组设为 PSM 休眠,定时器唤醒后再走一遍采集流程。这一套组合下来,关键在“少发报文”和“早进 PSM”。可以先在本地用电流钳表量一下 PSM 状态的待机电流,再逐步加阈值过滤,往往能在一个上报周期内看到明显改善。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/16 14:57:40

龙芯派LoongArch平台部署轻量人脸识别实战指南

简介&#xff1a;本资源是一个基于龙芯派平台开发的人脸识别智能物联网抽纸机嵌入式项目&#xff0c;面向单片机与嵌入式初学者、高校毕设/课设学生及物联网竞赛参赛者&#xff0c;解决从硬件感知、图像识别到机电联动控制的完整闭环设计问题。压缩包共153个文件&#xff0c;含…

作者头像 李华
网站建设 2026/9/16 14:56:44

STM32+MQ-7一氧化碳检测系统:从ADC采集到OLED显示与串口上报

简介&#xff1a;一套基于 STM32F10x 系列单片机与 MQ-7 一氧化碳传感器的环境监测项目源代码&#xff0c;面向嵌入式初学者与电子设计爱好者&#xff0c;旨在实现一氧化碳浓度的实时采集、本地显示、超标报警与数据上报。项目中&#xff0c;STM32 通过 ADC 模块读取 MQ-7 输出…

作者头像 李华
网站建设 2026/9/16 14:56:05

ZTP-148SRC1与R7KA8D2KFLCAC非接触测温实战指南

1. 项目概述&#xff1a;非接触式表面温度测量的实战落地路径ZTP-148SRC1 和 R7KA8D2KFLCAC 这两个器件组合&#xff0c;本质上是在构建一个高性价比、可嵌入、免校准的红外热电堆温度传感系统。它不依赖激光测距或光学聚焦镜头&#xff0c;而是通过热电堆传感器直接捕获目标物…

作者头像 李华
网站建设 2026/9/16 14:55:35

OpenMV+STM32智能车闭环控制系统设计与实现

简介&#xff1a;本资源是南京航空航天大学电子设计竞赛校赛‘自动泊车’题目的完整实现方案&#xff0c;面向嵌入式初学者与课程设计、毕设、工程实训学习者&#xff0c;提供从机器视觉识别到运动控制的端到端技术闭环。资源包含基于STM32F103主控的Keil工程&#xff08;含34个…

作者头像 李华
网站建设 2026/9/16 14:55:23

US Economic State Analysis

US Economic State Analysis 【免费下载链接】LifeOS ⛰️ The Life Operating System — an intent engineering platform that moves you from your current state to your ideal state, in life and work. 项目地址: https://gitcode.com/GitHub_Trending/pe/LifeOS …

作者头像 李华