大家好!在前 22 篇中,我们用蓝牙 BLE 实现了短距离无线通信,但当设备需要跨区域、长距离传输数据(如户外气象站、远程水表)时,BLE 的 100 米通信范围完全无法满足需求。而NB-IoT(Narrow Band Internet of Things,窄带物联网) 作为广域物联网技术,依托运营商蜂窝网络(2G/4G/5G),可实现 “无距离限制” 的数据传输,且功耗仅略高于 BLE,是电池供电广域设备的首选。这一篇我们将从 NB-IoT 的核心原理讲起,详解 STM32 与 NB-IoT 模块(BC26)的通信配置,通过 “温湿度数据上传至阿里云 IoT 平台” 的实操,让你掌握 “本地采集→广域传输→云端监控” 的完整物联网开发流程。
一、什么是 NB-IoT?用 “手机信号” 理解核心逻辑
NB-IoT 是基于运营商蜂窝网络的低功耗广域通信技术,本质是 “专为物联网优化的窄带通信协议”,就像 “轻量化手机通信”:
设备端(STM32+NB-IoT 模块):像 “极简手机”,仅保留数据传输功能,不支持语音 / 视频,通过 SIM 卡接入运营商网络;网络端(运营商基站):像 “信号塔”,接收设备发送的数据,转发至互联网;云端(IoT 平台):像 “数据中心”,接收、存储、展示设备上传的数据(如阿里云、腾讯云),支持远程查看与控制;低功耗关键:采用 “PSM(省电模式)” 和 “eDRX(扩展不连续接收)” 技术 —— 设备上传数据后立即进入深度休眠,仅按预设周期(如 1 小时)唤醒联网,待机电流可低至 μA 级。
NB-IoT 与蓝牙 BLE 的核心差异:
| 特性 | NB-IoT(广域) | 蓝牙 BLE(短距) |
|---|---|---|
| 通信距离 | 无限制(依托运营商网络) | 10~100 米(视距) |
| 功耗 | 低(PSM 模式≈5μA,传输≈50mA) | 极低(休眠≈10μA,传输≈10mA) |
| 网络依赖 | 需运营商 SIM 卡与基站信号 | 无需网络,直接点对点 |
| 数据速率 | 极低(上行最高 62.5kbps) | 低(最高 2Mbps) |
| 适用场景 | 远程监控(如农田、管网) | 近距离交互(如手机连传感器) |
二、NB-IoT 通信的核心流程:从设备到云端
NB-IoT 设备上传数据的完整流程分为 “联网→认证→数据上传→休眠” 四步,核心依赖 “AT 指令” 控制模块,关键概念如下:
1. 核心组件与依赖
NB-IoT 模块:如移远 BC26,集成基带与射频,通过 UART 与 STM32 通信,需插入运营商 NB-IoT 专用 SIM 卡(支持 NB 网络,年费低至几元);IoT 云平台:如阿里云 IoT、华为云 IoT,提供设备接入、数据存储、可视化界面,需为设备创建 “产品” 与 “设备”,获取唯一 “设备三元组”(ProductKey、DeviceName、DeviceSecret)用于身份认证;通信协议:NB-IoT 设备与云端通常采用 “MQTT 协议”(轻量级、低带宽),模块内置 MQTT 客户端,无需 STM32 手动实现复杂协议栈。
2. 核心通信流程(以 BC26 + 阿里云为例)
模块上电初始化:STM32 通过 UART 发送 AT 指令,初始化 BC26(如设置频段、检查 SIM 卡);接入运营商网络:BC26 搜索并注册到 NB-IoT 网络,获取 IP 地址(需确保有基站信号);云端身份认证:使用设备三元组,通过 MQTT 协议连接阿里云 IoT 平台,认证通过后建立稳定连接;数据上传:STM32 将采集的温湿度数据封装为 JSON 格式,通过 AT 指令发送给 BC26,模块转发至云端;进入低功耗模式:上传完成后,BC26 进入 PSM 模式,STM32 进入停止模式,按预设周期(如 1 小时)唤醒重复流程。
三、实操:STM32+BC26 实现温湿度上传阿里云 IoT
我们基于第 22 篇的低功耗框架,替换 BLE 模块为 NB-IoT 模块(BC26),实现功能:
STM32 采集温湿度数据,通过 UART 控制 BC26 接入 NB 网络;BC26 连接阿里云 IoT 平台,完成身份认证;将温湿度数据以 JSON 格式上传至云端;上传完成后,BC26 进入 PSM 模式,STM32 进入停止模式,1 小时后唤醒重复流程。
1. 硬件准备与连接
| 硬件 | 型号 / 规格 | 连接方式(STM32→NB 模块) | 作用 |
|---|---|---|---|
| STM32F103C8T6 | – | – | 主控制器,采集温湿度 |
| NB-IoT 模块 | 移远 BC26(UART 接口) | TX→PA10(USART1_RX),RX→PA9(USART1_TX),VCC→3.3V,GND→GND,PWR_KEY→PB0 | 广域数据传输,需插 NB SIM 卡 |
| 温湿度传感器 | SHT30(I2C) | SCL→PB6,SDA→PB7 | 采集温湿度数据 |
| 锂电池 | 18650(3.7V/2000mAh) | 经 LDO 稳压至 3.3V,供电给 STM32 与 BC26 | 续航更长,适合户外使用 |
2. 云端准备(阿里云 IoT 平台配置)
创建产品与设备:
登录阿里云 IoT 平台,进入 “设备管理→产品”,创建 “自定义产品”,通信方式选择 “NB-IoT”,数据格式选择 “JSON”;进入产品详情,点击 “设备→添加设备”,创建一个设备,记录生成的 “设备三元组”(ProductKey、DeviceName、DeviceSecret),用于模块认证。
创建数据解析模板(可选):
在产品详情的 “数据解析” 中,创建解析脚本,将设备上传的 JSON 数据(如)映射为平台可识别的 “温度”“湿度” 字段,便于后续可视化。
{"temp":25.5,"humi":60.2}
3. STM32 配置步骤(STM32CubeIDE)
步骤 1:配置 USART1(与 BC26 通信)
模式:异步模式,波特率 9600(BC26 默认波特率),8N1,引脚 PA9(TX)、PA10(RX);使能 USART 接收中断(用于接收 BC26 的 AT 指令响应,避免轮询占用 CPU)。
步骤 2:配置低功耗与定时唤醒
保留 RTC 定时唤醒配置,将唤醒周期改为 3600 秒(1 小时,减少联网次数降低功耗);保留 STM32 停止模式配置,确保休眠时功耗≈50μA。
步骤 3:生成代码
点击 “Generate Code”,自动生成 USART1、RTC、GPIO 的初始化代码。
4. 编写 NB-IoT 通信代码(核心:AT 指令控制 BC26)
(1)BC26 初始化与联网函数(nb_iot.c)
#include "nb_iot.h"
#include "usart.h"
#include "string.h"
#include "delay.h"
extern UART_HandleTypeDef huart1;
char uart_rx_buf[256]; // USART接收缓冲区
uint16_t uart_rx_len = 0;
// 发送AT指令并等待响应(timeout:超时时间ms)
uint8_t NB_Send_AT_CMD(char *cmd, char *resp, uint32_t timeout)
{
memset(uart_rx_buf, 0, sizeof(uart_rx_buf));
uart_rx_len = 0;
// 发送AT指令
HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 100);
HAL_UART_Transmit(&huart1, (uint8_t*)"
", 2, 100);
// 等待响应
uint32_t start_time = HAL_GetTick();
while (HAL_GetTick() - start_time < timeout)
{
if (strstr(uart_rx_buf, resp) != NULL)
{
return 0; // 收到预期响应,成功
}
}
return 1; // 超时,失败
}
// BC26初始化:检查SIM卡、注册网络
uint8_t BC26_Init(void)
{
// 1. 模块上电(拉低PWR_KEY引脚1秒,触发开机)
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);
HAL_Delay(5000); // 等待模块启动
// 2. 检查模块是否响应(发送AT,预期响应OK)
if (NB_Send_AT_CMD("AT", "OK", 3000) != 0)
{
printf("BC26模块无响应!
");
return 1;
}
// 3. 检查SIM卡状态(预期响应SIM OK)
if (NB_Send_AT_CMD("AT+CPIN?", "SIM OK", 5000) != 0)
{
printf("SIM卡异常!
");
return 1;
}
// 4. 注册NB网络(预期响应+CGREG: 0,1或0,5,表示注册成功)
if (NB_Send_AT_CMD("AT+CGREG?", "+CGREG: 0,1", 30000) != 0 &&
NB_Send_AT_CMD("AT+CGREG?", "+CGREG: 0,5", 10000) != 0)
{
printf("NB网络注册失败!
");
return 1;
}
printf("NB网络注册成功!
");
return 0;
}
// 连接阿里云IoT平台(使用设备三元组)
uint8_t BC26_Connect_AliIoT(char *product_key, char *device_name, char *device_secret)
{
char cmd[128];
// 1. 设置MQTT服务器地址(阿里云IoT地址:${product_key}.iot-as-mqtt.cn-shanghai.aliyuncs.com:1883)
sprintf(cmd, "AT+QMTCFG="broker",0,"%s.iot-as-mqtt.cn-shanghai.aliyuncs.com",1883,0,0", product_key);
if (NB_Send_AT_CMD(cmd, "OK", 5000) != 0) return 1;
// 2. 设置设备认证信息(ClientID格式:${device_name}|securemode=3,signmethod=hmacsha1|)
sprintf(cmd, "AT+QMTCFG="clientid",0,"%s|securemode=3,signmethod=hmacsha1|"", device_name);
if (NB_Send_AT_CMD(cmd, "OK", 5000) != 0) return 1;
// 3. 计算MQTT密码(需提前通过阿里云算法生成,此处简化用示例密码)
char password[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; // 实际项目需动态计算
// 4. 连接MQTT服务器(用户名:${device_name}&${product_key},密码:上述password)
sprintf(cmd, "AT+QMTCONN=0,"%s&%s","%s"", device_name, product_key, password);
if (NB_Send_AT_CMD(cmd, "+QMTCONN: 0,0,0", 10000) != 0) // 响应0,0,0表示连接成功
{
printf("阿里云连接失败!
");
return 1;
}
printf("阿里云连接成功!
");
return 0;
}
// 上传温湿度数据到阿里云(topic:/sys/${product_key}/${device_name}/thing/event/property/post)
uint8_t BC26_Upload_Data(char *product_key, char *device_name, float temp, float humi)
{
char cmd[256];
char topic[128];
char payload[64];
// 1. 构建阿里云数据上传topic
sprintf(topic, "/sys/%s/%s/thing/event/property/post", product_key, device_name);
// 2. 构建JSON payload(符合阿里云物模型格式)
sprintf(payload, "{"params":{"temp":%.1f,"humi":%.1f}}", temp, humi);
// 3. 发送MQTT消息(AT+QMTPUB=客户端号,消息ID,QoS,是否保留,topic, payload长度,payload)
sprintf(cmd, "AT+QMTPUB=0,1,0,0,"%s",%d,"%s"", topic, strlen(payload), payload);
if (NB_Send_AT_CMD(cmd, "+QMTPUB: 0,1,0", 10000) != 0) // 响应0,1,0表示发送成功
{
printf("数据上传失败!
");
return 1;
}
printf("数据上传成功:%s
", payload);
return 0;
}
// BC26进入PSM模式(低功耗)
void BC26_Enter_PSM(void)
{
// 发送AT指令设置PSM参数,上传完成后立即进入PSM
NB_Send_AT_CMD("AT+CPSMS=1,,,0,3600", "OK", 5000); // 3600秒后唤醒
NB_Send_AT_CMD("AT+QPOWD=1", "OK", 3000); // 触发PSM休眠
}
// USART1接收中断回调(存储BC26响应)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1)
{
uart_rx_buf[uart_rx_len++] = huart->Instance->DR;
if (uart_rx_len >= sizeof(uart_rx_buf)-1) uart_rx_len = 0;
// 重新启动接收中断
HAL_UART_Receive_IT(&huart1, (uint8_t*)&uart_rx_buf[uart_rx_len], 1);
}
}
(2)主程序逻辑(main.c)
#include "main.h"
#include "nb_iot.h"
#include "sht30.h"
#include "rtc.h"
#include "power.h"
// 阿里云设备三元组(替换为自己的实际信息)
char PRODUCT_KEY[] = "a1XXXXXXXXXX";
char DEVICE_NAME[] = "STM32_NB_Device";
char DEVICE_SECRET[] = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
float temp, humi;
int main(void)
{
HAL_Init();
SystemClock_Config();
// 初始化外设
MX_GPIO_Init();
MX_USART1_Init();
MX_I2C1_Init();
MX_RTC_Init();
// 启动USART1接收中断
HAL_UART_Receive_IT(&huart1, (uint8_t*)uart_rx_buf, 1);
// 初始化RTC(1小时唤醒一次)
RTC_Alarm_Init(3600);
while (1)
{
// 1. 初始化BC26并连接NB网络
if (BC26_Init() != 0)
{
goto LOW_POWER; // 初始化失败,直接进入低功耗
}
// 2. 连接阿里云IoT平台
if (BC26_Connect_AliIoT(PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET) != 0)
{
goto LOW_POWER;
}
// 3. 采集温湿度数据
SHT30_Read_Data(&temp, &humi);
printf("采集数据:Temp=%.1f℃, Humi=%.1f%%
", temp, humi);
// 4. 上传数据到阿里云
BC26_Upload_Data(PRODUCT_KEY, DEVICE_NAME, temp, humi);
LOW_POWER:
// 5. 进入低功耗:BC26 PSM + STM32停止模式
BC26_Enter_PSM();
Enter_Stop_Mode(); // 1小时后被RTC唤醒,重复循环
}
}
5. 云端验证(阿里云 IoT 平台)
登录阿里云 IoT 平台,进入 “设备管理→设备”,找到已创建的设备,查看 “运行状态”;设备上传数据后,在 “物模型数据” 页面可实时看到 “温度”“湿度” 字段的最新值;进入 “数据日志” 页面,可查看历史上传记录,验证数据传输的连续性与准确性。
6. 功耗与续航验证
工作阶段(1 小时内的 60 秒):BC26 开机 + 联网 + 上传,功耗≈50mA(持续 60 秒);低功耗阶段(1 小时内的 3540 秒):BC26 PSM 模式(≈5μA)+ STM32 停止模式(≈50μA),总功耗≈55μA;平均功耗:≈(50mA×60s + 55μA×3540s)/3600s ≈ 0.84mA;续航估算:18650 锂电池(2000mAh)续航≈2000mAh / 0.84mA ≈ 2381 小时 ≈ 99 天(满足户外设备 3 个月续航需求)。
四、NB-IoT 通信常见问题与调试技巧
模块无响应(AT 指令不回 OK)?
供电不足:BC26 启动时峰值电流达 200mA,需确保电源(如锂电池 + LDO)能提供足够电流,避免电压跌落;PWR_KEY 引脚操作错误:开机需拉低 PWR_KEY 1 秒以上,若仅拉低几十 ms,模块无法正常启动;波特率不匹配:BC26 默认波特率 9600,若修改过需重新配置 STM32 的 USART 波特率(可通过硬件复位模块恢复默认)。
NB 网络注册失败(+CGREG: 0,2)?
SIM 卡问题:确认是 NB-IoT 专用 SIM 卡,且已激活、有流量(可插入手机查看是否有信号);信号问题:户外或靠近窗户测试,室内信号弱可能导致注册失败;可通过 AT 指令查看信号强度(AT+CSQ,返回值≥10 表示信号良好);频段不匹配:不同地区运营商 NB 频段不同(如中国电信常用 B5/B8),需通过 AT 指令设置正确频段(AT+QCFG=”band”,0,80000000,1,开启 B5/B8)。
阿里云连接失败(+QMTCONN: 0,1,4)?
三元组错误:确认 ProductKey、DeviceName、DeviceSecret 与阿里云平台完全一致(区分大小写,无空格);密码计算错误:阿里云 MQTT 密码需通过 “device_name+product_key+device_secret” 按 hmacsha1 算法生成,不可硬编码示例值(实际项目需在 STM32 中实现算法);服务器地址错误:确认 MQTT 服务器地址格式为 “${product_key}.iot-as-mqtt.cn-shanghai.aliyuncs.com”,端口 1883。
五、第 23 篇总结与下一篇预告
总结
这一篇我们掌握了 NB-IoT 广域通信的核心:
NB-IoT 依托运营商网络实现无距离限制传输,通过 PSM 模式保障低功耗,适合户外远程设备;开发关键是通过 AT 指令控制 NB 模块(BC26)完成 “联网→认证→上传”,无需手动实现复杂协议;实操中实现了 “本地采集→云端上传→远程监控” 的完整物联网链路,平均功耗≈0.84mA,续航达 3 个月,满足户外设备需求。


















暂无评论内容