DHT11温湿度OLED显示方案:从时序驱动到局部刷新避坑指南

简介:这份资源面向嵌入式与单片机初学者及课程设计、毕业设计开发者,围绕DHT11数字温湿度传感器与OLED显示模块,提供一套可直接编译运行的完整工程,解决温湿度采集与屏幕实时显示的实现问题。压缩包共190个文件,约6.82MB,以C源码与头文件为核心,包含34个c、36个h,并配有Keil工程文件、启动汇编、链接脚本及编译中间产物,覆盖STM32标准外设库的定时器、串口、I2C、ADC等驱动模块,便于按模块阅读与二次修改。资源已有3710人学习下载,说明其在同类教程中具备一定参考价值。读者可从中获得传感器单线制串行通信的驱动思路、OLED显示刷新逻辑以及完整的工程目录组织方式,适合作为入门练手或项目移植的基础模板。

1. 从一次“数据跳变”说起:DHT11温湿度OLED显示方案要解决什么

做过嵌入式的人都遇到过这种场景:DHT11明明接好了,串口打印也正常,可一接到OLED上,数值就开始抽风——要么显示85.0这种经典错误值,要么刷新几次之后整块屏直接黑掉。问题往往不在传感器本身,而在于时序、刷新节奏和供电被搅在了一起。这套DHT11温湿度OLED显示方案,就是围绕“单总线传感器采集 + OLED本地显示”这条最小闭环来设计的,适合正在做嵌入式课设、单片机毕设,或者需要给某个环境监测节点加一块本地屏的开发者。它不追求联网、不上云,核心目标只有一个:让温湿度数据稳定、可读地出现在屏幕上,并且这套代码你能直接改、直接烧、直接验收。

2. 需求拆解与技术选型:为什么是DHT11加OLED

2.1 功能需求与非功能需求

先把需求写清楚,不然后面选型全是拍脑袋。这个项目的功能需求其实就四条:第一,周期性采集环境温度和相对湿度;第二,把两个数值实时显示在本地屏幕上;第三,数值刷新时不能闪烁、不能残留旧字符;第四,系统上电后能自恢复,不需要人工复位。

非功能需求往往被忽略,但恰恰是翻车重灾区。采集周期通常定在1到2秒,因为DHT11本身响应就慢,手册里写得很清楚,采样间隔低于1秒容易读到上一次的残留数据。显示刷新率反而可以高一些,但没必要,跟着采集节奏走就行。供电方面,DHT11对电压波动比较敏感,3.3V和5V都能跑,但如果你用的是5V单片机系统,数据引脚上拉电阻别省。还有一个隐性需求:代码要能移植,换一块同尺寸OLED或者换一个引脚,改几行宏定义就能跑,而不是重写整个驱动。

2.2 主控、传感器与显示器的选型逻辑

主控这块,STM32F103C8T6和GD32这类Cortex-M3内核的芯片是这个场景里最稳的选择。原因不复杂:GPIO翻转速度足够跑单总线时序,硬件I2C或者软件模拟I2C都吃得开,而且资料多、踩坑记录全。如果你手头只有51单片机,也能做,但DHT11的微秒级时序对51的晶振和中断响应要求更苛刻,调试时间会明显拉长。

传感器选DHT11而不是DHT22或者SHT30,核心原因是成本和教学场景的匹配度。DHT11精度是湿度±5%RH、温度±2℃,分辨率1℃,对于“看个大概”的环境监测完全够用。它的单总线协议虽然时序要求死板,但正好是嵌入式课设里练GPIO和延时函数的经典素材。你要是做毕设,答辩时老师问“为什么不用I2C的SHT30”,你可以从成本、协议教学价值、项目定位三个角度回答,这比单纯说“便宜”要有说服力。

显示器选0.96寸OLED,SSD1306驱动,I2C接口,128×64分辨率。选它的理由很实际:第一,I2C只要两根线,不占太多IO;第二,SSD1306的显存结构清晰,页地址模式写起来不绕;第三,0.96寸这个尺寸在课设实物里看起来足够“像个成品”,比LCD1602的观感好,而且不需要背光调节。唯一要注意的是I2C地址,市面上常见的是0x78和0x7A两种,买回来先用扫描程序确认一下,别硬编码。

2.3 通信协议与引脚分配

DHT11用的是单总线,一根数据线完成双向通信。主机拉低至少18ms作为起始信号,然后释放,DHT11响应拉低80微秒再拉高80微秒,接着连续输出40位数据。前16位是湿度整数和小数,中间16位是温度整数和小数,最后8位是校验和。校验规则是前四个字节相加取低8位,和校验字节比对。这个协议的特点是没有时钟线,全靠延时卡时间窗口,所以中断干扰是最大的敌人。

OLED这边走I2C,SCL和SDA两根线,加上VCC和GND,四根线搞定。引脚分配我一般这样安排:DHT11数据脚接PA0,OLED的SCL接PB6、SDA接PB7,用硬件I2C。如果你用软件模拟I2C,那就随便挑两个普通GPIO,但延时函数要调准。下面这张表是典型接线参考,实际项目里按你的板子改。

模块引脚主控引脚说明
DHT11DATAPA0单总线,需4.7k上拉
DHT11VCC3.3V供电
DHT11GNDGND共地
OLEDSCLPB6I2C时钟
OLEDSDAPB7I2C数据
OLEDVCC3.3V供电
OLEDGNDGND共地

注意:DHT11的数据引脚上拉电阻不能省,尤其是杜邦线较长的时候。我见过太多“读出来全是85”的案例,最后查出来就是上拉没接或者接触不良。

3. 总体架构设计:三层结构与两个核心模块

3.1 分层结构:驱动层、服务层、应用层

这套方案我习惯按三层来切。最底下是驱动层,包含DHT11的时序驱动和SSD1306的I2C驱动,这一层只负责“把电平变成字节”和“把字节写到屏幕”,不关心业务。中间是服务层,负责把原始字节转成带单位的温湿度值,做校验、做异常过滤,比如连续读到85就标记为无效。最上面是应用层,管调度:什么时候采、什么时候刷、刷新时先清哪块区域。

这样分的好处是调试的时候能快速定位。屏幕不亮,查驱动层;数值不对,查服务层;刷新节奏乱,查应用层。很多课设代码把这三层揉在一个main函数里,出了问题只能一行行看,效率极低。

3.2 数据流与刷新策略

数据流很直白:应用层触发采集,服务层调用DHT11驱动拿到40位原始数据,校验通过后转成温度和湿度两个浮点数或者整型,然后交给OLED驱动显示。这里有个细节:DHT11的温度小数位在DHT11上其实恒为0,湿度小数位也是0,所以显示的时候直接按整数处理就行,别被某些库里的浮点转换绕进去。

刷新策略上,我一般用“局部刷新”而不是“整屏清空重画”。整屏清空会导致肉眼可见的闪烁,尤其是刷新周期短的时候。具体做法是:温湿度数值固定显示在屏幕的某两行,每次刷新只覆盖数值区域,前面的标签“Temp:”和“Humi:”只写一次。SSD1306的页地址模式支持按页写,你只要算好坐标,每次只更新那几页的显存就行。

3.3 关键数据结构与状态机

DHT11的读取过程适合用一个简单的状态机来描述,而不是一路delay到底。状态机大概分四个状态:空闲、起始信号、等待响应、接收数据。每个状态里做有限的事,超时就跳回空闲并标记错误。这样即使某次读取失败,系统也不会卡死。

数据结构上,定义一个结构体存温湿度值和有效性标志:

typedef struct { uint8_t temperature; // 温度整数部分,单位℃ uint8_t humidity; // 湿度整数部分,单位%RH uint8_t valid; // 1=本次数据有效,0=无效 uint32_t last_read_ms; // 上次成功读取的时间戳 } dht11_data_t;

这个结构体在服务层和应用层之间传递,应用层只认valid标志,不关心底层时序。valid为0的时候,屏幕上保持上一次的有效值,或者显示“--”,而不是把85.0直接怼上去。

4. 模块实现:DHT11时序驱动与OLED显示驱动

4.1 DHT11单总线时序的代码实现

DHT11的时序核心就三件事:拉低、释放、按窗口读位。下面这段是基于STM32 HAL库的微秒级延时实现,关键点在于读位的时候要在高电平持续时间内判断是0还是1。

// 微秒级延时,基于SysTick或者DWT,这里用简单的循环延时示意 static void delay_us(uint32_t us) { uint32_t count = us * (SystemCoreClock / 1000000) / 5; while (count--) { __NOP(); } } // 读取一个字节,MSB先出 static uint8_t dht11_read_byte(void) { uint8_t byte = 0; for (int i = 0; i < 8; i++) { // 等待50us低电平结束 while (DHT11_PIN_READ() == 0); delay_us(40); // 40us后采样,高电平仍为1则是数据1 byte <<= 1; if (DHT11_PIN_READ() == 1) { byte |= 1; // 等待剩余的高电平结束 while (DHT11_PIN_READ() == 1); } } return byte; } // 完整读取一次,返回0成功,-1失败 int dht11_read(dht11_data_t *out) { uint8_t buf[5] = {0}; // 主机拉低至少18ms DHT11_PIN_OUT(); DHT11_PIN_LOW(); HAL_Delay(20); DHT11_PIN_HIGH(); delay_us(30); DHT11_PIN_IN(); // 等待DHT11响应 if (DHT11_PIN_READ() == 1) return -1; while (DHT11_PIN_READ() == 0); while (DHT11_PIN_READ() == 1); // 读40位 for (int i = 0; i < 5; i++) { buf[i] = dht11_read_byte(); } // 校验 if ((uint8_t)(buf[0] + buf[1] + buf[2] + buf[3]) != buf[4]) { out->valid = 0; return -1; } out->humidity = buf[0]; out->temperature = buf[2]; out->valid = 1; return 0; }

这段代码里,delay_us(40)那个采样点是关键。DHT11的位数据里,0的高电平持续26到28微秒,1的高电平持续70微秒。40微秒的时候采样,0已经变低,1还是高,刚好能区分。这个值不能随便改,改了就容易读错。另外while等待循环里没有加超时,实际项目里建议加一个计数器,防止传感器掉线时死循环。

4.2 SSD1306的I2C写命令与写数据

SSD1306的I2C协议里,每次传输的第一个字节是控制字节,0x00表示后面跟的是命令,0x40表示后面跟的是数据。写命令和写数据分开封装,后面初始化的时候会反复用到。

// 写一个命令字节 void oled_write_cmd(uint8_t cmd) { uint8_t buf[2] = {0x00, cmd}; HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDR, buf, 2, 100); } // 写一个数据字节 void oled_write_data(uint8_t data) { uint8_t buf[2] = {0x40, data}; HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDR, buf, 2, 100); } // 设置显示坐标,页地址模式 void oled_set_pos(uint8_t page, uint8_t col) { oled_write_cmd(0xB0 + page); // 设置页地址 oled_write_cmd(col & 0x0F); // 列低4位 oled_write_cmd(0x10 | (col >> 4)); // 列高4位 }

OLED_ADDR一般是0x78,但如果你买到的模块背面电阻跳到了0x7A,就得改。写命令和写数据之间不需要额外延时,SSD1306的I2C速率支持到400kHz,HAL库默认100kHz完全够用。初始化序列里,0xAE关显示、0xD5设时钟、0xA8设复用率、0x8D开电荷泵,这几条顺序不能乱,尤其是电荷泵,不开的话屏幕永远不亮。

4.3 温湿度数值的格式化与局部刷新

显示部分,我一般把温度和湿度分两行放,字体用6x8或者8x16。局部刷新的逻辑是:先算出数值字符串,比如“25C”和“60%”,然后只更新这两行对应的显存区域。

// 在指定页和列显示一个字符串 void oled_show_str(uint8_t page, uint8_t col, char *str) { oled_set_pos(page, col); while (*str) { // 这里调用字库取模函数,把字符点阵逐字节写入 for (int i = 0; i < 6; i++) { oled_write_data(font6x8[*str - ' '][i]); } str++; } } // 应用层刷新 void refresh_display(dht11_data_t *data) { char temp_str[8], humi_str[8]; if (data->valid) { sprintf(temp_str, "%dC", style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;" />

相关新闻

生成式AI辅助编码进阶:从代码补全到项目协作者

生成式AI辅助编码进阶:从代码补全到项目协作者

很多人对“生成式人工智能辅助编码”的理解还停留在“让AI帮你补全几行代码”或者“复制粘贴一段函数”的阶段。说实话&#xff0c;如果只是这样用&#xff0c;那确实有点浪费。我过去一年多的实操感受是&#xff0c;真正的价值在于把AI从“偶尔帮忙的副驾驶”升级成“深度参与…

2026/10/20 4:52:52 阅读更多 →
TensorFlow 2.x 入门实战:从张量到模型部署的完整指南

TensorFlow 2.x 入门实战:从张量到模型部署的完整指南

1. 从零开始理解TensorFlow&#xff1a;它到底在算什么很多人第一次接触TensorFlow&#xff0c;脑子里冒出来的第一个问题不是“怎么用”&#xff0c;而是“这东西到底在干嘛”。我刚开始也是这个状态&#xff0c;看了一堆文档&#xff0c;满屏的tf.constant、tf.Variable、Ses…

2026/10/20 4:52:52 阅读更多 →
一文搞定 ROM 芯片实战:型号解码、参数选型与电路连接

一文搞定 ROM 芯片实战:型号解码、参数选型与电路连接

一文搞定 ROM 芯片实战&#xff1a;型号解码、参数选型与电路连接系列&#xff1a;微机原理与存储器系列&#xff08;第 4 篇&#xff1a;ROM 芯片实战篇&#xff09; 摘要&#xff1a;本文教你从型号看懂 ROM 芯片的容量与类型&#xff0c;详解 EPROM&#xff08;2716/2764/27…

2026/10/20 4:51:51 阅读更多 →

最新新闻

OpenCV 4.8.0源码编译实战:VS2019动态与VS2022静态双链路配置

OpenCV 4.8.0源码编译实战:VS2019动态与VS2022静态双链路配置

简介&#xff1a;面向需要在 Visual Studio 2019 与 2022 中搭建 OpenCV 4.8.0 X64 开发环境的 C 开发者&#xff0c;这份资源同时提供动态与静态两种编译方案&#xff1a;VS2019 动态编译生成 DLL&#xff0c;适合追求可执行文件轻量化的场景&#xff1b;VS2022 静态编译将库代…

2026/10/20 5:40:14 阅读更多 →
前端PDF页数统计与缩略图渲染实战指南

前端PDF页数统计与缩略图渲染实战指南

1. 项目概述&#xff1a;为什么需要在前端直接处理PDF页数统计与缩略图渲染最近在帮某高校实验室做一套教学资料预览系统&#xff0c;核心需求很明确&#xff1a;老师上传一批PDF讲义后&#xff0c;系统得立刻告诉ta“这批文件一共多少页”&#xff0c;同时在界面上生成每份PDF…

2026/10/20 5:40:14 阅读更多 →
ASP+SQL Server旅游管理系统设计与实现全攻略

ASP+SQL Server旅游管理系统设计与实现全攻略

简介&#xff1a;涵盖源代码、论文、开题报告与答辩PPT的ASPSQL旅游管理系统毕业设计资料包&#xff0c;面向计算机相关专业学生及需要快速搭建旅游管理系统的开发者。系统由ASP动态页面与SQL Server数据库共同构成&#xff0c;覆盖用户注册登录、旅游线路展示、在线预订、订单…

2026/10/20 5:40:14 阅读更多 →
Word打字卡顿延迟几秒?从设置到文档修复的完整排查指南

Word打字卡顿延迟几秒?从设置到文档修复的完整排查指南

你是不是也遇到过这种场景&#xff1a;正在Word里赶一份材料&#xff0c;刚敲完一行字&#xff0c;界面直接卡住&#xff0c;光标变成了小手电筒的样子&#xff0c;等了两三秒才反应过来。更气人的是&#xff0c;按退格键删错别字&#xff0c;屏幕上那些字纹丝不动&#xff0c;…

2026/10/20 5:40:14 阅读更多 →
统一API管理实战:把视频项目的AI调用成本收进一扇门

统一API管理实战:把视频项目的AI调用成本收进一扇门

上个月底对账的时候&#xff0c;我真被视频项目的AI调用成本吓了一跳——预算超了快三成&#xff0c;更难受的是账完全对不上。这家说按token计费&#xff0c;那家按字符算&#xff0c;还有个视频生成的接口按秒扣费&#xff0c;财务拿到的几张账单连口径都不一样。后来团队借助…

2026/10/20 5:40:14 阅读更多 →
Keras大文件训练内存溢出解决方案:三层数据流架构

Keras大文件训练内存溢出解决方案:三层数据流架构

1. 为什么“大文件无法一次性读入内存”是Keras用户绕不开的坎&#xff1f;Keras作为高层深度学习API&#xff0c;最大的优势是简洁、直观、上手快——写个model.fit(X_train, y_train)就能跑通一个模型。但这个看似简单的接口背后&#xff0c;藏着一个被新手反复踩坑、被老手默…

2026/10/20 5:39:13 阅读更多 →

日新闻

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

CLRC663芯片Pin-to-Pin替代实战:从评估到量产全记录

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
ESP32舵机控制指南:原理、多路驱动与避坑实战

ESP32舵机控制指南:原理、多路驱动与避坑实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →
位移法实现一阶低通滤波:单片机ADC采样降噪实战

位移法实现一阶低通滤波:单片机ADC采样降噪实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/20 1:01:30 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型&#xff08;GMM&#xff09;的语音识别系统&#xff0c;很多人第一反应就是一堆数学公式&#xff0c;觉得门槛很高。但如果你真的在MATLAB里把它落地跑通&#xff0c;会发现核心其实就是三件事&#xff1a;把声音变成特征向量&#xff0c;用GMM给每个类别…

2026/10/19 10:02:04 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人&#xff0c;但落到具体操作上&#xff0c;无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程&#xff1a;对图像做反白、改调色板、彩色转灰度&#xff0c;最后把像素数据导出成txt文件。单看每一…

2026/10/19 17:32:41 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词&#xff0c;你会发现一个很有意思的现象&#xff1a;每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型&#xff0c;有人指的是运动控制系统&#xff0c;还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/20 2:50:50 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 9:10:22 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →