【STM32】Proteus仿真STM32教程(标准库)9——DHT11温湿度采集仿真(OLED12864显示)
大家好欢迎来到我们的STM32Proteus仿真教程系列。在前面的教程中我们学习了按键、LED以及数码管的操作。今天我们要来玩点“高级”且非常实用的东西——环境温湿度监测本期教程我们将使用DHT11温湿度传感器采集数据并将结果实时显示在OLED12864显示屏上。跟着我的步骤包教包会让我们开始吧目录一、前期准备二、 核心元器件简介三、 Proteus电路图搭建3.1 查找并添加元件3.2 硬件连线分配四、 代码编写思路与核心代码4.1 DHT11驱动代码 (dht11.c)4.2 主逻辑代码 (main.c)五、 免费获取资料一、前期准备在开始之前请确保你已经准备好提前安装目标 IDE如 Keil MDK V5方便后续验证生成的工程本文以「Keil MDK V5」为例进行演示。安装教程关注本文最下面的芦苇电子微信公众号私信回复0008提前安装仿真软件如 proteus9.0方便后续验证生成的工程本文以「proteus9.0」为例进行演示。安装教程关注本文最下面的芦苇电子公众号私信回复0005二、 核心元器件简介在画电路图之前我们先简单认识一下今天的主角DHT11温湿度传感器这是一款含有已校准数字信号输出的温湿度复合传感器。它只有一根数据线单总线协议单片机通过这一根线既能发送命令也能接收温湿度数据。OLED12864显示屏IIC接口一种非常清晰的屏幕分辨率为128x64。我们选用4针的IIC接口版本VCC、GND、SCL、SDA接线少代码控制也相对简单。三、 Proteus电路图搭建打开Proteus新建一个工程我们开始“进货”并连线。3.1 查找并添加元件在左侧元件库中搜索并添加以下元件STM32F103C8主控MCU。DHT11温湿度传感器。OLED12864或搜SSD1306找到一个4针的IIC接口OLED屏。3.2 硬件连线分配DHT11接线VDD 接电源GND 接地。DATA数据引脚 接单片机的PA0。OLED屏接线VCC 接电源GND 接地。SCL时钟线 接单片机的PA8。SDA数据线 接单片机的PA9。四、 代码编写思路与核心代码打开Keil MDK5新建基于标准库的STM32工程。由于OLED的底层驱动代码比较长包含字库等这里我们主要展示主程序逻辑和DHT11的核心驱动代码。(注OLED驱动可以直接使用网上的开源SSD1306 IIC标准库代码添加到工程即可)。4.1 DHT11驱动代码 (dht11.c)DHT11属于单总线通信意味着引脚PA0一会儿要当输出发信号一会儿要当输入读数据。所以我们需要两个辅助函数来切换GPIO模式。/** ****************************************************************************** * file DHT11函数 * author 芦苇电子 * version V1.0 * date 2026-xx-xx * brief ****************************************************************************** * attention * * 有问题请私信 微信公众号芦苇电子 * ****************************************************************************** */#includeDHT11.hvoidDHT11_IO_OUT(void){//温湿度模块输出函数GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_PinDHT11_IO;//选择端口号0~15或allGPIO_InitStructure.GPIO_ModeGPIO_Mode_Out_PP;//推挽输出GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz;//设置IO接口速度2/10/50MHzGPIO_Init(DHT11_PORT,GPIO_InitStructure);}voidDHT11_IO_IN(void){//温湿度模块输入函数GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_PinDHT11_IO;//选择端口号0~15或allGPIO_InitStructure.GPIO_ModeGPIO_Mode_IPU;//上拉输入GPIO_Init(DHT11_PORT,GPIO_InitStructure);}voidDHT11_RST(void){//DHT11端口复位发出起始信号IO发送DHT11_IO_OUT();//端口为输出GPIO_ResetBits(DHT11_PORT,DHT11_IO);//使总线为低电平Delay_ms(20);//拉低至少18msGPIO_SetBits(DHT11_PORT,DHT11_IO);//使总线为高电平Delay_us(30);//主机拉高20~40us}u8DHT11_Check(void){//等待DHT11回应返回1:未检测到DHT11返回0:成功IO接收u8 retry0;//定义临时变量DHT11_IO_IN();//IO到输入状态//GPIO端口输入时配置为上拉输入或者浮空输入因为外接上拉电阻所以默认为高电平//如果DHT11的数据线输入为高电平且 retry 小于100则将 retry 加1并延时1微秒重复这个过程直到 retry 大于等于100 或者DHT11的数据线输入变成低电平。如果 retry 大于等于100表示检测失败返回1否则将 retry 重置为0。while((GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO)1)retry80)//DHT11会拉低40~80us{retry;Delay_us(1);}if(retry80)return1;elseretry0;//如果DHT11的数据线输入为低电平且 retry 小于100则将 retry 加1并延时1微秒重复这个过程直到 retry 大于等于100 或者DHT11的数据线输入变成高电平。如果 retry 大于等于100表示检测失败返回1否则返回0表示检测成功。while((GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO)0)retry80)//DHT11拉低后会再次拉高40~80us{retry;Delay_us(1);}if(retry80)return1;return0;}u8DHT11_Init(void){//DHT11初始化RCC_APB2PeriphClockCmd(DHT11_RCC,ENABLE);//开始DHT11的时钟GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);GPIO_InitStructure.GPIO_PinDHT11_IO;//PA0GPIO_InitStructure.GPIO_ModeGPIO_Mode_Out_PP;//推挽输出GPIO_InitStructure.GPIO_SpeedGPIO_Speed_50MHz;GPIO_Init(DHT11_PORT,GPIO_InitStructure);GPIO_SetBits(DHT11_PORT,DHT11_IO);DHT11_RST();//DHT11端口复位发出起始信号returnDHT11_Check();//等待DHT11回应}//从DHT11读取一个位//返回值1/0u8DHT11_Read_Bit(void){u8 retry0;while((GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO)1)retry100)//等待变为低电平{retry;Delay_us(1);}retry0;while((GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO)0)retry100)//等待变高电平{retry;Delay_us(1);}Delay_us(40);//等待40usif(GPIO_ReadInputDataBit(DHT11_PORT,DHT11_IO)1)//用于判断高低电平即数据1或0return1;elsereturn0;}//从DHT11读取一个字节//返回值读到的数据u8DHT11_Read_Byte(void){u8 i,dat;dat0;for(i0;i8;i){dat1;//左移运算符,dat左移1位dat|DHT11_Read_Bit();//|表示按位或等于}returndat;}//从DHT11读取一次数据//temp:温度值(范围:0~50°)//humi:湿度值(范围:20%~90%)//返回值0,正常;1,读取失败u8DHT11_Read_Data(u8*temp,u8*humi){u8 buf[5];u8 i;DHT11_RST();//DHT11端口复位发出起始信号if(DHT11_Check()0)//等待DHT11回应0为成功回应{for(i0;i5;i)//读取40位数据{buf[i]DHT11_Read_Byte();//读出数据}if((buf[0]buf[1]buf[2]buf[3])buf[4])//数据校验{*humibuf[0];//将湿度值放入指针humi*tempbuf[2];//将温度值放入指针temp}}elsereturn1;return0;}4.2 主逻辑代码 (main.c)在main.c中我们将DHT11读出的数据送到OLED上显示。*******************************************************************************file 主函数*author 芦苇电子*version V1.0*date2026-xx-xx*brief oled*******************************************************************************attention**有问题请私信 微信公众号芦苇电子********************************************************************************/#includestm32f10x.h// Device header#includeDelay.h#includeOLED.h#includeDHT11.huint8_ttemp,temp_old;// 存放温度uint8_thumi,humi_old;// 存放湿度intmain(void){uint8_ti0;OLED_Init();// 初始化OLED// 初始化延时函数OLED_ShowString(1,5,temphumi);// 顶部标题while(DHT11_Init()){OLED_ShowString(1,1,DHT11 Error);// 如果读取失败可以在这里做个提示处理Delay_ms(100);}while(1){DHT11_Read_Data(temp,humi);// // 调用我们写的函数读取温湿度for(i0;i5;i)//DHT11不需要频繁读取利用刷新屏幕进行延时{OLED_ShowString(3,5,temp:);OLED_ShowNum(3,11,temp,3);OLED_ShowString(3,14,C);OLED_ShowString(4,5,humi:);OLED_ShowNum(4,11,humi,3);OLED_ShowString(4,14,%);Delay_ms(50);}}}五、 免费获取资料关注下面的 芦苇电子 微信公众号,在公众号内 私信回复052收到后自动发送该仿真资料今天的教程就到这里啦我们通过单总线协议读传感器再通过IIC协议驱动屏幕相当于一次性掌握了两种常见外设的用法进步非常大如果大家在仿真过程中遇到了任何玄学问题或者需要OLED的完整库代码欢迎在评论区留言交流如果觉得这篇文章对你有帮助欢迎点赞、收藏、转发——你的认可是我持续输出嵌入式硬核干货的最大动力我们下期再见