告别串口打印:用STM32 HAL库+DS18B20做个OLED屏显温度计(Keil工程开源)
STM32 HAL库实战打造OLED屏显温度计附完整Keil工程在嵌入式开发中将传感器数据可视化是提升用户体验的关键一步。想象一下当你的温度监测设备不再依赖笨重的串口调试工具而是通过一块精致的OLED屏幕实时显示数据这种即时的视觉反馈会让整个项目瞬间生动起来。本文将带你用STM32 HAL库驱动DS18B20温度传感器和SSD1306 OLED显示屏构建一个完整的温度监测系统。1. 硬件选型与工程搭建1.1 核心硬件组件这个项目的硬件架构非常简单只需要三个关键部件主控芯片STM32F103C8T6蓝色pill开发板温度传感器DS18B20防水型封装显示模块0.96寸OLEDSSD1306驱动I2C接口选择STM32F103的原因在于其广泛的社区支持和丰富的HAL库资源而DS18B20的单总线协议和OLED的I2C接口可以最大限度减少IO占用。以下是硬件连接示意图STM32引脚外设连接备注PA0DS18B20 DATA需接4.7K上拉电阻PB6OLED SCLI2C1时钟线PB7OLED SDAI2C1数据线1.2 开发环境配置在Keil MDK中新建工程时需要特别注意以下配置项// 在CubeMX中的关键配置 1. 启用I2C1标准模式100kHz 2. 配置PA0为GPIO输出DS18B20数据线 3. 开启Systick定时器用于us级延时提示建议先单独测试DS18B20和OLED模块的功能确保每个部件正常工作后再进行集成。2. DS18B20驱动优化2.1 单总线协议实现DS18B20的经典驱动通常包含大量延时函数这在结合OLED显示时可能导致屏幕刷新卡顿。我们通过以下优化提升系统响应速度// 优化后的延时函数基于Systick void DS18B20_Delay(uint16_t us) { uint32_t ticks us * (SystemCoreClock / 1000000); uint32_t start SysTick-VAL; while((start - SysTick-VAL) ticks); }关键改进点取消全局中断禁用改为关键段保护增加超时检测机制避免总线死锁采用HAL库标准的GPIO操作函数2.2 温度数据滤波处理工业级应用中简单的单次采样往往不够可靠。我们实现了一个滑动平均滤波器#define FILTER_SIZE 5 float TempFilter(float new_temp) { static float buffer[FILTER_SIZE] {0}; static uint8_t index 0; float sum 0; buffer[index] new_temp; if(index FILTER_SIZE) index 0; for(int i0; iFILTER_SIZE; i){ sum buffer[i]; } return sum / FILTER_SIZE; }3. OLED界面设计3.1 SSD1306驱动集成使用开源u8g2库可以快速实现OLED驱动以下是适配STM32 HAL的初始化代码// u8g2初始化结构体 u8g2_t u8g2; void OLED_Init(void) { u8g2_Setup_ssd1306_i2c_128x64_noname_f( u8g2, U8G2_R0, u8x8_byte_sw_i2c, u8x8_stm32_gpio_and_delay ); u8g2_InitDisplay(u8g2); u8g2_SetPowerSave(u8g2, 0); }3.2 温度显示UI设计一个专业的温度显示界面应该包含以下元素当前温度值大号字体温度变化趋势图极值记录单位标识°C/°F实现代码示例void DrawTempScreen(float temp) { char buf[20]; u8g2_ClearBuffer(u8g2); u8g2_SetFont(u8g2, u8g2_font_logisoso32_tf); sprintf(buf, %.1f, temp); u8g2_DrawStr(u8g2, 10, 40, buf); u8g2_SetFont(u8g2, u8g2_font_unifont_t_symbols); u8g2_DrawGlyph(u8g2, 90, 40, 0x00b0); // 度符号 u8g2_DrawStr(u8g2, 102, 40, C); u8g2_SendBuffer(u8g2); }4. 系统整合与性能优化4.1 任务调度策略为了避免温度采样影响显示流畅度我们采用状态机架构typedef enum { STATE_MEASURE_START, STATE_MEASURE_WAIT, STATE_DISPLAY_UPDATE } SystemState; void MainTask(void) { static SystemState state STATE_MEASURE_START; static uint32_t timer 0; static float current_temp 0; switch(state){ case STATE_MEASURE_START: DS18B20_Start(); state STATE_MEASURE_WAIT; timer HAL_GetTick(); break; case STATE_MEASURE_WAIT: if(HAL_GetTick() - timer 750){ // DS18B20转换需要750ms current_temp DS18B20_Get_Temp(); state STATE_DISPLAY_UPDATE; } break; case STATE_DISPLAY_UPDATE: DrawTempScreen(current_temp); state STATE_MEASURE_START; break; } }4.2 低功耗设计对于电池供电的应用我们可以进一步优化功耗在温度稳定时降低采样频率使用OLED的局部刷新功能配置STM32进入低功耗模式void EnterLowPowerMode(void) { // 配置GPIO为模拟输入最低功耗 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin GPIO_PIN_All; GPIO_InitStruct.Mode GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); // 进入STOP模式保留RAM内容 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); }5. 进阶功能扩展5.1 温度报警功能通过STM32的GPIO驱动蜂鸣器或LED实现超温报警#define TEMP_THRESHOLD 28.0f void CheckTempAlert(float temp) { static uint8_t alert_state 0; if(temp TEMP_THRESHOLD){ if(!alert_state){ HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_SET); alert_state 1; } }else{ if(alert_state){ HAL_GPIO_WritePin(BUZZER_GPIO_Port, BUZZER_Pin, GPIO_PIN_RESET); alert_state 0; } } }5.2 多传感器网络单总线协议的优势在于可以挂载多个DS18B20。修改搜索ROM命令即可实现多点测温void DS18B20_SearchRom(uint8_t *rom_code) { DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xF0); // Search ROM命令 for(int i0; i8; i){ rom_code[i] DS18B20_Read_Byte(); } }在实际项目中我发现OLED的刷新速率与温度采样周期需要精细平衡。当采样间隔设置为1秒时屏幕刷新会显得非常流畅而将温度滤波窗口设为5个样本可以有效消除数据抖动。