从“点灯”到“显示”:用STM32F103的IIC接口驱动0.96寸OLED屏制作一个简易天气站
2026/6/6 8:14:02 网站建设 项目流程

从“点灯”到“显示”:用STM32F103的IIC接口驱动0.96寸OLED屏制作一个简易天气站

在嵌入式开发领域,将硬件与软件完美结合创造出实用小工具总是令人兴奋。想象一下,用一块硬币大小的OLED屏幕和常见的STM32F103开发板,就能制作一个实时显示温湿度的桌面天气站——这不仅是学习IIC通信协议的绝佳实践,更是将理论知识转化为实际应用的典型范例。本文将带你从零开始,完整实现这个兼具技术深度和实用价值的小项目。

1. 硬件选型与系统架构设计

1.1 核心硬件组件解析

STM32F103C8T6最小系统板作为项目核心,其72MHz主频和丰富的外设接口完全满足需求。选择这款芯片的三大理由:

  • 内置硬件IIC控制器(也可软件模拟)
  • 充足的GPIO资源(后续扩展性强)
  • 广泛的社区支持(遇到问题容易解决)

0.96寸OLED显示屏(SSD1306驱动)的四线接口配置:

引脚名称功能描述连接STM32引脚
GND电源地GND
VCC3.3V供电3.3V
SCLIIC时钟线PB6
SDAIIC数据线PB7

DHT11温湿度传感器的单总线协议虽然简单,但为了系统统一性,建议选择IIC接口的传感器如SHT30或BME280,它们具有:

  • 更高测量精度(±2%RH vs DHT11的±5%RH)
  • 真正的IIC接口(地址可配置)
  • 温度湿度同步测量

1.2 系统通信架构设计

当多个IIC设备共用总线时,地址冲突是常见问题。典型解决方案:

  1. 硬件修改:部分传感器提供地址选择引脚(如BME280的SDO引脚)
  2. 软件复用:分时复用IIC总线(需严格时序控制)
  3. 接口转换:使用IIC多路复用器(如TCA9548A)

实际项目中,采用BME280(地址0x76)与SSD1306(地址0x3C)的组合最为理想,二者地址不冲突且性能优越。

2. IIC通信深度优化实践

2.1 硬件IIC与软件模拟对比

STM32的硬件IIC常被诟病稳定性问题,但经过合理配置后表现优异。关键配置参数:

void I2C_Config(void) { I2C_InitTypeDef I2C_InitStruct; I2C_InitStruct.I2C_Mode = I2C_Mode_I2C; I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStruct.I2C_OwnAddress1 = 0x00; // 主机模式设为0 I2C_InitStruct.I2C_Ack = I2C_Ack_Enable; I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStruct.I2C_ClockSpeed = 400000; // 400kHz标准模式 I2C_Init(I2C1, &I2C_InitStruct); I2C_Cmd(I2C1, ENABLE); }

软件模拟IIC的典型实现(当硬件IIC不可用时):

void IIC_Delay(void) { uint8_t i = 10; while(i--); } void SDA_Out(void) { GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; } void SDA_In(void) { GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; } uint8_t IIC_Wait_Ack(void) { uint8_t timeout = 0; SDA_In(); IIC_SCL_H(); while(READ_SDA()) { if(timeout++ > 100) { IIC_Stop(); return 1; } } IIC_SCL_L(); return 0; }

2.2 多设备通信时序优化

当OLED屏幕刷新与传感器数据读取同时进行时,合理的时序安排至关重要:

  1. 分时复用策略

    • 每100ms读取一次传感器数据
    • 每50ms刷新一次OLED局部区域
    • 关键操作加互斥锁防止总线冲突
  2. 数据缓冲机制

    typedef struct { float temperature; float humidity; uint32_t last_update; } WeatherData; WeatherData weather_cache;
  3. 错误处理增强

    #define IIC_RETRY_MAX 3 uint8_t IIC_Write_WithRetry(uint8_t addr, uint8_t reg, uint8_t data) { uint8_t retry = 0; while(retry < IIC_RETRY_MAX) { if(IIC_Write_Byte(addr, reg, data) == SUCCESS) return SUCCESS; Delay_ms(1); retry++; } return ERROR; }

3. OLED显示界面高级设计

3.1 多页面显示架构

实现温度、湿度、天气趋势三页循环显示:

typedef enum { PAGE_TEMP, PAGE_HUMI, PAGE_TREND, PAGE_MAX } DisplayPage; void OLED_UpdateDisplay(DisplayPage page) { OLED_ClearBuffer(); switch(page) { case PAGE_TEMP: DrawTemperaturePage(); break; case PAGE_HUMI: DrawHumidityPage(); break; case PAGE_TREND: DrawTrendPage(); break; } OLED_Refresh(); }

3.2 图形化元素设计技巧

温度计图标动态绘制算法

void DrawThermometer(float temp, uint8_t x, uint8_t y) { // 绘制温度计轮廓 OLED_DrawRect(x, y, 10, 30); OLED_DrawCircle(x+5, y+33, 5); // 计算液柱高度(假设显示范围0-40℃) uint8_t height = (uint8_t)((temp / 40.0) * 28); OLED_FillRect(x+2, y+28-height, 6, height); }

字体优化方案

  1. 使用自定义8x16点阵字体显示主要数据
  2. 采用6x8字体显示辅助信息
  3. 关键数值使用反色显示增强对比度

3.3 刷新率优化策略

通过局部刷新技术大幅提升显示流畅度:

  1. 脏矩形技术

    typedef struct { uint8_t x_start; uint8_t y_start; uint8_t width; uint8_t height; bool need_refresh; } DirtyRegion;
  2. 差异刷新算法

    void SmartRefresh(uint8_t new_temp, uint8_t old_temp) { if(new_temp != old_temp) { // 仅刷新温度显示区域 OLED_PartialRefresh(10, 20, 30, 12); } }

4. 系统集成与性能调优

4.1 低功耗设计实现

通过以下措施使整机工作电流降至5mA以下:

  • OLED动态关闭背光(非睡眠模式)
  • STM32主频动态调整(72MHz↔8MHz)
  • 传感器间歇工作模式(每秒唤醒一次)

配置代码示例:

void Enter_LowPowerMode(void) { RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI); // 切换至内部8MHz时钟 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); SystemInit(); // 唤醒后恢复时钟配置 }

4.2 数据稳定性处理

针对传感器读数波动问题,采用三重滤波:

  1. 硬件滤波:在传感器电源端添加0.1μF去耦电容
  2. 软件均值滤波:连续采样5次取中间值
  3. 滑动窗口滤波:维护10个历史数据的环形缓冲区
#define FILTER_WINDOW_SIZE 10 typedef struct { float buffer[FILTER_WINDOW_SIZE]; uint8_t index; } MovingAverage; float UpdateFilter(MovingAverage* filter, float new_val) { filter->buffer[filter->index] = new_val; filter->index = (filter->index + 1) % FILTER_WINDOW_SIZE; float sum = 0; for(int i=0; i<FILTER_WINDOW_SIZE; i++) { sum += filter->buffer[i]; } return sum / FILTER_WINDOW_SIZE; }

4.3 扩展接口设计

预留的扩展功能接口:

  1. USB虚拟串口:用于调试信息输出
  2. SWD调试接口:方便固件更新
  3. GPIO扩展口:可连接按键控制显示切换

硬件连接建议:

功能引脚分配备注
USB_DPPA12需1.5kΩ上拉电阻
SWDIOPA13建议添加保护电阻
用户按键PC13内部上拉模式

5. 项目进阶方向

当基础功能实现后,可以考虑以下增强功能:

  • 历史数据记录:利用STM32内部Flash存储24小时数据
  • 无线传输:通过ESP-01模块上传数据至物联网平台
  • 智能预警:当温湿度超出设定范围时显示警示图标
  • 多语言支持:通过字体库切换实现中英文显示

一个典型的天气预警实现:

void CheckWeatherAlert(void) { if(weather_cache.temperature > 30.0) { OLED_DrawBitmap(100, 0,高温图标, 16, 16); } else if(weather_cache.humidity > 80.0) { OLED_DrawBitmap(100, 0,高湿图标, 16, 16); } }

在完成这个项目的过程中,最令人惊喜的发现是OLED屏幕的局部刷新特性——通过精确控制刷新区域,可以将整体刷新时间从15ms降低到3ms左右。这种优化对于电池供电的设备尤其重要,它使得系统在保持实时性的同时,功耗降低了近40%。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询