用STM32F103C8T6和DS18B20做个智能温湿度监控器(附OLED显示和代码包)

张开发
2026/4/9 1:18:04 15 分钟阅读

分享文章

用STM32F103C8T6和DS18B20做个智能温湿度监控器(附OLED显示和代码包)
基于STM32F103C8T6与DS18B20的智能温控系统实战指南在创客圈子里温湿度监控一直是个经久不衰的经典项目。这次我们要做的不是简单的温度读数显示而是一个具备阈值报警、历史数据记录功能的智能监控系统。手头只需一块STM32F103C8T6开发板俗称蓝板、DS18B20温度传感器和0.96寸OLED屏幕就能搭建出远超基础功能的实用装置。这个项目的独特之处在于我们不仅会实现温度数据的精准采集还会设计完整的用户交互界面。通过按键设置报警阈值当温度异常时触发蜂鸣器报警同时OLED屏幕动态显示温度曲线。整套系统代码采用模块化设计方便后续扩展湿度传感器或无线传输功能。1. 硬件架构设计1.1 核心元件选型分析STM32F103C8T6作为主控芯片其72MHz主频和丰富的外设接口完全能满足我们的需求。相比ArduinoSTM32的优势在于更精确的定时器控制对DS18B20的时序要求至关重要更大的Flash存储空间可扩展数据记录功能更低的功耗适合长期运行DS18B20这款数字温度传感器的三大特点使其成为首选单总线接口仅需1个GPIO引脚测量范围-55°C至125°C±0.5°C的精度12位分辨率时1.2 电路连接方案完整接线图如下表示元件STM32引脚连接说明DS18B20 DATAPA4需接4.7K上拉电阻OLED SCLPB6I2C时钟线OLED SDAPB7I2C数据线蜂鸣器PB8低电平触发按键SETPB9阈值设置键下拉电阻按键ADDPB10参数增加键按键SUBPB11参数减少键注意DS18B20的电源引脚(VDD)可以接3.3V或5V但必须确保上拉电阻连接正确否则无法正常通信。2. 软件工程架构2.1 模块化代码组织我们采用分层设计各功能模块相互独立Project/ ├── Drivers/ │ ├── ds18b20.c # 温度传感器驱动 │ └── oled.c # 显示驱动 ├── Middlewares/ │ └── menu.c # 用户界面处理 └── Core/ ├── main.c # 主逻辑 └── system.c # 系统初始化2.2 DS18B20驱动优化原始代码中的延时函数需要改进我们采用SysTick定时器实现更精确的时序控制// 精确微秒延时基于72MHz系统时钟 void DS18B20_DelayUs(uint16_t us) { uint32_t ticks us * (SystemCoreClock / 1000000); uint32_t start DWT-CYCCNT; while((DWT-CYCCNT - start) ticks); }温度读取函数增加CRC校验确保数据可靠性float DS18B20_GetTemp(void) { uint8_t tempL, tempH, crc; int16_t temp; DS18B20_StartConversion(); DS18B20_ReadScratchpad(tempL, tempH, crc); if(DS18B20_CheckCRC(tempL, 8, crc)) { temp (tempH 8) | tempL; return temp * 0.0625f; // 12位分辨率 } return NAN; // 校验失败返回非数字 }3. 用户界面设计3.1 OLED多级菜单实现采用状态机模式管理界面切换typedef enum { MAIN_DISPLAY, SET_THRESHOLD, SET_ALARM, VIEW_HISTORY } MenuState; void Menu_Handler(void) { static MenuState state MAIN_DISPLAY; switch(state) { case MAIN_DISPLAY: Display_TempGraph(); if(KEY_SET_PRESSED) state SET_THRESHOLD; break; case SET_THRESHOLD: Display_ThresholdSetting(); if(KEY_ADD_PRESSED) Threshold; if(KEY_SUB_PRESSED) Threshold--; if(KEY_SET_PRESSED) state MAIN_DISPLAY; break; // 其他状态处理... } }3.2 温度曲线绘制技巧在128x64的OLED上实现平滑曲线显示void Draw_TempGraph(float *temps, uint8_t count) { uint8_t x, y, prev_y 0; float min_temp 20, max_temp 30; // 动态调整 // 找出极值 for(int i0; icount; i) { if(temps[i] min_temp) min_temp temps[i]; if(temps[i] max_temp) max_temp temps[i]; } // 绘制坐标轴 OLED_DrawLine(10, 10, 10, 54); OLED_DrawLine(10, 54, 118, 54); // 绘制曲线 for(x0; xcount; x) { y 54 - (uint8_t)((temps[x]-min_temp)*44/(max_temp-min_temp)); if(x0) OLED_DrawLine(12x*2, prev_y, 14x*2, y); prev_y y; } }4. 系统功能扩展4.1 报警触发机制实现温度超限时的多级报警void Check_Alarm(float current_temp) { static uint8_t alarm_level 0; if(current_temp Threshold 5) { if(alarm_level ! 2) { Buzzer_Beep(3, 200, 100); // 急促报警 alarm_level 2; } } else if(current_temp Threshold) { if(alarm_level ! 1) { Buzzer_Beep(1, 500, 0); // 单次提醒 alarm_level 1; } } else { alarm_level 0; } }4.2 数据记录功能利用STM32内部Flash模拟EEPROM存储历史数据#define FLASH_PAGE_SIZE 1024 #define DATA_START_ADDR 0x0801FC00 // 最后一页 void Save_ToFlash(float temp) { static uint16_t index 0; uint16_t temp_int (uint16_t)(temp * 10); // 保存1位小数 FLASH_Unlock(); FLASH_ErasePage(DATA_START_ADDR); for(int i0; iFLASH_PAGE_SIZE/2; i) { FLASH_ProgramHalfWord(DATA_START_ADDR i*2, (i index) ? temp_int : 0xFFFF); } index (index 1) % (FLASH_PAGE_SIZE/2); FLASH_Lock(); }5. 性能优化技巧5.1 低功耗处理当用于电池供电场景时可启用STM32的睡眠模式void Enter_SleepMode(void) { // 配置唤醒源如定时器或外部中断 RTC_SetWakeUpCounter(10); // 10秒后唤醒 PWR_EnterSTANDBYMode(); } void RTC_WKUP_IRQHandler(void) { if(RTC_GetITStatus(RTC_IT_WUT)) { RTC_ClearITPendingBit(RTC_IT_WUT); EXTI_ClearITPendingBit(EXTI_Line22); } }5.2 抗干扰设计针对DS18B20易受干扰的问题在数据线加10-100nF电容滤波通信失败时自动重试机制软件去抖动算法float Get_StableTemp(void) { float temps[3]; uint8_t retry 0; for(int i0; i3; i) { temps[i] DS18B20_GetTemp(); if(isnan(temps[i]) retry5) { i--; retry; DelayMs(100); } } // 取中值滤波 return (temps[0]temps[1]temps[2])/3; }6. 项目进阶方向这套基础框架可扩展为更复杂的监测系统多节点组网添加NRF24L01实现无线传感网络云端同步通过ESP8266上传数据到物联网平台能源管理增加太阳能充电电路外壳设计3D打印防水防尘外壳硬件连接示意图[STM32F103C8T6] --I2C-- [OLED] | |--单总线--[DS18B20] | |--GPIO--[按键矩阵] | |--PWM--[蜂鸣器]在调试过程中发现DS18B20的响应时间会随导线长度增加而变长。使用1米导线时建议将转换时间从750ms调整为1000ms并在代码中添加延时补偿。

更多文章