1. 项目概述
作为一名嵌入式系统开发者,我最近完成了一个基于STM32的便携式气象监测系统项目。这个系统能够实时监测多种气象参数,包括温湿度、风速风向、PM2.5浓度、光照强度、雨量和大气压强等。整套系统设计紧凑,成本控制在合理范围内,非常适合小区域气象监测应用,比如农业大棚、校园气象站或者户外活动场所。
在实际开发过程中,我发现气象监测系统有几个关键挑战:传感器数据的准确性、系统的低功耗设计、恶劣环境下的稳定性,以及数据的实时显示和报警功能。这个项目我先后迭代了三个版本,从基础版到增加蓝牙功能,再到最终的WiFi版本,每个版本都针对特定需求做了优化。
2. 系统硬件设计
2.1 核心控制器选型
我选择了STM32F103C8T6作为主控制器,这款芯片属于STM32F1系列,具有以下优势:
- 72MHz主频,性能足够处理多传感器数据
- 64KB Flash和20KB SRAM,满足程序存储和运行需求
- 丰富的外设接口(USART、I2C、SPI等)
- 低功耗模式,适合便携设备
- 性价比高,开发资源丰富
提示:STM32F103系列有多个型号,C8T6是最经济的版本,如果对IO口数量有更高要求,可以考虑RCT6等型号。
2.2 传感器模块选型与接口设计
2.2.1 温湿度传感器
选用DHT11数字温湿度传感器,通过单总线协议与MCU通信。虽然精度不算最高(温度±2℃,湿度±5%RH),但胜在价格低廉、接口简单。实际使用中发现,DHT11对供电稳定性较敏感,建议在VCC引脚加0.1μF去耦电容。
2.2.2 气压传感器
采用BMP180数字气压传感器,通过I2C接口连接。这款传感器不仅能测量气压(精度0.03hPa),还能通过气压值计算海拔高度。实际测试时需要注意:
- 海拔计算需要提供当前海平面气压作为基准
- 传感器对温度变化敏感,建议定期进行温度补偿
2.2.3 风速风向传感器
使用三杯式风速传感器和风向标组合,配合霍尔元件输出脉冲信号。风速计算基于单位时间内脉冲数量,风向则通过电位器分压值判断。这部分电路设计有几个关键点:
- 脉冲输入需要硬件消抖电路
- 风向传感器需要稳定的参考电压
- 户外安装要考虑防雷击措施
2.2.4 PM2.5传感器
选用激光式PM2.5传感器(如GP2Y1010AU0F),通过ADC采集模拟输出。这类传感器容易受湿度影响,建议:
- 定期进行零点校准
- 数据做滑动平均滤波处理
- 避免在极端潮湿环境下使用
2.2.5 雨量传感器
采用电阻式雨滴传感器,雨滴越多导电性越强,输出电压越低。实际使用中发现:
- 传感器表面容易积灰,影响灵敏度
- 需要定期清洁感应区域
- 阈值设置要考虑当地气候特点
2.3 显示与人机交互
系统采用2.4寸TFT液晶屏作为主显示器,通过SPI接口连接。显示界面设计遵循以下原则:
- 重要参数(如风速、温度)用大字体显示
- 超过阈值的数据用红色高亮
- 分页显示不同类别的气象数据
四个机械按键提供人机交互功能:
- 设置键:进入参数设置模式
- 加/减键:调整参数值或切换选项
- 返回键:退出当前菜单
3. 系统软件设计
3.1 主程序架构
系统软件采用前后台架构,主循环负责数据显示和用户交互,中断处理传感器数据采集和报警判断。
c复制int main(void)
{
Hardware_Init(); // 硬件初始化
Sensor_Calibration(); // 传感器校准
while(1) {
Display_Update(); // 更新显示
Key_Process(); // 处理按键输入
Alarm_Check(); // 检查报警条件
Data_Save(); // 存储数据(如有SD卡)
}
}
3.2 传感器驱动实现
3.2.1 DHT11温湿度驱动
DHT11采用单总线协议,时序要求严格。以下是读取数据的核心代码:
c复制uint8_t DHT11_Read_Data(float *temperature, float *humidity)
{
uint8_t buf[5];
// 主机拉低总线18ms以上
DHT11_IO_OUT();
DHT11_DQ_OUT(0);
delay_ms(20);
DHT11_DQ_OUT(1);
delay_us(30);
// 切换为输入模式等待响应
DHT11_IO_IN();
// 检查传感器响应信号
if(DHT11_DQ_IN() != 0) return 1;
while(DHT11_DQ_IN() == 0); // 等待低电平结束
while(DHT11_DQ_IN() == 1); // 等待高电平结束
// 读取40位数据
for(int i=0; i<5; i++) {
buf[i] = DHT11_Read_Byte();
}
// 校验和检查
if(buf[0] + buf[1] + buf[2] + buf[3] != buf[4]) return 2;
// 数据转换
*humidity = buf[0];
*temperature = buf[2];
return 0;
}
3.2.2 BMP180气压传感器驱动
BMP180通过I2C接口通信,需要先读取校准参数:
c复制void BMP180_Read_Calibration(void)
{
bmp180_cal.ac1 = BMP180_Read_Reg(0xAA, 2);
bmp180_cal.ac2 = BMP180_Read_Reg(0xAC, 2);
// 读取其他校准参数...
}
float BMP180_Calculate_Altitude(float pressure, float seaLevelPressure)
{
// 根据气压计算海拔高度
float altitude = 44330.0 * (1.0 - pow(pressure / seaLevelPressure, 1/5.255));
return altitude;
}
3.3 数据处理与滤波算法
传感器原始数据通常存在噪声,需要适当的滤波处理:
c复制// 滑动平均滤波示例
#define FILTER_LEN 10
float Moving_Average_Filter(float new_data)
{
static float buffer[FILTER_LEN] = {0};
static uint8_t index = 0;
static float sum = 0;
sum -= buffer[index];
buffer[index] = new_data;
sum += buffer[index];
index = (index + 1) % FILTER_LEN;
return sum / FILTER_LEN;
}
对于风速这种变化较快的参数,可以采用加权滑动平均:
c复制float Weighted_Moving_Average(float new_data)
{
static float prev_data = 0;
const float alpha = 0.2; // 权重系数
prev_data = alpha * new_data + (1 - alpha) * prev_data;
return prev_data;
}
3.4 报警功能实现
系统支持多参数阈值报警,当任何参数超过设定值时触发声光报警:
c复制void Alarm_Check(void)
{
uint8_t alarm_flag = 0;
if(current_temp > temp_threshold) alarm_flag |= TEMP_ALARM;
if(current_humidity > humidity_threshold) alarm_flag |= HUMIDITY_ALARM;
// 检查其他参数...
if(alarm_flag) {
Buzzer_On();
LED_Alert_On();
Display_Set_Alert_Color();
} else {
Buzzer_Off();
LED_Alert_Off();
Display_Set_Normal_Color();
}
}
4. 无线通信功能实现
4.1 蓝牙版本实现
蓝牙版本采用HC-05模块,通过串口与STM32通信。手机APP通过蓝牙接收数据并显示:
c复制void Bluetooth_Send_Data(void)
{
char buffer[128];
sprintf(buffer, "T:%.1f,H:%.1f,P:%.1f,W:%.1f",
current_temp, current_humidity,
current_pressure, current_wind_speed);
USART_SendString(USART1, buffer);
}
手机端需要开发配套APP,可以使用Android Studio开发,核心功能包括:
- 蓝牙设备搜索与连接
- 数据接收与解析
- 阈值设置与报警显示
- 历史数据图表展示
4.2 WiFi版本实现
WiFi版本采用ESP8266模块,通过AT指令实现网络连接和数据传输:
c复制void WiFi_Send_Data_To_Server(void)
{
char buffer[256];
sprintf(buffer, "GET /update?field1=%.1f&field2=%.1f HTTP/1.1\r\n"
"Host: api.thingspeak.com\r\n"
"Connection: close\r\n\r\n",
current_temp, current_humidity);
ESP8266_Send_Cmd("AT+CIPSTART=\"TCP\",\"api.thingspeak.com\",80");
ESP8266_Send_Cmd("AT+CIPSEND=%d", strlen(buffer));
ESP8266_Send_Data(buffer);
ESP8266_Send_Cmd("AT+CIPCLOSE");
}
WiFi版本的优势在于可以实现远程监控,数据可以上传到云平台(如Thingspeak),用户可以通过网页或手机APP随时随地查看气象数据。
5. 系统优化与调试经验
5.1 低功耗设计
便携式设备需要考虑功耗问题,我采取了以下措施:
- 传感器分时供电:非采集时段切断传感器电源
- MCU睡眠模式:在空闲时段进入Stop模式
- 显示背光控制:无操作时降低背光亮度
- 无线模块功耗管理:蓝牙/WiFi间歇性工作
c复制void Enter_Low_Power_Mode(void)
{
// 关闭外设时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, DISABLE);
// 配置唤醒源(如RTC或外部中断)
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
// 唤醒后恢复系统时钟
SystemInit();
}
5.2 抗干扰措施
户外环境电磁干扰较多,PCB设计时需要注意:
- 模拟和数字地分开布局,单点连接
- 关键信号线加屏蔽或采用差分传输
- 电源输入端加π型滤波电路
- 传感器信号线尽量短,必要时加终端匹配
5.3 校准与测试
气象监测设备的准确性至关重要,我采用的校准方法包括:
- 温度:与标准水银温度计对比,记录偏差值
- 湿度:使用饱和盐溶液法校准
- 气压:参考当地气象站数据校准
- 风速:使用风洞或已知风速环境测试
校准数据可以存储在STM32的Flash中:
c复制void Save_Calibration_Data(void)
{
FLASH_Unlock();
FLASH_ErasePage(CALIBRATION_DATA_ADDRESS);
FLASH_ProgramHalfWord(CALIBRATION_DATA_ADDRESS, temp_offset);
FLASH_ProgramHalfWord(CALIBRATION_DATA_ADDRESS+2, humidity_offset);
// 存储其他校准参数...
FLASH_Lock();
}
6. 常见问题与解决方案
6.1 传感器数据异常
问题现象:DHT11偶尔返回错误数据
排查步骤:
- 检查电源电压是否稳定(3.3V±5%)
- 检查上拉电阻(4.7kΩ)是否正确连接
- 检查时序是否符合规格书要求
- 增加读取失败后的重试机制
解决方案:
c复制uint8_t retry = 3;
while(retry--) {
if(DHT11_Read_Data(&temp, &humidity) == 0) break;
delay_ms(100);
}
if(retry == 0) {
// 读取失败处理
}
6.2 无线连接不稳定
问题现象:WiFi模块经常断开连接
可能原因:
- 天线性能不佳
- 供电不足(ESP8266峰值电流可达200mA)
- 网络信号弱
- AT指令响应超时
优化措施:
- 使用外置天线
- 电源路径加1000μF以上电容
- 增加连接状态监测和自动重连机制
- 调整AT指令超时时间
6.3 显示刷新慢
问题现象:TFT屏幕刷新导致系统响应迟缓
优化方案:
- 采用局部刷新代替全屏刷新
- 使用DMA传输显示数据
- 建立显示缓冲区,减少直接操作屏幕次数
- 非关键数据降低刷新频率
c复制// 使用DMA传输显示数据示例
void TFT_Refresh_With_DMA(uint16_t *buffer, uint32_t size)
{
DMA_Cmd(DMA1_Channel4, DISABLE);
DMA_SetCurrDataCounter(DMA1_Channel4, size);
DMA_Cmd(DMA1_Channel4, ENABLE);
// 等待传输完成
while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);
DMA_ClearFlag(DMA1_FLAG_TC4);
}
7. 项目扩展与改进方向
在实际使用过程中,我发现这个系统还有几个可以改进的地方:
-
太阳能供电系统:增加太阳能电池板和锂电池管理电路,实现完全自供电,适合野外长期监测。
-
数据记录功能:添加SD卡存储模块,实现长时间数据记录,便于后续分析。
-
更多传感器接口:预留I2C和UART扩展接口,方便接入CO2、紫外线等更多类型传感器。
-
机械结构优化:设计防水防尘外壳,改进风速风向传感器的安装方式,提高长期稳定性。
-
数据分析算法:在本地实现简单的气象趋势预测算法,而不仅仅是数据显示。
-
LoRa远传版本:对于需要远距离传输的场景,可以改用LoRa无线模块,传输距离可达数公里。
这个气象监测系统从最初的概念到最终实现,经历了多次迭代和优化。通过这个项目,我深刻体会到嵌入式系统开发需要综合考虑硬件设计、软件算法和实际应用场景。特别是在户外环境中,设备的可靠性和稳定性往往比功能的丰富性更重要。
