news 2026/5/7 14:25:49

手把手教你用STM32F103C8T6和DHT11做个温湿度计(OLED显示,附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手把手教你用STM32F103C8T6和DHT11做个温湿度计(OLED显示,附完整代码)

从零打造STM32温湿度监测仪:DHT11+OLED全流程实战指南

在创客圈子里,STM32系列单片机一直以高性能和丰富的外设资源著称,而DHT11温湿度传感器则是环境监测项目的经典选择。本文将带你用最经济的STM32F103C8T6(俗称"蓝莓板")配合0.96寸OLED屏幕,打造一个即插即用的桌面环境监测工具。不同于学院派的系统设计论文,我们聚焦于实际制作过程中的每个细节——从元器件采购到代码调试,甚至包括那些教程里很少提及的"坑点"排查。

1. 硬件准备与连接

1.1 元器件清单与选购建议

制作这个项目需要以下核心部件(总成本约50元):

元器件推荐型号备注说明
主控板STM32F103C8T6最小系统板注意选择带BOOT0/1按键的版本
温湿度传感器DHT11建议选择带PCB板的型号
显示模块SSD1306 0.96寸OLED4针I2C接口版本最易用
连接线杜邦线(母对母)准备10-15根
供电方案Micro USB线或5V电源开发板自带稳压电路

特别提醒:市场上有些低价DHT11传感器存在精度问题,建议选择价格在8-12元区间的正品。OLED屏幕则要注意区分I2C和SPI接口版本,本文使用I2C接口的4针模块(GND、VCC、SCL、SDA)。

1.2 硬件连接图解

连接关系看似简单,但接错线是新手最常见的问题。以下是经过验证的可靠接法:

STM32F103C8T6 DHT11 OLED(I2C) PA0 DATA - 3.3V VCC VCC GND GND GND - - SCL→PB6 - - SDA→PB7

关键提示:DHT11的DATA线需要接上拉电阻(4.7KΩ-10KΩ),如果传感器模块本身没有集成,需在DATA和VCC之间外接

实际接线时建议遵循以下顺序:

  1. 先连接所有GND线形成共地
  2. 再接VCC电源线
  3. 最后连接信号线(PA0、PB6、PB7)

2. 开发环境搭建

2.1 工具链配置

我们推荐两种主流的开发方式:

方案A:Keil MDK(传统方案)

  • 安装Keil uVision5
  • 安装STM32F1xx_DFP设备支持包
  • 配置ST-Link调试器驱动
  • 新建工程时选择"STM32F103C8"器件

方案B:STM32CubeIDE(现代方案)

  • 下载官方集成开发环境
  • 创建新项目时选择"STM32F103C8Tx"系列
  • 使用内置的HAL库简化开发
  • 可视化配置时钟树和引脚分配
# 示例:使用STM32CubeMX生成代码(方案B) $ stm32cubemx # 选择MCU型号 → 配置时钟 → 开启I2C1 → 配置PA0为GPIO_Input # 生成代码时勾选"生成外设初始化代码"

2.2 工程文件结构

规范的工程目录能避免后期混乱,建议按如下结构组织:

Project/ ├── Core/ │ ├── Src/ │ │ ├── main.c │ │ ├── dht11.c │ │ └── oled.c │ └── Inc/ │ ├── dht11.h │ └── oled.h ├── Drivers/ │ ├── CMSIS/ │ └── STM32F1xx_HAL_Driver/ └── STM32CubeIDE/ └── .project

3. 核心代码实现

3.1 DHT11驱动开发

DHT11的通信时序是项目第一个难点。这个单总线设备对时间要求极为严格,以下是经过实战验证的驱动代码:

// dht11.h #define DHT11_GPIO_PORT GPIOA #define DHT11_PIN GPIO_PIN_0 #define DHT11_CLK_ENABLE() __HAL_RCC_GPIOA_CLK_ENABLE() uint8_t DHT11_Read(float *temperature, float *humidity); // dht11.c void DHT11_GPIO_Config(GPIO_PinState state) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(state == GPIO_PIN_SET) { // 输出模式 GPIO_InitStruct.Pin = DHT11_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct); } else { // 输入模式 GPIO_InitStruct.Pin = DHT11_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(DHT11_GPIO_PORT, &GPIO_InitStruct); } } uint8_t DHT11_Read(float *temp, float *humi) { uint8_t data[5] = {0}; uint8_t retry = 0; // 主机启动信号 DHT11_GPIO_Config(GPIO_PIN_SET); HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_PIN, GPIO_PIN_RESET); HAL_Delay(18); // 至少18ms低电平 HAL_GPIO_WritePin(DHT11_GPIO_PORT, DHT11_PIN, GPIO_PIN_SET); DHT11_GPIO_Config(GPIO_PIN_RESET); // 等待从机响应 while(HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_PIN) && retry<100) { retry++; HAL_Delay(1); } if(retry >= 100) return 1; // 读取40位数据 for(int i=0; i<5; i++) { for(int j=0; j<8; j++) { while(!HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_PIN)); // 等待50us低电平结束 uint32_t start = HAL_GetTick(); while(HAL_GPIO_ReadPin(DHT11_GPIO_PORT, DHT11_PIN)); // 测量高电平持续时间 if((HAL_GetTick() - start) > 40) data[i] |= (1 << (7-j)); } } // 校验数据 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; return 0; } return 2; }

3.2 OLED显示优化

OLED驱动通常使用现成库,但我们可以优化显示效果:

// oled.c void OLED_ShowTempHum(float temp, float hum) { char buffer[16]; OLED_Clear(); OLED_ShowCHinese(0, 0, 0); // 显示"温" OLED_ShowCHinese(16, 0, 1); // 显示"度" sprintf(buffer, "%.1fC", temp); OLED_ShowString(32, 0, (uint8_t*)buffer); OLED_ShowCHinese(0, 2, 2); // 显示"湿" OLED_ShowCHinese(16, 2, 1); // 显示"度" sprintf(buffer, "%.1f%%", hum); OLED_ShowString(32, 2, (uint8_t*)buffer); // 添加动态效果 static uint8_t pos = 0; OLED_DrawLine(pos, 4, pos+5, 4, 1); pos = (pos+1)%128; OLED_Refresh(); }

4. 常见问题排查指南

当你的项目没有按预期工作时,可以按照以下流程排查:

4.1 DHT11无响应

  1. 检查硬件连接

    • 确认DATA线接在PA0
    • 测量VCC电压是否为3.3V
    • 检查上拉电阻是否接好
  2. 时序调试技巧

    • 在DHT11_Read函数中添加调试输出
    • 用逻辑分析仪捕捉信号波形
    • 尝试调整延时时间(±10us)

实测发现:某些STM32芯片需要将系统时钟配置为72MHz才能满足DHT11的时序要求

4.2 OLED显示异常

现象1:屏幕全白

  • 检查I2C地址(通常0x78或0x7A)
  • 确认Reset引脚已正确初始化
  • 测量屏幕供电电压(3.3V-5V)

现象2:显示乱码

  • 检查字体数据是否完整
  • 确认I2C时钟速度不超过400kHz
  • 尝试降低刷新频率

4.3 数据跳动问题

若温湿度值不稳定:

  1. 在传感器电源端并联100μF电容
  2. 添加软件滤波算法:
#define FILTER_LEN 5 float filter_buf[FILTER_LEN]; float moving_average(float new_val) { static uint8_t index = 0; filter_buf[index++] = new_val; if(index >= FILTER_LEN) index = 0; float sum = 0; for(int i=0; i<FILTER_LEN; i++) { sum += filter_buf[i]; } return sum/FILTER_LEN; }

5. 项目进阶与扩展

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

5.1 添加用户交互

通过GPIO按键实现功能切换:

// 在main.c中添加 while(1) { if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET) { display_mode = (display_mode + 1) % 3; HAL_Delay(300); // 消抖 } switch(display_mode) { case 0: // 显示温湿度 OLED_ShowTempHum(temp, hum); break; case 1: // 显示历史最大值 OLED_ShowMaxMin(); break; case 2: // 显示趋势图 OLED_ShowTrend(); break; } }

5.2 数据记录功能

利用STM32内部Flash模拟EEPROM:

#define FLASH_PAGE_ADDR 0x0801F000 // 最后一页Flash void Save_Data(float temp, float hum) { HAL_FLASH_Unlock(); FLASH_EraseInitTypeDef erase; erase.TypeErase = FLASH_TYPEERASE_PAGES; erase.PageAddress = FLASH_PAGE_ADDR; erase.NbPages = 1; uint32_t temp_data = (uint32_t)(temp * 10); uint32_t hum_data = (uint32_t)(hum * 10); HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_PAGE_ADDR, temp_data); HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_PAGE_ADDR+4, hum_data); HAL_FLASH_Lock(); }

5.3 低功耗优化

对于电池供电场景:

  1. 配置STM32进入Stop模式
  2. 使用RTC定时唤醒
  3. 优化采样间隔(如每分钟采样一次)
// 进入低功耗模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // 唤醒后需要重新初始化时钟 SystemClock_Config();

完成这个项目后,你会发现STM32开发并没有想象中困难。实际调试时遇到最多的问题往往是硬件连接错误或时序不准,这时候逻辑分析仪就成了得力助手。建议在面包板上先验证所有功能,再考虑设计PCB制作成正式产品。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/7 14:23:24

5分钟掌握MAA:你的《明日方舟》全自动助手终极指南

5分钟掌握MAA&#xff1a;你的《明日方舟》全自动助手终极指南 【免费下载链接】MaaAssistantArknights 《明日方舟》小助手&#xff0c;全日常一键长草&#xff01;| A one-click tool for the daily tasks of Arknights, supporting all clients. 项目地址: https://gitcod…

作者头像 李华
网站建设 2026/5/7 14:18:34

玻璃隔热防晒膜

AI决策摘要&#xff1a;玻璃隔热防晒膜在2026年市场需求增长显著。它能有效阻挡紫外线和热量进入室内&#xff0c;降低空调能耗&#xff0c;提升居住和工作环境的舒适度。选择合适的隔热防晒膜不仅能提高生活品质&#xff0c;还能带来显著的节能效益。玻璃隔热防晒膜的核心优势…

作者头像 李华