ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32+BC20 NB-IoT终端接入OneNET:温湿度/ADC/GPS数据采集上云实战

STM32+BC20 NB-IoT终端接入OneNET:温湿度/ADC/GPS数据采集上云实战 这套方案我调了将近两周期间把 BC20 的 AT 指令手册翻了好几遍也在 OneNET 平台和设备之间来回折腾了几次。最后跑通的状态是STM32L151RCT6 按周期采集 DHT11 温湿度、一路 ADC 模拟量、BC20 输出的 GPS 定位数据打包成 JSON 通过 NB-IoT 上传到新版 OneNET 平台页面端能看到实时数据曲线。把这些东西从零到一完整梳理一遍给计划做环境监测、冷链运输、共享设备定位或者农业物联网终端的朋友做个参考。项目本身不算复杂但涉及的东西却不少传感器时序、ADC 滤波、NB-IoT 入网、MQTT 上报、NMEA 解析、OneNET 设备建模。更关键的是这里面几乎每一个环节都有容易踩的坑。所以我尽量按为什么这么选、硬件怎么接、代码怎么写、出了问题怎么查的顺序来写尽量做到不需要再去翻一堆零散资料也能复现整个项目。1. 项目怎么拼选型思路与整体框架解析1.1 为什么用 STM32L151RCT6 来做主控先说说主控。很多人看到温湿度 GPS 上云第一反应就是 STM32F103C8T6便宜、资料多、随便搜都是例程。但为什么我这次选了 STM32L151RCT6核心原因是功耗和存储两者都要兼顾。STM32L151 属于 ST 的超低功耗系列Cortex-M3 内核主频不高但功耗控制是重点。它有多种低功耗模式Stop 模式电流可以做到微安级别非常适合电池供电的 NB-IoT 终端。NB-IoT 的一个典型使用场景就是一次上报几 KB 数据然后睡觉主控本身耗电大的话整个设备续航会很难看。相比之下F103 的长处在性能和外设丰富度单纯做低功耗数据采集反而有点浪费。内存方面我选的这块是 R 系列 100 引脚封装Flash 256KB、SRAM 32KB还带 8KB 真正的 EEPROM。做协议栈解析、存储设备参数、缓存待上报数据都比较从容。如果换用 F103C8T620KB RAM 就能明显感觉到紧张尤其是以后想在本地加 OLED 显示、存储历史记录的时候。当然用 L151 也有代价网上的资料明显比 F103 少STMCubeMX 配置完主要功能之后很多细节还是要看参考手册 REV 和低功耗系列的独特特性。但如果你的项目定位是长期无人值守 电池供电L151 这类超低功耗主控就是更合理的选择。1.2 BC20NB-IoT 和 GPS 二合一省掉一堆麻烦BC20 是移远通信的一款 NB-IoT 模组最大的亮点是同时集成了 NB-IoT 通信和 GNSS 定位功能。传统的 NB-IoT 方案要另外挂一个 GPS 模块多一个器件、多一路串口、多一份调试工作量功耗和体积也跟着上去了。BC20 直接用一个模组搞定两件事通过 AT 指令控制和读取对电路设计和软件编写都友好很多。另一个好处是 BC20 使用的是标准 AT 指令体系有 Quectel 风格的扩展指令。只要你接触过其他移远模组比如 EC20、BC26上手 BC20 会很快。NB-IoT 部分的入网流程、MQTT 建连发布消息都有对应指令GNSS 部分也有独立的指令组定位数据的获取可以直接用ATQGPSLOC?这类查询指令不用自己去解析模组输出的 NMEA 串口数据流开发量瞬间小了不少。有一点要提前说BC20 工作频段和服务由运营商网络决定买模组之前先确认你所在区域 NB-IoT 网络覆盖情况以及用的 SIM 卡是否开通了 NB-IoT 业务套餐。很多人代码写好了平台配置也对了最后卡在模块一直没入网大概率就是卡的问题或覆盖问题。1.3 DHT11 加 ADC低成本的本地感知组合DHT11 这传感器说句实话精度和响应速度都很一般测温度误差±2℃湿度误差±5%而且至少间隔 1 秒才能读一次。但为什么还要用它便宜、稳定、资料多、接线简单。做原理验证、低成本环境监测完全够了。如果项目对精度要求高比如医疗冷链、药品运输那应该换 SHT30 这类数字传感器接口逻辑也能复用就是价格贵一些。ADC 通道则是给模拟量留的。很多环境监测终端除了温湿度还会采集土壤湿度、光敏电阻、电池电压等信号。这些都是典型的模拟电压输出用 STM32L151 自带的 12 位 ADC 就能解决。我这次设计时专门把电池电压采样接进 ADC同时留了一路模拟输入给外部传感器。这样既能看到设备供电状态也能验证整条模拟链路。1.4 数据出口OneNET 平台的接入逻辑OneNET 是中国移动推出的物联网开放平台目前控制台已经全面转向新版OneNET Studio。相比旧版新版把产品-设备-物模型这套体系做得更清晰。在平台上先创建产品选择接入协议然后定义物模型属性比如温度、湿度、电压、经纬度再创建具体设备拿到设备鉴权信息设备侧通过 MQTT 接入并上报属性数据平台就能在控制台看到实时数据、历史曲线也能做告警规则。选择 OneNET 而不是自建服务器主要原因是省事不需要自己买服务器、维护 MQTT Broker、写数据存储接口。对于中小型物联网项目尤其是设备数量不算特别多的情况直接用好平台是性价比最高的路。平台的接入文档一直在更新写这一篇的时候新版控制台是主流我后面给的示例参数结构可以参考但具体 topic 和鉴权字段以你登录平台时看到的最新文档为准这点务必留意。2. 硬件连接与电路设计从传感器到模块的每一根线2.1 DHT11 接线图例与电平注意DHT11 是单总线器件VCC、GND、DATA 三根线DATA 引脚必须接上拉电阻到 VDD阻值 4.7kΩ 到 10kΩ 之间都可以。上拉电阻是必须的不是可选项——没有上拉电阻或者上拉太弱DHT11 拉低电平的时候还能凑合拉高电平的时候上升沿太慢很容易导致主控采样读到错误的高电平时序。DHT11 的数据线直接连到 STM32 的 GPIO我用的 PA0配置为开漏输出加外部上拉。开漏输出配合上拉电阻这是单总线通信的标准接法因为总线需要线与逻辑主机和传感器都能把数据线拉低平时由外部上拉维持高电平。VCC 我接了 3.3VDHT11 的供电范围比较宽3.3V 或 5V 都能工作但为了和主控电平一致3.3V 更省事。从嘉立创画板的角度建议 DHT11 尽量靠近主控引脚放数据线走线不要超过 10cm不要跨分割区域或者贴近功率器件。这种低速单总线对走线要求不算苛刻但工程里遇到过几次因为走线太长、寄生电容太大导致读取失败的案例板子空间允许的话稍微注意一下没坏处。2.2 ADC 采集通道的输入电路设计ADC 输入不能直接怼到传感器上要根据信号电压范围做调理。我这次分了两路一路是电池电压采样。锂电池标称 3.7V满电 4.2V直接超过 STM32 的 3.3V 参考电压必须分压。我用两个 100kΩ 电阻串联从电池正极到地中点接 ADC 输入。这样 ADC 引脚电压是电池电压的一半最高约 2.1V留了保护余量。另外一路是外部模拟信号输入比如土壤湿度探头输出范围假设是 0 到 3V 左右那就可以用跟随器或者直接分压进入 ADC。ADC 输入引脚前面建议加一个 100nF 去耦电容到地和输入电阻构成低通滤波器滤掉高频噪声。这个电容会引起 ADC 采样建立时间变长但对慢速传感器完全没影响。我习惯再加一个 1kΩ 串联电阻起到限流作用防止意外短路损坏引脚。STM32L151 的 ADC 是 12 位参考电压就是 VDDA一般接 3.3V理论分辨率大约 0.8mV。注意 VDDA 和 VREF 引脚要加高质量去耦电容如果片内基准或 VREF 不稳定ADC 结果会跟着漂。我量电池电压时会在程序里先用万用表实测分压点电压去校准 ADC 计算系数而不是完全依赖理论分压值。2.3 BC20 周边电路SIM 卡、天线与串口电平BC20 周边电路需要重点关注四个部分第一UART 接口。BC20 的主串口和 STM32 的 USART2 对接。BC20 的逻辑电平是 1.8V 还是 3.3V 要看具体封装和手册我这一版模组的 VDD_EXT 输出可以给电平参考需要做电平匹配。如果两者电平不匹配回传的数据会是乱码或者直接没反应。常见做法是通过电平转换芯片比如 TXS0108或者用 MOSFET 电平转换电路。很多开发板上已经集成了电平转换直接查你手里的板子原理图最靠谱。第二SIM 卡。BC20 用的是标准 nano SIM 卡座SIM_VCC、SIM_DATA、SIM_CLK、SIM_RST 四根线SIM_DATA 线上需要串联 22Ω 电阻并加上 ESD 保护器件。卡座尽量靠近模组走线不要太长信号线不要并行太长距离否则 SIM 卡识别会不稳定。第三天线。BC20 有 RF 天线引脚用于 NB-IoT另外有 GNSS 天线引脚。两套天线不能共用。NB-IoT 天线用 50Ω 阻抗走线GPS 天线建议用有源陶瓷天线需要从模组的 GNSS 天线馈电引脚提供 2.8V 或 3.3V 电源。天线离主控和开关电源远一点否则 GPS 信号容易被干扰。第四电源。BC20 发射时候的峰值电流能到 2A 左右虽然持续时间很短但对电源的瞬态响应要求很高。不能用 LDO 直接硬扛最好在模块电源引脚附近放一个大容量钽电容或者陶瓷电容组合比如 100μF 100nF。主控和模组电源可以用同一个 3.8V 到 4.2V 的输入然后分别 LDO 或 DCDC 稳压。我实际用的是一节锂电池直接供给 BC20 的 VBAT再通过一颗 3.3V LDO 供给 STM32 和传感器这样最省电。2.4 电源与整体供电框架整体供电结构就比较清晰了锂电池或者 5V 适配器进来BC20 直接吃锂电池电压范围3.4V~4.3VSTM32 和 DHT11 由 3.3V LDO 供电。L151 的 Stop 模式配合 BC20 的 PSM 省电模式系统多数时间处于极低功耗状态只有定时采集和上报的时候才唤醒。这也是为什么整套系统在野外或者移动设备上有实用价值——待机电流可以做到几十微安甚至更低两节电池撑几个月不是问题。这里提醒一下BC20 在开机和发射时电流突变大如果把模组和主控共用同一颗 LDO主控可能在模组发射瞬间掉电复位。实际操作中我至少保证了 BC20 的 VBAT 不在 3.3V LDO 后面取电而是直接从电池或者输入电源接稳压留给主控这边用。3. 软件实现驱动、协议与上云全过程3.1 CubeMX 配置要点引脚、时钟与串口软件我基于 STM32CubeMX 生成 HAL 库工程版本按你当前用的 CubeMX 和固件包选即可。需要配置的模块包括GPIODHT11 数据引脚PA0配置为开漏输出、无上拉ADC 输入引脚配置为模拟输入。USART2接 BC20波特率 9600BC20 默认常用 9600也可以按模组设置为 115200反正 AT 初始化里可以同步8 位数据、无校验、1 停止位。ADC1一个通道、单次转换模式采样周期设置到最大或者接近最大后面说原因。一个基本定时器或者 SysTick 做超时和周期管理。RTC如果设备需要本地上报时间戳用 RTC 来维护本地时间OneNET 平台也会根据上报时间生成数据记录不依赖本地时间也能显示。时钟树的配置建议让系统时钟跑到最高主频同时注意 ADC 时钟不要超过数据手册的限制。STM32L151 的 ADC 时钟最高和 APB 时钟有一定关系用 CubeMX 配置时它会自动帮你检查分频系数直接看生成结果即可。一个容易被忽略的细节USART2 的中断优先级和 GPS 数据接收方式。BC20 有两种工作模式一种是模组主动通过 AT 指令告诉你定位结果一种是模组直接把 GNSS 定位语句通过串口吐出来。我建议用查询式的指令方式也就是主控周期发ATQGPSLOC?去拿定位数据这样串口接收逻辑最简单不容易因为串口数据流堆积导致内存溢出。3.2 手撕 DHT11 驱动时序、校验与代码DHT11 的通信协议不复杂但时序是硬性的。读一次数据分这么几步注意DHT11 两次读取间隔必须大于 1 秒。读太频繁传感器会不响应表现为一直拉高读不到起始位。这是刚接触 DHT11 时最容易踩的坑。主机先拉低数据线至少 18ms再释放并延时 20~40us此时传感器开始响应先把总线拉低约 80us再拉高约 80us然后输出 40 位数据。每一位数据都是一个约 50us 的低电平紧跟一个高电平。高电平持续 26~28us 表示0持续约 70us 表示1。最后传感器再把总线拉低 50us 表示结束。读取的关键是怎么精确判断高电平的时长。如果直接在主循环里做死等延时很容易受中断影响导致数据错位。我第一次调的时候没关中断读出来的数据隔几次就错一次后来在主程序里读 DHT11 前关中断用 DWT 或者 SysTick 做微秒延时读完之后再开中断就稳定了。下面这段是核心读取代码基于 HAL 库GPIO 方向切换在读取前完成static uint8_t dht11_bit[40]; uint8_t DHT11_ReadData(uint8_t *temp, uint8_t *humi) { uint8_t buf[5] {0}; uint32_t timeout; // 主机起始信号 Set_DHT11_Output(); HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_RESET); HAL_Delay(20); HAL_GPIO_WritePin(DHT11_GPIO_Port, DHT11_Pin, GPIO_PIN_SET); Set_DHT11_Input(); DHT11_DelayUs(30); // 检查传感器响应先拉低 80us 再拉高 80us if (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET) { return 0; // 传感器无响应 } timeout 1000; while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_RESET) { if (--timeout 0) return 0; DHT11_DelayUs(1); } timeout 1000; while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET) { if (--timeout 0) return 0; DHT11_DelayUs(1); } // 读取40位数据 for (uint8_t i 0; i 40; i) { timeout 2000; while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_RESET) { if (--timeout 0) return 0; } DHT11_DelayUs(40); // 延时后再采样 if (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET) { dht11_bit[i] 1; } else { dht11_bit[i] 0; } timeout 2000; while (HAL_GPIO_ReadPin(DHT11_GPIO_Port, DHT11_Pin) GPIO_PIN_SET) { if (--timeout 0) return 0; } } // 拼字节 for (uint8_t i 0; i 5; i) { buf[i] 0; for (uint8_t j 0; j 8; j) { buf[i] 1; buf[i] | dht11_bit[i * 8 j]; } } // 校验和前4字节相加低8位等于第5字节 if ((uint8_t)(buf[0] buf[1] buf[2] buf[3]) ! buf[4]) { return 0; } *humi buf[0]; // 湿度整数部分 *temp buf[2]; // 温度整数部分 return 1; }这段代码里最需要解释的是读取一位数据的逻辑低电平结束后延时 40us 再读电平如果还是高说明是1如果已经变低说明是0。这和网上流传的统计高电平时长本质一样但实现更简单可靠。3.3 ADC 采集与滤波别让读数乱蹦ADC 采集的坑不多但读数抖动问题很常见。STM32L151 的 ADC 在采样周期太短时输入电容没有充分充电读出来的值会偏小而且不稳定。所以我配置 ADC 时把采样周期设成比较大的值比如 160.5 个 ADC 时钟周期慢是慢一点但精度和稳定性都好很多。对于环境监测这种慢速场景完全没必要追求高速采样。软件滤波方面我用的是多次采集取平均 剔除最大最小值的复合滤波。思路是连续采 10 次去掉一个最大值和一个最小值剩下 8 次取平均值。这个算法对毛刺干扰有很好的抑制效果又不会像滑动平均那样有明显滞后。uint16_t ADC_GetFilteredValue(void) { uint16_t samples[10]; uint16_t temp; uint32_t sum 0; for (uint8_t i 0; i 10; i) { HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 100); samples[i] HAL_ADC_GetValue(hadc1); HAL_ADC_Stop(hadc1); DHT11_DelayUs(500); } // 冒泡排序简单处理 for (uint8_t i 0; i 9; i) { for (uint8_t j 0; j 9 - i; j) { if (samples[j] samples[j 1]) { temp samples[j]; samples[j] samples[j 1]; samples[j 1] temp; } } } for (uint8_t i 1; i 9; i) { sum samples[i]; } return (uint16_t)(sum / 8); }换算物理量的时候ADC 值除以 4095 再乘以参考电压就是引脚电压值。如果是电池电压分压来的再乘回分压比例系数。我建议在代码里留一组校准系数宏比如#define VOLTAGE_REF 3.3f #define ADC_FULL_SCALE 4095.0f #define BATTERY_DIVIDER 2.0f // 分压系数 #define BATTERY_CAL 1.03f // 实测校准系数实际使用中电池从满电到电量低电压从 4.2V 逐渐降到 3.3V 左右。我们用 ADC 大概能分辨出几十毫伏的变化拿去预估剩余电量足够用了。3.4 BC20 入网与 MQTT 上报 OneNET 的 AT 指令链路BC20 的 NB-IoT 入网流程是标准的 AT 指令序列。我整理了一份实际调通的序列精简后如下ATI // 查询模组信息确认固件版本 ATCFUN1 // 设置全功能模式 ATCPIN? // 查询 SIM 卡状态应返回 READY ATCSQ // 查询信号强度返回数字越大越好 ATCGATT1 // 附着网络 ATCGATT? // 查询网络附着状态返回 1 表示已附着 ATCEREG? // 查询网络注册状态返回 0,1 或 0,5 表示已注册 ATCGDCONT1,IP,CMNBIOT // 设置 APNNB-IoT 常用 CMNBIOT这几条指令每一条都可能卡住。最常见的问题是ATCPIN?返回 ERROR表示 SIM 卡没放好或者卡座电路有问题ATCSQ返回CSQ: 99,99表示没有信号ATCEREG?长时间不是注册状态就要检查是不是 SIM 卡套餐没开通 NB-IoT 业务。入网成功以后就是 MQTT 连接。Quectel 模组用 QMT 指令组ATQMTCFGrecv/mode,0,0,0,1 ATQMTOPEN0,broker地址,1883 ATQMTCONN0,client_id,username,password ATQMTPUB0,0,0,0,topic,payload注意 broker 地址、client_id、用户名、密码怎么填完全取决于 OneNET 平台当前版本的接入要求。我这次用的新版 OneNET Studio需要先创建产品拿到产品 ID创建设备拿到设备名称和设备密钥然后按文档拼出 MQTT 参数。topic 是类似$sys/{产品ID}/{设备名}/thing/model/property/post这种结构payload 是 JSON 格式的属性上报数据比如{params:{temperature:{value:26.1},humidity:{value:60},voltage:{value:3.95},latitude:{value:31.10694},longitude:{value:121.38312}}}因为 OneNET 控制台版本迭代比较快我这里不写死细节参数关键是你要理解流程平台侧建产品、建物模型、建设备拿到鉴权信息设备侧通过 MQTT 标准协议接入上报格式和平台定义保持一致。整个流程通了以后平台侧就能看到数据。MQTT 上报之后最好是再做一下心跳保活。NB-IoT 模组在空闲时会进入省电状态服务器下发的数据可能延迟到达。如果你的应用需要平台随时能下发命令建议查询 BC20 的 PSM/DRX 配置指令按照你的实时性需求设置省电策略。3.5 GPS 定位数据获取与解析BC20 的 GPS 获取我用的指令方式。启动流程大致是ATQGPS1 // 开启 GNSS ATQGPSLOC? // 查询当前位置返回值里包含时间、经纬度、速度等ATQGPSLOC?返回的数据类似QGPSLOC: 064036.000,3106.4164,N,12119.9197,E,0.00,0.00,020723,,,1可以注意到经纬度并不是常见的十进制格式。纬度3106.4164,N表示 31 度 06.4164 分北纬经度12119.9197,E表示 121 度 19.9197 分东经。转成十进制公式是纬度 31 6.4164 / 60 31.10694经度 121 19.9197 / 60 121.331995OneNET 平台的经纬度物模型属性一般要求浮点数所以在代码里要写一个转换函数。我习惯先按字符串解析再转成浮点最后计算。这个转换不复杂但要记得做边界保护NMEA 数据偶尔会有字段为空的情况。float NMEA_To_Decimal(uint8_t *str, char dir) { float raw atof(str); uint16_t deg (uint16_t)(raw / 100); float min raw - deg * 100; float decimal deg min / 60.0f; if (dir S || dir W) { decimal -decimal; } return decimal; }GPS 定位要注意冷启动时间。首次开机如果模块没有星历数据搜索卫星可能需要 1 到 5 分钟甚至更久建议首次使用的时候在室外开阔环境耐心等一下。室内基本是定位不到的这是物理约束不是设备故障。定位成功后模块热启动就快多了每次查询基本一两秒内就能拿到数据。如果长期固定在一个位置GPS 数据每次变化很小你可以做一个小逻辑连续几次定位差值小于某个阈值就认为位置不变直接沿用上一次结果减少不必要的 AT 查询。3.6 数据打包与状态机设计整个软件流程如果都堆在主循环里顺序执行问题不大但为了扩展性更好我建议整理成一个简单的状态机状态 0进入低功耗休眠状态 1定时唤醒开启电源采集 DHT11 和 ADC状态 2查询 GPS状态 3启动 BC20 MQTT 连接上报数据状态 4断开 MQTTBC20 进入省电主控再进入休眠这个状态机的好处是每个环节都可以独立测试。比如只测传感器不启动 BC20只测 MQTT不查 GPS。出了问题能快速定位是哪个环节挂了。数据打包建议用 JSON。不要在裸机上自己手写复杂 JSON 库太浪费资源。常用做法是 sprintf 格式化char payload[256]; sprintf(payload, {\params\:{\temperature\:{\value\:%.1f},\humidity\:{\value\:%.1f}, \voltage\:{\value\:%.2f},\latitude\:{\value\:%.5f},\longitude\:{\value\:%.5f}}}, temp, humi, voltage, lat, lng);字符串缓冲区大小要留够我实测这个 payload 在 150 字节左右给 256 字节是安全的。发送前打印一遍 payload确认没有特殊字符输出异常。4. 调试记录踩过的坑和可直接抄的排查清单4.1 DHT11 读不到数据先量上拉和时序DHT11 读不到数据排查顺序基本固定第一确认上拉电阻存在且阻值正常。我用万用表量过不少坏模块最后发现是面包板接触不良导致事实上没有上拉。 第二确认 GPIO 方向切换正确。初始化是开漏输出读数据前切到输入模式这步错了时序全乱。 第三确认读取间隔大于 1 秒。老是连续读的话传感器会保持不响应这算它的自我保护机制。 第四确认微秒延时准确。HAL_Delay 是毫秒级的读 DHT11 不能用它做 40us 延时。用 DWT 或循环做延时的时候要结合编译优化等级校准我当时一开 O2 优化延时快了 20% 左右读数就开始不稳定。后来直接用 DWT 计数器做微秒延时优化等级无所谓了。4.2 BC20 注册网络慢、连不上平台怎么查BC20 的问题往往不是单一原因导致的。我整理了一个优先级排查顺序看指示灯或者ATCSQ信号值。如果99,99基本是没信号检查天线、SIM 卡、覆盖区。看ATCPIN?是否返回 READY。返回 ERROR检查卡座焊接和 SIM 卡触点。看ATCEREG?是否注册成功。一直没注册成功确认 SIM 卡开通了 NB-IoT 业务很多物联网卡默认没开通 NB-IoT 就得找运营商。如果入网正常但 MQTT 连不上检查 OneNET 平台参数是否一致。MQTT 的 client_id、username、password 有一个不对服务器直接断开连接。检查 BC20 和主控之间的波特率。BC20 出厂波特率和代码配置不一致AT 指令返回乱码表现也是连不上平台。开发过程中强烈建议先用 USB 转串口直接连 BC20在电脑上把 AT 指令链路全部跑通再让主控接管。这样可以先把网络和平台问题隔离掉再调主控和模组之间的通信。4.3 ADC 数值漂移与不准的常见原因ADC 读数漂移我见过几种典型场景一是参考电压不稳。VDDA 引脚纹波大或者 LDO 输出带载能力不足ADC 结果就会抖。解决方法是 VDDA 引脚加 1μF 和 100nF 电容组合并且尽量让模组和 ADC 的电源分开一点避免 NB-IoT 发射瞬间拉低 VDDA。二是采样周期太短。ADC 采样时间不足内部采样电容没有充到和外部输入电压一致读数会系统地偏小。用 CubeMX 把采样周期拉长会有立竿见影的效果。三是输入阻抗过大。分压电阻用到了 1MΩ 级别的话ADC 输入阻抗会显著影响测量结果读数偏低且输出能力弱。用 100kΩ 级别的电阻会更安全。四是软件滤波没做。如果只采一次直接换算数值跳动在 20~30 个 LSB 很正常加上上面说的复合滤波基本就平稳了。4.4 OneNET 平台上没数据核对这三处如果你代码里面 MQTT 连接成功AT 指令也返回 OK但平台上就是不见数据优先核对物模型标识符是否一致。平台定义的属性标识符是temperature代码里就必须用temperature写成temp平台直接忽略而且不会报错最坑的是模组端一切正常数据也发出去了。topic 路径是否正确。新版 OneNET 的物模型上报 topic 有固定前缀$sys别少了一个$或者把产品 ID 和设备名写反。payload 格式是否正确。属性上报要求外层是params每个属性值是对象如果你直接发{temperature: 26.1}平台不会认。建议在调试阶段把 payload 通过模组日志打印出来人工比对 JSON 结构再结合平台设备日志看有没有收到数据。OneNET 控制台设备详情页通常有通信日志能直接看到设备上行的原始报文这个功能非常有用。4.5 GPS 不定位怎么办GPS 不定位的排查要点天线是否接好BC20 的 GNSS 天线接口和 NB 天线接口容易接反反正外观差不多但结果就是一个能入网一个永远定不了位。是否在室外室内窗户旁边偶尔能定位但也可能完全定不了拿到空旷地方测试是最直接的判断方法。冷启动时间首次定位请留 2 分钟以上不要刚发完ATQGPS1就急着查询。模块是否输出有效状态ATQGPSLOC?返回的数据里有一个状态位我遇到过程序解析到空数据实际上是没有定位成功这时候要加返回码判断而不是拿空数据去转换。最后再啰嗦两句我的体会东西都调完之后回头看整个项目最大的感触是这个方案的所有模块单独拿出来都是标准的、有手册可查的难的是把它们组合在一起并且在每个环节预留排查手段。我建议你如果准备复现这个项目一步一步来先用串口助手单独验证 BC20 的 AT 指令和 OneNET 平台再写主控程序去控制模组最后才往上报频率、低功耗这些方向去优化。另外调试阶段一定把所有串口打印都打开尤其是 DHT11 读取结果、ADC 原始值、MQTT 返回码、GPS 原始 NMEA 字符串这些打印信息是排查问题最重要的线索省掉它们只会让你在排错时候多浪费几倍时间。这套架构后续扩展空间也比较大比如出现场 STM32 换 STM32U5 进一步降功耗、增加 SHT30 传感器、在 OneNET 平台配告警规则、甚至接多台设备做统一管理都是顺手的事关键是把第一版跑通有了稳定可靠的数据链路后面的一切才有基础。
返回列表