实验介绍 :本实验是基于STM32的一个OLED显示实验,包括了RTC时钟显示,DHT11的温湿度显示,动态图显示。(基于标准库)
注:基于HAL库的OLED显示——DHT11可以参考这篇大佬的文章基于stm32的太空人温湿度时钟项目——DHT11(HAL库)
实验效果图:
引脚配置:
DHT11:
VCC -->3.3V
DATA-->PB12
GND-->GND
OLED:
VCC -->3.3V
GND-->GND
SCL-->PA8
SDA-->PA9
一、DHT11介绍
1.1DHT11概述
DHT11
是广州奥松有限公司生产的一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个 NTC
测温元件,并与一个高性能
8
位单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集本地湿度和温度。DHT11
与单片机之间能采用简单的
单总线
进行通信,仅仅需要一个 I/O 口。传感器内部湿度和温度数据
40Bit 的数据
一次性传给单片机,数据采用 校验和方式进行校验,有效的保证数据传输的准确性。DHT11
功耗很低,
5V
电源电压下,工作平均最大电流 0.5mA
。
性能指标和特性如下:
①
工作电压范围:
3.5V-yuan
②
工作电流
:平均
0.5mA
③
湿度测量范围:20-90%RH
④
温度测量范围:0-50℃
⑤
湿度分辨率
:
1
%RH
8
位
⑥
温度分辨率
:
1
℃
8
位
⑦
采样周期
:
1S
⑧
单总线结构(DATA引脚)
⑨
与 TTL 兼容(5V)
1.2DHT11数据结构
DHT11数字湿温度传感器采用单总线数据格式。即,单个数据引脚端口完成输
入输出双向传输。其数据包由
5Byte
(
40Bit
)组成。数据分小数部分和整数部分
,
具
体格式在下面说明。
一次完整的数据传输为40bit
,高位先出。
数据格式:8bit
湿度整数数据
+8bit
湿度小数数据
+8bit温度整数数据+8bit温度小数数据
+8bit校验和
校验和数据为前四个字节相加。
传感器数据输出的是未编码的二进制数据。数据(
湿度、温度、整数、小数
)
之间
应该分开处理。如果,某次从传感器中读取如下
5Byte
数据:
由以上数据就可得到湿度和温度的值,计算方法:
humi (湿度)= byte4 . byte3=45.0 (%RH
)
temp (温度)= byte2 . byte1=28.0 (
℃
)
jiaoyan(校验)= byte4+ byte3+ byte2+ byte1=73(=humi+temp)(
校验正确
)
注意:
DHT11
一次通讯时间最大
3ms
,主机连续采样间隔建议不小于
100ms
。
二、RTC时钟
RTC(Real Time Clock)实时时钟是个独立的定时器。RTC模块拥有一个连续计数的计数器,在相应的软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期。
2.1、RTC 组成部分
APB1接口:用来和APB1总线相连。通过APB1接口可以访问RTC的相关寄存器 (预分频值,计数器值,闹钟值)
RTC核心:由一组可编程计数器组成。分两个主要模块。
①第一个是RTC预分频模块,它可以编程产生最长1秒的RTC时间基TR CLK。如果设置了秒中断允许位,可以产生秒中断。
②第二个是32位的可编程计数器可被初始化为当前时间系统时间按TR CLK周期累加并与存储在RTC ALR寄存器中的可编程时间相比当匹配时候如果设置了闹钟中断允许位,可以产生闹钟中断
2.2、工作原理图
RTC 内核完全独立于
RTC APB1
接口,而软件是通过
APB1
接口访问
RTC
的预分频值、计
数器值和闹钟值的。但是相关可读寄存器只在
RTC APB1
时钟进行重新同步的
RTC
时钟的上升
沿被更新,
RTC
标志也是如此。这就意味着,如果
APB1
接口刚刚被开启之后,在第一次的内
部寄存器更新之前,从
APB1
上读取的
RTC
寄存器值可能被破坏了(通常读到
0
)。因此,若
在读取
RTC
寄存器曾经被禁止的
RTC APB1
接口,软件首先必须等待
RTC_CRL
寄存器的
RSF
位(寄存器同步标志位,
bit3
)被硬件置
1
。
2.3、RTC 代码
RTC实时时钟的代码作者是移植了正点原子的RTC代码,可自行参考正点原子的相关代码,或者给作者留言,会相继把代码发送给诸位爱学习的小伙伴 。
三、DHT11代码(标准库)
3.1、DHT11代码
首先,先介绍一下 DHT11
的传输时序。
数据发送流程:首先主机发送开始信号,即:拉低数据线,保持 t1
(至少
18ms
)时间,然后拉高数据线
t2(20~40us
)时间,然后读取
DHT11
的响应,正常的话,
DHT11
会拉低数据线,保持
t3
(
40~50us
) 时间,作为响应信号,然后 DHT11
拉高数据线,保持
t4
(
40~50us
)时间后,开始输出数据。
3.1.1 配置DATA引脚
基于 DHT11单总线通讯的特性,设置PB12引脚即为输出模式又为输入模式。
void DHT11_IO_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12); //高电平
}
void DHT11_IO_IN(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_12); //高电平
}
3.1.2 DHT11复位函数
拉低数据线,保持t1 (至少18ms) 时间然后拉高数据线t2 (20~40us)时间。
复位函数:
//复位
void DHT11_Rst(void)
{
DHT11_IO_OUT();
DHT11_DQ_OUT=0;
delay_ms(20);
DHT11_DQ_OUT=1;
delay_us(30);
}
3.1.3 DHT11检查函数
检查DHT11是否工作正常。正常返回 0,检测异常返回1。
代码 :
//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_Check(void)
{
u8 retry=0;
DHT11_IO_IN();//SET INPUT
while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
else retry=0;
while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
return 0;
}
3.1.4 读取一位数据
从DHT11读取一个位,返回值:1/0。
作者选择了一个延时 大于26-28us的延时(因为“1”延时远大于“0”所需 延时),即40us 。当 检测到高电平时,一位数据为“1”,否则 ,为“0”。
读取“0”时序图
读取“1”时序图
读取DHT11一位数据代码:
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void)
{
u8 retry=0;
while(DHT11_DQ_IN&&retry<100)//等待变为低电平
{
retry++;
delay_us(1);
}
retry=0;
while(!DHT11_DQ_IN&&retry<100)//等待变高电平
{
retry++;
delay_us(1);
}
delay_us(40);
if(DHT11_DQ_IN) return 1;
else return 0;
}
3.1.5 读取DHT11一个字节
循环读取DHT11 8位数据。
//从DHT11读取一个字节
//返回值:读到的数据
u8 DHT11_Read_Byte(void)
{
u8 i,dat=0;
for(i=0;i<8;i++)
{
dat <<= 1;
if(DHT11_Read_Bit())
{
dat |= 1;
}
}
return dat;
}
3.1.6 读取DHT11温度和湿度数据
根据DHT11定义,温度和湿度包括了整数部分和小数部分,本文作者只选择了整数部分进行显示。
注:DHT11 的数据格式为:8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数
数据+8bit 温度小数数据+8bit 校验和。
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp,u8 *humi)
{
u8 i;
u8 data[5]={0};
DHT11_Rst();
if(DHT11_Check()==0)
{
for(i=0;i<5;i++)
{
data[i]=DHT11_Read_Byte();//读取5byte
}
if((data[0]+data[1]+data[2]+data[3]) == data[4])
{
*temp=data[2];//温度
*humi=data[0];//湿度
}
else return 1;
}
return 0;
}
3.1.7 DHT11.h代码
#ifndef __DHT11_H
#define __DHT11_H
#include "sys.h"
//数据IO操作
#define DHT11_DQ_OUT PBout(12) //写命令
#define DHT11_DQ_IN PBin(12) //写数据
//DHT11函数
u8 DHT11_Init(void);
void DHT11_Rst(void);
u8 DHT11_Check(void);
u8 DHT11_Read_Byte(void);
u8 DHT11_Read_Data(u8 *temp,u8 *humi);
void DHT11_IO_OUT(void);
void DHT11_IO_IN(void);
#endif
3.2 main.c代码
#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "dht11.h"
#include "rtc.h"
int main(void)
{
u8 t=0;
u8 wendu,shidu;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
OLED_Init(); //OLED端口初始化
RTC_Init();
DHT11_Init();
//温度
OLED_ShowCN_STR(0 , 4 , 0 , 2);
OLED_ShowString(32,4,":",16);
//OLED_ShowNum(40,4,wendu,2,16);
OLED_ShowCN_STR(60 , 4 , 4 , 1);
//湿度
OLED_ShowCN_STR(0 , 6 , 2 , 2);
OLED_ShowString(32,6,":",16);
//OLED_ShowNum(40,6,shidu,2,16);
OLED_ShowString(60,6,"%RH",16);
while(1)
{
RTC_Display();
OLED_DrawGIF(85, 2,125, 7, 6, 240, GIF);
for(t=0;t<2;t++) //100ms读取一次
{
DHT11_Read_Data(&wendu,&shidu);
//温度
OLED_ShowNum(40,4,wendu,2,16);
//湿度
OLED_ShowNum(40,6,shidu,2,16);
t++;
delay_ms(150);
}
t=0;
}
}
四、实验效果
基于OLED的DHT11显示 实验
基于OLED的DHT11显示 实验-CSDN直播
文章链接
发表评论