1. 项目概述
这个基于STM32L151RCT6微控制器的物联网终端项目,实现了环境温湿度采集(DHT11)、GPS定位数据获取以及模拟量采集(ADC)功能,并通过BC20 NB-IoT模块将数据上传至最新版OneNET物联网平台。整套系统特别适合户外环境监测、物流追踪等需要低功耗远程数据传输的场景。
我在实际部署中发现,STM32L151RCT6的低功耗特性与BC20模块的组合,在保持每月传输2000次数据的情况下,仅需3000mAh锂电池就能持续工作6-8个月。这种组合既满足了户外设备对能耗的严苛要求,又保证了数据的可靠传输。
2. 硬件系统设计
2.1 核心器件选型
主控芯片选择:
STM32L151RCT6是ST的Cortex-M3低功耗系列MCU,具有:
- 256KB Flash + 32KB RAM
- 运行功耗仅170μA/MHz
- 停止模式电流低至0.4μA
- 内置12位ADC和多路USART
选择这款芯片主要考虑:
- 充足的IO接口可同时连接DHT11、GPS和ADC
- 低功耗特性适合电池供电场景
- 成本控制在项目预算范围内
通信模块选型:
BC20是移远推出的NB-IoT模块,优势包括:
- 支持Band5/Band8频段
- 最大下行速率62.5kbps
- 待机电流仅1μA
- 内置GNSS定位功能(本项目未使用)
注意:BC20模块需要单独供电(3.4-4.2V),不能直接使用STM32的3.3V输出
2.2 传感器接口设计
DHT11温湿度传感器:
- 单总线协议,连接至PC0引脚
- 需外接4.7K上拉电阻
- 典型响应时间2s
GPS模块:
- 选用ublox NEO-6M模块
- 通过USART2连接(PA2/PA3)
- 波特率默认9600bps
ADC采集:
- 使用STM32内置ADC1
- 通道0(PA0)连接电位器
- 12位分辨率,参考电压3.3V
3. 软件实现细节
3.1 开发环境搭建
- 安装Keil MDK 5.25
- 导入STM32L1xx HAL库
- 配置工程选项:
- 目标设备:STM32L151RC
- 时钟源:HSI 16MHz
- 优化等级:-O2
c复制// 系统时钟配置示例
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 配置HSI作为系统时钟源
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
// 配置时钟树
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}
3.2 传感器驱动实现
DHT11数据采集:
c复制#define DHT11_PIN GPIO_PIN_0
#define DHT11_PORT GPIOC
uint8_t DHT11_ReadData(float *temp, float *humi)
{
uint8_t buf[5] = {0};
// 启动信号(拉低18ms)
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_RESET);
HAL_Delay(18);
HAL_GPIO_WritePin(DHT11_PORT, DHT11_PIN, GPIO_PIN_SET);
// 等待响应
if(DHT11_WaitForResponse() != 0) return 1;
// 读取40位数据
for(int i=0; i<5; i++){
for(int j=0; j<8; j++){
while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_RESET);
uint32_t start = HAL_GetTick();
while(HAL_GPIO_ReadPin(DHT11_PORT, DHT11_PIN) == GPIO_PIN_SET);
uint8_t bit = (HAL_GetTick()-start > 40) ? 1 : 0;
buf[i] = (buf[i]<<1) | bit;
}
}
// 校验和数据
if(buf[4] != (buf[0]+buf[1]+buf[2]+buf[3])) return 2;
*humi = buf[0] + buf[1]*0.1;
*temp = buf[2] + buf[3]*0.1;
return 0;
}
GPS数据解析:
采用NMEA-0183协议,主要解析GPRMC语句:
c复制void GPS_Parse(char *buf, GPS_Data *gps)
{
if(strstr(buf, "$GPRMC") == NULL) return;
char *p = strtok(buf, ",");
int field = 0;
while(p != NULL){
switch(field){
case 1: // UTC时间
if(p[0] != '\0'){
gps->hour = (p[0]-'0')*10 + (p[1]-'0');
gps->min = (p[2]-'0')*10 + (p[3]-'0');
gps->sec = (p[4]-'0')*10 + (p[5]-'0');
}
break;
case 2: // 定位状态
gps->valid = (p[0] == 'A') ? 1 : 0;
break;
case 3: // 纬度
if(strlen(p) >= 4){
gps->latitude = atof(p+2)/60.0;
gps->latitude += (p[0]-'0')*10 + (p[1]-'0');
if(p[strlen(p)+1] == 'S') gps->latitude = -gps->latitude;
}
break;
// 其他字段解析...
}
p = strtok(NULL, ",");
field++;
}
}
4. OneNET平台对接
4.1 设备注册与协议选择
使用OneNET的MQTT协议接入:
- 在平台创建LwM2M产品
- 添加设备时记录设备ID和API Key
- 选择MQTT协议,服务器地址:mqtt.heclouds.com,端口:1883
4.2 数据上传实现
c复制void BC20_SendToOnenet(float temp, float humi, GPS_Data gps, uint16_t adc)
{
char cmd[256];
char json[128];
// 构造JSON数据
sprintf(json, "{\"temp\":%.1f,\"humi\":%.1f,\"lat\":%f,\"lon\":%f,\"adc\":%d}",
temp, humi, gps.latitude, gps.longitude, adc);
// 构造MQTT发布命令
sprintf(cmd, "AT+QMTPUB=0,0,0,0,\"/sys/a1b2c3d4e5/device1/thing/event/property/post\",%d\r\n", strlen(json));
// 发送到BC20模块
HAL_UART_Transmit(&huart1, (uint8_t*)cmd, strlen(cmd), 1000);
HAL_UART_Transmit(&huart1, (uint8_t*)json, strlen(json), 1000);
}
关键点:OneNET新版平台要求Topic格式为
/sys/{productID}/{deviceName}/thing/event/property/post
5. 低功耗优化策略
5.1 电源管理模式
-
运行模式优化:
- 主频设置为8MHz(满足需求情况下最低)
- 外设时钟动态开关
- ADC采样后立即关闭
-
睡眠模式配置:
c复制void Enter_StopMode(void)
{
// 关闭所有外设时钟
__HAL_RCC_GPIOA_CLK_DISABLE();
__HAL_RCC_GPIOB_CLK_DISABLE();
__HAL_RCC_GPIOC_CLK_DISABLE();
// 配置唤醒源(RTC每5分钟唤醒)
HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1);
HAL_PWREx_EnableUltraLowPower();
// 进入停止模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后重新初始化系统时钟
SystemClock_Config();
}
5.2 数据传输节电
- 采用非确认模式(QoS0)发送数据
- 数据打包发送间隔设置为5分钟
- 启用BC20的PSM模式:
code复制AT+CPSMS=1,,,"00000100","00000000"
6. 常见问题与解决方案
| 问题现象 | 可能原因 | 解决方法 |
|---|---|---|
| DHT11读数异常 | 1. 时序不符合要求 2. 上拉电阻未接 |
1. 严格遵循时序图 2. 检查4.7K上拉电阻 |
| GPS无数据输出 | 1. 天线未接好 2. 波特率不匹配 |
1. 检查天线连接 2. 确认模块与MCU波特率一致 |
| BC20连接失败 | 1. SIM卡问题 2. 网络覆盖差 |
1. 检查SIM卡安装 2. 测试AT+CSQ信号强度 |
| OneNET数据未显示 | 1. Topic格式错误 2. 产品ID不匹配 |
1. 核对新版Topic格式 2. 检查三元组信息 |
实测经验:
- BC20模块首次上电需要等待2-3分钟才能注册到NB网络
- DHT11在湿度>80%环境下响应时间会延长至3-4秒
- STM32L151的ADC在低功耗模式下需要重新校准才能保证精度
7. 项目扩展方向
-
增加传感器:
- 光照强度(BH1750)
- 大气压力(BMP280)
- 空气质量(SGP30)
-
本地存储:
- 添加SPI Flash存储历史数据
- 在信号差时缓存数据,网络恢复后补传
-
OTA升级:
- 通过OneNET推送固件更新包
- 使用STM32的IAP功能实现远程升级
-
边缘计算:
- 在设备端实现简单算法(如温湿度突变报警)
- 减少不必要的数据传输
在实际部署中,我发现这套系统的稳定性很大程度上取决于NB-IoT网络的覆盖质量。建议在正式部署前,先用BC20的AT指令测试当地信号强度(AT+CSQ),RSSI值最好大于-85dBm。