1.3寸单色OLED屏驱动移植与温湿度显示实战:基于CW32F030C8T6与DHT11
1.3寸单色OLED屏驱动移植与温湿度显示实战基于CW32F030C8T6与DHT11最近在做一个环境监测的小项目需要把温湿度数据直观地显示出来。我选择了1.3寸的单色OLED屏搭配DHT11温湿度传感器主控用的是立创的CW32F030C8T6开发板。这套组合成本低、效果好非常适合初学者学习嵌入式外设驱动和显示技术。今天我就来手把手教你如何把OLED屏的驱动移植到CW32F030C8T6上并读取DHT11的数据最终在屏幕上实时显示温湿度。整个过程我会详细拆解从硬件连接到软件驱动再到数据整合显示保证你跟着做就能成功。1. 项目硬件准备与连接在开始写代码之前咱们先把硬件搞清楚、连对线。这是后续所有工作的基础线接错了代码写得再好也没用。1.1 认识我们的“主角”这次项目用到三个核心部件主控MCU立创CW32F030C8T6开发板。这是一款基于ARM Cortex-M0内核的微控制器性能足够应对我们这个项目而且资料开源对初学者友好。传感器DHT11温湿度传感器。它是一个数字传感器只用一根数据线就能同时读取温度和湿度非常方便。它的精度对于日常环境监测完全够用。显示屏1.3寸单色OLED屏。这种屏幕是自发光的不需要背光显示对比度高功耗低而且接口简单通常使用I2C或SPI通信。1.2 硬件连接图思路由于原始资料主要提供了DHT11的驱动我们这里重点讲解DHT11的连接。OLED屏的连接需要根据你手头屏幕的具体型号是I2C接口还是SPI接口来确定但原理是相通的。DHT11模块连接DHT11模块通常有3个引脚VCC, GND, DATA。我们需要将它连接到CW32开发板的GPIO上。VCC- 开发板的3.3V引脚GND- 开发板的GND引脚DATA- 开发板的GPIO引脚例如 PB0注意DHT11的数据线DATA在空闲时必须保持高电平。好在模块板上通常已经集成了上拉电阻所以我们直接连接GPIO即可。如果没有就需要在DATA线和VCC之间接一个4.7K-10K的上拉电阻。OLED屏连接以常见的I2C接口为例I2C接口的OLED通常有4个引脚VCC, GND, SCL, SDA。VCC- 开发板的3.3V引脚GND- 开发板的GND引脚SCL- 开发板的I2C时钟引脚例如 PB6SDA- 开发板的I2C数据引脚例如 PB7请务必查阅你OLED屏的资料确认其通信接口和引脚定义。2. DHT11温湿度传感器驱动详解DHT11的驱动是整个数据采集的关键。它的通信协议是“单总线”听起来简单但时序要求很严格写代码时得特别小心。2.1 单总线通信时序剖析你可以把单总线想象成一条独木桥主机MCU和从机DHT11都要按严格的顺序和时间通过不能抢行。一次完整的DHT11数据读取分为四个阶段起始信号MCU发起聊天。MCU把数据线配置为输出模式拉低至少18毫秒。然后MCU释放总线拉高等待20-40微秒。代码体现就是输出低电平 - 延时19ms - 输出高电平 - 延时20us。响应信号DHT11回应“我在请讲”。MCU将数据线切换为输入模式。DHT11会先把总线拉低约80微秒然后再拉高80微秒告诉MCU它准备好了。代码里我们需要等待这个低电平的到来如果等不到超时说明通信失败。数据传输DHT11发送数据。DHT11发送40位数据。每一位都以一个54微秒的低电平开始。紧接着是一个高电平它的持续时间决定了这一位是0还是126-28微秒的高电平表示位‘0’。70微秒的高电平表示位‘1’。我们的策略是等待每个位开始的低电平过去后延时28微秒一个介于0和1之间的时间点再去读取引脚电平。如果此时还是高电平那肯定是‘1’如果是低电平那就是‘0’。结束信号DHT11发送完数据后会拉低总线54微秒然后释放。MCU需要重新将总线设置为输出模式并拉高结束本次通信。2.2 数据格式与校验DHT11一次发送40位5个字节数据。这5个字节的含义和校验方法至关重要数据段字节1字节2字节3字节4字节5含义湿度整数湿度小数温度整数温度小数校验和说明例如35固定为0例如24例如4前4字节相加的低8位举个例子如果收到数据0x23, 0x00, 0x18, 0x04, 0x3F。湿度 0x23 35 %RH温度 0x18 0x04 * 0.1 24 0.4 24.4 ℃校验和 0x23 0x00 0x18 0x04 0x3F与收到的第5字节(0x3F)一致数据有效。如果校验和不一致说明传输过程中可能受到了干扰这次数据应该丢弃重新读取。2.3 驱动代码移植与解析原始资料提供了完整的DHT11驱动代码我们把它移植到自己的工程里就行。这里我挑核心函数DHT11_Read_Data讲讲关键点。首先在你的工程里新建dht11.c和dht11.h两个文件。dht11.h 头文件关键配置这里主要是引脚定义你需要根据自己实际的连接来修改。比如我的DATA线接在PB0上。// dht11.h #ifndef _BSP_DHT11_H_ #define _BSP_DHT11_H_ #include board.h /**************引脚修改此处****************/ #define RCC_DHT11_GPIO_ENABLE() __RCC_GPIOB_CLK_ENABLE() #define PORT_DHT11 CW_GPIOB #define GPIO_DHT11 GPIO_PIN_0 // 根据你的连接修改引脚号 //设置DHT11输出高或低电平 #define DATA_GPIO_OUT(x) GPIO_WritePin(PORT_DHT11, GPIO_DHT11, x ? GPIO_Pin_SET : GPIO_Pin_RESET) //获取DHT11数据引脚高低电平状态 #define DATA_GPIO_IN GPIO_ReadPin(PORT_DHT11, GPIO_DHT11) extern float temperature; extern float humidity; void DHT11_GPIO_Init(void); unsigned int DHT11_Read_Data(void); float Get_temperature(void); float Get_humidity(void); #endifdht11.c 核心读取函数解析这个函数严格遵循了我们上面分析的时序。// dht11.c 部分代码 unsigned int DHT11_Read_Data(void) { int i; long long val0; // 用于存储40位原始数据 int timeout0; float small_point0; unsigned char verify_num 0; // 1. 发送起始信号 DATA_GPIO_OUT(0); // 主机拉低数据线 delay_ms(19); // 保持低电平至少18ms这里给19ms留点余量 DATA_GPIO_OUT(1); // 主机释放总线拉高 delay_us( 20 ); // 拉高后等待20us // 2. 切换为输入模式等待DHT11响应 DHT11_GPIO_Mode_IN(); // 等待DHT11拉低响应信号开始 timeout 5000; while( (! DATA_GPIO_IN ) ( timeout 0 ) )timeout--; if(timeout 0) return 0; // 超时响应失败 // 等待DHT11拉高响应信号结束准备发数据 timeout 5000; while( DATA_GPIO_IN ( timeout 0 ) )timeout-- ; if(timeout 0) return 0; // 超时 // 3. 接收40位数据 #define CHECK_TIME 28 // 关键延时用于区分0和1 for(i0;i40;i) { timeout 5000; // 等待每位开始的低电平过去约54us while( ( !DATA_GPIO_IN ) (timeout 0) ) timeout--; if(timeout 0) break; // 超时退出 delay_us(CHECK_TIME); // 延时28us后采样 // 判断当前电平决定是0还是1 if ( DATA_GPIO_IN ) // 还是高电平说明是1 { val(val1)1; // 左移一位末尾加1 } else // 是低电平说明是0 { val1; // 左移一位末尾加0 } // 等待当前位的高电平结束如果是1则等待剩余的高电平时间 timeout 5000; while( DATA_GPIO_IN (timeout 0) ) timeout-- ; } // 4. 通信结束主机重新控制总线 DHT11_GPIO_Mode_OUT(); DATA_GPIO_OUT(1); // 5. 校验数据 // 计算前4个字节的和 verify_num (val32) (val24) (val16) (val8); // 与接收到的校验和第5字节比较 verify_num verify_num - (val0xff); if( verify_num ) // 校验和不等于0说明错误 { return 0; } else // 校验成功解析数据 { // 解析湿度整数部分小数部分 humidity (val32)0xff; small_point (val24)0x00ff; small_point small_point * 0.1; humidity humidity small_point; // 解析温度整数部分小数部分 temperature (val16)0x0000ff; small_point (val8)0x000000ff; small_point small_point * 0.1; temperature temperature small_point; return val8; // 可以返回原始数据供其他用途 } }踩坑提示CHECK_TIME这个延时值是区分数据0和1的关键。28us是一个经验值因为‘0’的高电平是26-28us‘1’的高电平是70us。在28us时采样能可靠地区分两者。如果发现数据偶尔错乱可以微调这个值并用逻辑分析仪抓取时序波形进行对比。2.4 在主函数中测试将驱动文件添加到工程后在主函数里初始化并循环读取可以通过串口打印数据来验证。// main.c #include board.h #include stdio.h #include bsp_uart.h #include dht11.h int32_t main(void) { board_init(); // 开发板初始化 uart1_init(115200); // 初始化串口用于打印数据 DHT11_GPIO_Init(); // DHT11引脚初始化 delay_ms(1000); // 上电后等待传感器稳定 printf(DHT11 Test Start\r\n); while(1) { if(DHT11_Read_Data()) // 如果读取成功 { printf(Temp: %.1f C, Humi: %.1f %%RH\r\n, Get_temperature(), Get_humidity()); } else { printf(DHT11 Read Error!\r\n); } delay_ms(2000); // 每隔2秒读取一次DHT11两次读取间隔需大于1秒 } }编译下载到开发板打开串口助手你应该能看到每隔2秒打印出的温湿度数据。如果显示“Read Error”请检查硬件连接、引脚配置以及CHECK_TIME延时参数。3. 1.3寸OLED屏驱动移植OLED屏的驱动移植相对独立。你需要找到对应你屏幕型号的驱动代码通常是oled.c和oled.h。市面上常见的OLED驱动芯片是SSD1306驱动代码很多。3.1 驱动适配关键点无论你拿到的是I2C还是SPI的驱动代码移植到CW32F030上主要修改以下几个地方硬件接口函数重写驱动代码底层一定有OLED_WR_Byte写字节、OLED_Init初始化这样的函数里面包含了具体的GPIO操作或I2C/SPI发送函数。你需要将这些函数内部对硬件的操作替换成CW32 HAL库的函数。如果是I2C使用CW32的CW_I2C库函数进行读写。如果是SPI使用CW32的CW_SPI库函数进行读写。如果是模拟GPIO软件I2C/SPI修改里面的OLED_SCL、OLED_SDA等宏定义对应的CW32 GPIO操作函数。延时函数替换驱动代码里可能有delay_ms或delay_us确保它们指向你工程里可用的延时函数。屏幕尺寸配置在oled.h中确认OLED_WIDTH和OLED_HEIGHT被正确设置为你的屏幕分辨率例如128x64。3.2 显示温湿度数据驱动移植成功后OLED屏应该能显示测试图形或文字了。接下来我们把DHT11读取的数据显示上去。通常OLED驱动会提供字符和字符串显示函数比如OLED_ShowString、OLED_ShowNum。我们需要做的是在main.c中包含OLED头文件。在main函数中在初始化DHT11之后初始化OLED屏。在while(1)循环中读取DHT11数据后调用OLED显示函数来刷新屏幕。// 在main.c中 #include oled.h int32_t main(void) { char str_buf[20]; // 用于格式化字符串的缓冲区 board_init(); uart1_init(115200); DHT11_GPIO_Init(); OLED_Init(); // 初始化OLED OLED_Clear(); // 清屏 delay_ms(1000); while(1) { if(DHT11_Read_Data()) // 读取数据成功 { float temp Get_temperature(); float humi Get_humidity(); // 通过串口打印 printf(Temp: %.1f C, Humi: %.1f %%RH\r\n, temp, humi); // 在OLED上显示 OLED_Clear(); // 清屏准备刷新也可局部刷新优化 OLED_ShowString(0, 0, Env Monitor, 16); // 第0行显示标题 OLED_ShowString(0, 2, Temp:, 16); // 第2行 sprintf(str_buf, %.1f C, temp); // 将浮点数格式化为字符串 OLED_ShowString(40, 2, (uint8_t*)str_buf, 16); OLED_ShowString(0, 4, Humi:, 16); // 第4行 sprintf(str_buf, %.1f %%, humi); OLED_ShowString(40, 4, (uint8_t*)str_buf, 16); OLED_Refresh(); // 更新显示到屏幕 } else { OLED_ShowString(0, 6, Sensor Error!, 16); OLED_Refresh(); } delay_ms(2000); // 2秒更新一次 } }3.3 优化与调试建议避免频繁清屏OLED_Clear()会清除整个屏幕缓冲区再全部重画可能导致闪烁。可以优化为只更新数字变化的区域。处理读取失败DHT11容易受干扰一次读取失败是正常的。可以增加重试机制比如连续读取3次取其中校验成功的两次结果。检查电源确保给DHT11和OLED的电源3.3V稳定。不稳定的电源是通信失败的常见原因。使用逻辑分析仪如果时序怎么调都不对逻辑分析仪是终极武器。用它抓取DATA线上的实际波形和DHT11数据手册的时序图对比一目了然。按照以上步骤你应该就能在CW32F030C8T6开发板上成功驱动OLED屏并显示来自DHT11的实时温湿度数据了。这个项目虽然小但涵盖了GPIO控制、精确延时、单总线协议、数据校验、外设驱动移植和显示输出等多个嵌入式开发基础知识点非常适合用来练手和巩固基础。动手试试吧遇到问题多在论坛里交流讨论。

相关新闻

破解云盘限速困局:网盘直链下载助手的技术突围之路

破解云盘限速困局:网盘直链下载助手的技术突围之路

破解云盘限速困局:网盘直链下载助手的技术突围之路 【免费下载链接】Online-disk-direct-link-download-assistant 可以获取网盘文件真实下载地址。基于【网盘直链下载助手】修改(改自6.1.4版本) ,自用,去推广&#xf…

2026/7/5 16:02:24 阅读更多 →
AD9361配置802.11a无线通信的5个关键参数详解(附FPGA对接指南)

AD9361配置802.11a无线通信的5个关键参数详解(附FPGA对接指南)

AD9361配置802.11a无线通信的5个关键参数详解(附FPGA对接指南) 对于从事无线通信系统开发的硬件工程师和FPGA开发者而言,将一款高性能的射频收发器与一个成熟的通信协议栈进行无缝对接,往往是项目中最具挑战性也最富成就感的环节。…

2026/7/6 15:28:05 阅读更多 →
告别网盘限速:直链下载工具如何突破云盘速度壁垒

告别网盘限速:直链下载工具如何突破云盘速度壁垒

告别网盘限速:直链下载工具如何突破云盘速度壁垒 【免费下载链接】Online-disk-direct-link-download-assistant 可以获取网盘文件真实下载地址。基于【网盘直链下载助手】修改(改自6.1.4版本) ,自用,去推广&#xff0…

2026/7/7 1:38:38 阅读更多 →

最新新闻

开发环境准备

开发环境准备

配置深度学习环境 配置参考 vscode连接到conda环境 1.安装python插件 2.打开自己的.py文件 3.Ctrl Shift P 呼出命令面板,输入Python: Select Interpreter,选择自己的conda环境 4.执行测试 import torch import timeprint("" * 40) prin…

2026/7/7 1:45:57 阅读更多 →
当我想给小说配音时,我到底经历了什么

当我想给小说配音时,我到底经历了什么

事情的起因很简单 我写了一本小说,大概十几万字,想让它在喜马拉雅上「活」起来。不是那种机器念经式的AI朗读,而是真正的、有情绪起伏的、分角色的有声书——旁白沉稳克制,主角鲜活有记忆点,反派说话自带压迫感&#x…

2026/7/7 1:43:57 阅读更多 →
CUDA 12.x 环境诊断:3 种方法区分 Driver、Runtime 与 NVCC 版本差异

CUDA 12.x 环境诊断:3 种方法区分 Driver、Runtime 与 NVCC 版本差异

CUDA 12.x 环境诊断:3 种方法区分 Driver、Runtime 与 NVCC 版本差异当你在Windows上部署PyTorch或TensorFlow时,是否经常遇到"CUDA版本不匹配"的报错?这通常是因为开发者混淆了CUDA Driver、Runtime和NVCC这三个关键组件的版本。本…

2026/7/7 1:43:57 阅读更多 →
ROS2话题通信Python实现详解

ROS2话题通信Python实现详解

目录 一、引言 二、准备工作 2.1 安装ROS2 2.2 创建工作空间和功能包 三、简单文本话题通信 3.1 编写发布方代码(publisher.py) 3.2 编写订阅方代码(subscriber.py) 3.3 运行节点 四、自定义接口话题通信 4.1 定义自定义…

2026/7/7 1:39:56 阅读更多 →
FPG平台:从公开信息出发,梳理信息披露习惯与流程清晰度

FPG平台:从公开信息出发,梳理信息披露习惯与流程清晰度

在外汇行业语境里,表达越清晰、信息越透明,越容易建立稳定预期。在FPG平台的外汇服务中,从公开信息与使用体验出发,梳理其更值得肯定的能力点与细节表现。在外汇相关服务中,读者最在意的通常是信息是否清楚、提示是否到…

2026/7/7 1:35:55 阅读更多 →
第 二 章线性代数

第 二 章线性代数

文章目录2.1 标量与向量2.1.1 标量与向量的概念2.1.2 向量运算2.1.3 向量范数2.2 矩阵与张量2.2.1 矩阵的概念2.2.2 矩阵乘法2.2.3 矩阵转置2.2.4 矩阵的逆2.2.5 其他矩阵运算2.2.6 张量2.3 矩阵求导2.3.1 常用求导结果2.3.2 Jacobian矩阵与梯度矩阵2.3.3 一阶实矩阵微分&#…

2026/7/7 1:33:55 阅读更多 →

日新闻

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

鸿蒙新特性:图片画廊与轮播导航——构建沉浸式图片浏览体验

图片浏览是移动应用中最高频的场景之一。从社交应用的照片流到电商平台的商品图集,从旅游应用的景点相册到摄影作品展示——用户对图片浏览的体验要求不断提高:流畅的切换动画、直观的缩略图导航、便捷的收藏操作、自动播放模式。HarmonyOS NEXT ArkUI 虽…

2026/7/7 0:05:16 阅读更多 →
24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V DC-DC降压芯片PW2312B/PW2815,SOT23-6到SOP8-EP方案对比

24V稳压芯片完整选型指南 PW8600 PW75XX PW2815 PW2312B LDODC/DC全方案 一、24V稳压方案概述 24V直流电源在工业自动化、门禁系统、电梯控制、汽车电子、LED驱动、监控设备等场景中应用极广,是最常见的中压直流母线电压。要将24V母线稳定降压至下游MCU、传感器…

2026/7/7 0:05:16 阅读更多 →
RAG+知识图谱混合检索与Graph RAG核心对比

RAG+知识图谱混合检索与Graph RAG核心对比

做企业RAG落地的团队,往往容易卡在一容易踩坑的选型难题: 当需求单纯靠向量RAG搞不定、单纯靠知识图谱也搞不定,必须同时依赖「文本语义理解 实体关系推理」时,到底是做「向量图谱混合检索」就够了,还是必须上「Grap…

2026/7/7 0:07:19 阅读更多 →

周新闻

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容

B站视频下载神器BiliTools:5分钟学会轻松保存任何B站内容 【免费下载链接】BiliTools A cross-platform bilibili toolbox. 跨平台哔哩哔哩工具箱,支持下载视频、番剧等等各类资源 项目地址: https://gitcode.com/GitHub_Trending/bilit/BiliTools …

2026/7/6 8:11:50 阅读更多 →
威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型全解析:从新手入门到实战应用,助你构建安全产品!

威胁模型的陌生现状在忙碌疲惫的一天里,参与了关于混合后量子密码学的讨论,应付端点攻击找茬的人,还参与留言板讨论后,发现“威胁模型”对多数人仍是陌生概念,且多被当作时髦用语。有趣的相关画作有一幅由 Embyr 创作的…

2026/7/6 8:11:52 阅读更多 →
渗透测试入门指南:从零基础到实战环境搭建

渗透测试入门指南:从零基础到实战环境搭建

1. 从“看热闹”到“入门”:我理解的渗透测试到底是什么?每次看到新闻里说某个大公司的数据被“黑”了,或者某个网站被攻击导致服务瘫痪,你是不是和我一样,心里会冒出两个念头:一是“这黑客真厉害”&#x…

2026/7/6 6:52:56 阅读更多 →

月新闻