三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

手把手教你用STM32F103和ESP8266做一个桌面天气时钟(附完整代码和接线图)

手把手教你用STM32F103和ESP8266做一个桌面天气时钟(附完整代码和接线图)

从零打造智能桌面天气时钟:STM32F103与ESP8266的完美组合

在创客圈里,能够实时显示天气和时间的桌面摆件一直是热门项目。它不仅实用,还能展现你的技术实力。今天,我将带你用STM32F103C8T6和ESP8266-01S模块,打造一个功能完善、界面精美的智能天气时钟。

1. 硬件选型与准备

选择适合的硬件是项目成功的第一步。我们需要平衡性能、成本和易用性。

核心组件清单:

  • STM32F103C8T6最小系统板(蓝色药丸)
  • ESP8266-01S WiFi模块
  • 0.96寸OLED显示屏(I2C接口)
  • USB转TTL模块(用于调试)
  • ST-Link V2下载器

提示:ESP8266-01S比普通ESP8266-01更稳定,建议优先选用

硬件连接时,特别注意供电问题。ESP8266在发送数据时瞬时电流可能达到200mA,而STM32的3.3V稳压芯片通常只能提供150mA左右。我推荐两种解决方案:

  1. 使用外部3.3V稳压模块单独给ESP8266供电
  2. 在STM32的3.3V输出端并联470μF电容

2. 开发环境搭建

工欲善其事,必先利其器。我们需要配置好开发环境才能高效编码。

2.1 软件工具准备

  • Keil MDK-ARM(建议V5.25以上)
  • STM32CubeMX(用于外设初始化)
  • VSCode(辅助代码编辑)
  • 串口调试助手(推荐XCOM或Putty)

2.2 工程配置要点

在CubeMX中配置时,特别注意以下几点:

  1. 时钟树配置:

    • HSE选择8MHz
    • 系统时钟设为72MHz
    • APB1总线时钟设为36MHz
  2. 串口配置:

    • USART1用于调试输出(PA9-TX, PA10-RX)
    • USART3用于ESP8266通信(PB10-TX, PB11-RX)
  3. I2C配置:

    • I2C2用于OLED(PB10-SCL, PB11-SDA)
    • 时钟速度设为400kHz
// 示例:I2C初始化代码片段 void MX_I2C2_Init(void) { hi2c2.Instance = I2C2; hi2c2.Init.ClockSpeed = 400000; hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c2.Init.OwnAddress1 = 0; hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c2.Init.OwnAddress2 = 0; hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c2) != HAL_OK) { Error_Handler(); } }

3. ESP8266通信实现

ESP8266是这个项目的网络门户,稳定可靠的WiFi连接是获取天气数据的关键。

3.1 AT指令交互设计

与ESP8266通信主要使用AT指令。为提高可靠性,我建议实现以下功能函数:

  1. 发送指令并等待响应
  2. 带超时的响应等待
  3. 自动重试机制
#define ESP8266_MAX_RETRY 3 #define ESP8266_TIMEOUT_MS 2000 uint8_t esp8266_send_command(const char* cmd, const char* expect, uint32_t timeout) { uint8_t retry = 0; uint32_t start_time = HAL_GetTick(); while(retry < ESP8266_MAX_RETRY) { HAL_UART_Transmit(&huart3, (uint8_t*)cmd, strlen(cmd), HAL_MAX_DELAY); HAL_UART_Transmit(&huart3, (uint8_t*)"\r\n", 2, HAL_MAX_DELAY); // 清空接收缓冲区 esp8266_rx_index = 0; memset(esp8266_rx_buffer, 0, sizeof(esp8266_rx_buffer)); // 等待响应 while((HAL_GetTick() - start_time) < timeout) { if(esp8266_rx_index > 0 && strstr(esp8266_rx_buffer, expect)) { return 1; // 成功 } HAL_Delay(10); } retry++; HAL_Delay(100); } return 0; // 失败 }

3.2 网络请求优化

获取天气数据时,建议采用以下策略:

  1. 使用稳定的天气API(如心知天气、和风天气)
  2. 实现HTTP长连接减少握手开销
  3. 添加数据缓存机制,避免频繁请求

API请求对比表:

服务提供商免费额度更新频率数据格式稳定性
心知天气500次/天实时JSON★★★★☆
和风天气1000次/天每小时JSON★★★★★
OpenWeather60次/分钟实时JSON★★★☆☆

4. OLED显示设计

0.96寸OLED虽然小巧,但通过精心设计可以呈现丰富信息。

4.1 显示布局规划

我推荐的分区布局方案:

  1. 顶部区域:实时时间(大字体)
  2. 中部左侧:天气图标
  3. 中部右侧:温度/湿度
  4. 底部区域:日期和空气质量
void update_display(void) { OLED_Clear(); // 显示时间 (24小时制) OLED_ShowString(0, 0, "Time:", 16); OLED_ShowNum(40, 0, time.hour, 2, 16); OLED_ShowString(64, 0, ":", 16); OLED_ShowNum(72, 0, time.minute, 2, 16); OLED_ShowString(96, 0, ":", 16); OLED_ShowNum(104, 0, time.second, 2, 16); // 显示日期 char date_str[20]; sprintf(date_str, "%04d-%02d-%02d", time.year, time.month, time.day); OLED_ShowString(0, 16, date_str, 16); // 显示天气信息 OLED_ShowString(0, 32, "Temp:", 16); OLED_ShowNum(40, 32, weather.temperature, 2, 16); OLED_ShowString(64, 32, "C", 16); // 显示天气图标 draw_weather_icon(80, 32, weather.condition); // 显示空气质量 OLED_ShowString(0, 48, "AQI:", 16); OLED_ShowNum(32, 48, weather.aqi, 3, 16); }

4.2 显示刷新优化

OLED频繁刷新会导致闪烁,建议采用以下策略:

  1. 分区域刷新:只更新变化的部分
  2. 双缓冲机制:先在内存中绘制完整帧再显示
  3. 定时刷新:时间每秒刷新,天气每10分钟刷新

5. 系统整合与调试

将所有模块整合后,系统架构如下:

  1. 主循环处理用户输入和定时任务
  2. WiFi任务在后台获取数据
  3. 显示任务负责界面更新
  4. RTC提供本地计时

常见问题及解决方案:

问题现象可能原因解决方法
ESP8266不响应供电不足增加电容或独立供电
时间获取失败服务器不稳定更换时间API或添加重试
OLED显示异常I2C干扰缩短连线,加10k上拉电阻
系统死机堆栈溢出增大任务堆栈大小

在项目开发过程中,我特别建议:

  1. 使用版本控制(如Git)管理代码
  2. 编写详细的调试日志
  3. 模块化开发,逐个验证功能

最终完成的天气时钟不仅实用,还能成为展示你技术能力的作品。通过这个项目,你能够掌握STM32开发、WiFi通信、OLED驱动等多项实用技能。

← 返回列表