DIY一个低成本气象站:STM32F103C8T6核心板+OLED显示风速风向温湿度
DIY低成本气象站STM32F103C8T6OLED实现风速风向温湿度监测最近在整理工作室时翻出一块闲置的STM32F103C8T6核心板突然萌生了个有趣的想法——能不能用它做个桌面气象站这个被称为蓝色药丸的开发板价格不到20元配合常见的传感器模块完全可以搭建一个功能完整的微型气象监测系统。经过两周的折腾终于实现了风速、风向、温湿度的实时采集与OLED显示整套硬件成本控制在百元以内。1. 硬件选型与成本控制选择STM32F103C8T6作为主控有几个明显优势首先是极高的性价比市面上兼容板价格普遍在15-25元区间其次是丰富的社区资源正点原子和野火等厂商提供了完善的基础库最重要的是其性能完全满足需求——72MHz主频、64KB Flash、20KB RAM足以处理多个传感器的数据采集与显示任务。传感器组合经过多次对比测试后确定为风速风向传感器选用RS485输出的工业级传感器约45元相比PWM输出型号更稳定可靠温湿度传感器经典的DHT11模块8元虽然精度不如SHT30但胜在接线简单显示模块0.96寸4线OLED15元比LCD更省电且支持自定义界面提示所有模块建议选择3.3V供电版本避免电平转换问题。若使用5V传感器需额外添加电平转换电路。硬件连接方案有两种选择方案优点缺点适用场景飞线连接零成本快速验证可靠性差易松动短期测试自制PCB稳定可靠需要设计打板时间长期使用我最初采用飞线方案验证功能确认可行后设计了简单的双面PCB通过嘉立创免费打样服务制作实际花费仅需支付运费。2. 传感器数据采集实战2.1 RS485风速风向传感器配置工业级风速传感器通常采用Modbus-RTU协议需要特别注意以下参数配置// USART2初始化代码示例4800bps 8N1 huart2.Instance USART2; huart2.Init.BaudRate 4800; huart2.Init.WordLength UART_WORDLENGTH_8B; huart2.Init.StopBits UART_STOPBITS_1; huart2.Init.Parity UART_PARITY_NONE; huart2.Init.Mode UART_MODE_TX_RX; HAL_UART_Init(huart2);传感器数据读取流程发送Modbus查询帧如读取保持寄存器等待并接收响应数据校验CRC16后提取有效值转换为实际物理量如m/s2.2 DHT11温湿度采集技巧DHT11虽然简单但时序要求严格常见问题包括响应超时检查接线是否接触不良校验和错误适当增加两次读取间隔数据漂移避免传感器靠近发热元件改进后的采集代码结构void DHT11_ReadData(float *temp, float *humi) { // 1. 主机发送开始信号 DQ_OUT(); DQ_LOW(); delay_ms(18); DQ_HIGH(); delay_us(30); // 2. 等待从机响应 DQ_IN(); while(DQ_READ()); while(!DQ_READ()); while(DQ_READ()); // 3. 接收40位数据 uint8_t data[5] {0}; for(int i0; i5; i) { for(int j0; j8; j) { while(!DQ_READ()); delay_us(30); data[i] | DQ_READ() (7-j); while(DQ_READ()); } } // 4. 校验并转换数据 if(data[4] (data[0]data[1]data[2]data[3])) { *humi data[0] data[1]*0.1; *temp data[2] data[3]*0.1; } }3. OLED界面设计与优化0.96寸OLED分辨率通常为128x64合理布局可以同时显示所有气象数据。我的界面分为三个区域顶部状态栏显示当前时间通过RTC模块获取中央数据区用图标数值形式展示实时测量值底部趋势区用简易折线图显示最近10分钟变化实现这种布局需要精心设计显示函数void OLED_DisplayData(float temp, float humi, float wind_speed, uint16_t wind_dir) { OLED_Clear(); // 1. 绘制顶部状态栏 OLED_ShowString(0, 0, STM32气象站, 16); OLED_ShowString(90, 0, get_time_str(), 16); OLED_DrawLine(0, 16, 127, 16); // 2. 中央数据区 OLED_ShowBMP(0, 20, 16, 16, temp_icon); // 温度图标 OLED_ShowString(20, 20, 温度:, 16); OLED_ShowFloat(60, 20, temp, 1, 16); OLED_ShowString(100, 20, C, 16); // ... 其他数据类似显示 // 3. 底部趋势图 OLED_DrawLine(0, 50, 127, 50); draw_simple_graph(wind_speed_history, 10); OLED_Refresh(); }注意频繁刷新全屏会导致闪烁建议使用局部刷新技术。SSD1306支持设置列地址和页地址可以只更新变化区域。4. 系统整合与性能优化当所有传感器和显示功能单独测试通过后需要解决多任务调度问题。STM32F103没有RTOS支持可以采用以下策略定时器中断配置基本定时器产生1Hz中断作为系统心跳状态机设计将各传感器读取分解为独立状态非阻塞延时用HAL_GetTick()替代delay_ms()典型的主循环结构while(1) { uint32_t now HAL_GetTick(); // 每秒读取一次温湿度 if(now - last_dht11_time 1000) { DHT11_ReadData(temp, humi); last_dht11_time now; } // 每5秒读取风速风向 if(now - last_wind_time 5000) { read_wind_sensor(); last_wind_time now; } // 实时刷新显示 OLED_DisplayData(temp, humi, wind_speed, wind_dir); }电源管理是另一个优化重点。实测发现全速运行电流约45mA关闭不用的外设可降至30mA加入休眠模式后待机电流1mA通过合理配置可以显著延长电池供电时间void enter_sleep_mode(void) { // 关闭外设时钟 __HAL_RCC_USART2_CLK_DISABLE(); __HAL_RCC_I2C1_CLK_DISABLE(); // 配置唤醒源 HAL_PWR_EnableWakeUpPin(PWR_WAKEUP_PIN1); // 进入停止模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 唤醒后重新初始化 SystemClock_Config(); MX_USART2_UART_Init(); MX_I2C1_Init(); }5. 扩展功能与改进方向基础功能实现后可以考虑添加这些增强功能数据记录添加SPI Flash存储历史数据无线传输通过ESP-01模块上传数据到服务器报警功能设置阈值触发蜂鸣器报警太阳能供电配合TP4056充电模块实现离网运行一个实用的改进是增加风向标校准功能。由于安装位置和周边建筑影响原始风向数据可能需要补偿// 风向补偿表16方位 const int16_t wind_dir_offset[16] { 0, // N 23, // NNE 45, // NE 68, // ENE 90, // E 113, // ESE 135, // SE 158, // SSE 180, // S 203, // SSW 225, // SW 248, // WSW 270, // W 293, // WNW 315, // NW 338 // NNW }; uint16_t correct_wind_direction(uint16_t raw) { uint8_t index raw / 22.5; return (raw wind_dir_offset[index]) % 360; }硬件上也可以持续优化改用SMT元件缩小PCB尺寸添加防雷击保护电路设计3D打印外壳提升美观度这个项目最让我惊喜的是STM32F103C8T6的表现——虽然已经面世十多年但在这种小型物联应用中依然游刃有余。整个开发过程中最耗时的部分其实是传感器的机械固定和防风防水处理电子部分反而比较顺利。建议初学者可以先在洞洞板上验证所有功能再考虑制作PCB避免反复修改造成的浪费。