当前位置:   article > 正文

【嵌入式】DHT11模块OLED显示温度和日历和利用串口_dh11

dh11


一、了解时钟RTC

RTC (Real Time Clock):实时时钟

RTC是个独立的定时器。RTC模块拥有一个连续计数的计数器,在相应的软件配置下,可以提供时钟日历的功能。修改计数器的值可以重新设置当前时间和日期 RTC还包含用于管理低功耗模式的自动唤醒单元。
RTC实质是一个掉电后还继续运行的定时器,从定时器的角度来看,相对于通用定时器TIM外设,它的功能十分简单,只有计时功能(也可以触发中断)。但其高级指出也就在于掉电之后还可以正常运行。

两个 32 位寄存器包含二进码十进数格式 (BCD) 的秒、分钟、小时( 12 或 24 小时制)、星期几、日期、月份和年份。此外,还可提供二进制格式的亚秒值。系统可以自动将月份的天数补偿为 28、29(闰年)、30 和 31 天。

上电复位后,所有RTC寄存器都会受到保护,以防止可能的非正常写访问。

无论器件状态如何(运行模式、低功耗模式或处于复位状态),只要电源电压保持在工作范围内,RTC使不会停止工作。

RCT特征:
● 可编程的预分频系数:分频系数高为220。
● 32位的可编程计数器,可用于较长时间段的测量。
● 2个分离的时钟:用于APB1接口的PCLK1和RTC时钟(RTC时钟的频率必须小于PCLK1时钟 频率的四分之一以上)。
● 可以选择以下三种RTC的时钟源:
● HSE时钟除以128;
● LSE振荡器时钟;
● LSI振荡器时钟

● 2个独立的复位类型:
● APB1接口由系统复位;
● RTC核心(预分频器、闹钟、计数器和分频器)只能由后备域复位

● 3个专门的可屏蔽中断:
● 1.闹钟中断,用来产生一个软件可编程的闹钟中断。

● 2.秒中断,用来产生一个可编程的周期性中断信号(长可达1秒)。

● 3.溢出中断,指示内部可编程计数器溢出并回转为0的状态。

RTC时钟源:
三种不同的时钟源可被用来驱动系统时钟(SYSCLK):

● HSI振荡器时钟
● HSE振荡器时钟
● PLL时钟

这些设备有以下2种二级时钟源:

● 40kHz低速内部RC,可以用于驱动独立看门狗和通过程序选择驱动RTC。 RTC用于从停机/待机模式下自动唤醒系统。
● 32.768kHz低速外部晶体也可用来通过程序选择驱动RTC(RTCCLK)。
在这里插入图片描述
RTC时钟的框图还是比较简单的,这里我们把他分成 两个部分:

APB1 接口:用来和 APB1 总线相连。 此单元还包含一组 16 位寄存器,可通过 APB1 总线对其进行读写操作。APB1 接口由 APB1 总 线时钟驱动,用来与 APB1 总线连接。

通过APB1接口可以访问RTC的相关寄存器(预分频值,计数器值,闹钟值)。
在这里插入图片描述
第一个模块是 RTC 的 预分频模块,它可编程产生 1 秒的 RTC 时间基准 TR_CLK。RTC 的预分频模块包含了一个 20 位的可编程分频器(RTC 预分频器)。如果在 RTC_CR 寄存器中设置了相应的允许位,则在每个 TR_CLK 周期中 RTC 产生一个中断(秒中断)。

在这里插入图片描述
第二个模块是一个 32 位的可编程计数器 (RTC_CNT),可被初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算,可以记 录 4294967296 秒,约合 136 年左右,作为一般应用,这已经是足够了的。
RTC具体流程:
RTCCLK经过RTC_DIV预分频,RTC_PRL设置预分频系数,然后得到TR_CLK时钟信号,我们一般设置其周期为1s,RTC_CNT计数器计数,假如1970设置为时间起点为0s,通过当前时间的秒数计算得到当前的时间。RTC_ALR是设置闹钟时间,RTC_CNT计数到RTC_ALR就会产生计数中断,

RTC_Second为秒中断,用于刷新时间,
RTC_Overflow是溢出中断。
RTC Alarm 控制开关机
RTC时钟选择
使用HSE分频时钟或者LSI的时候,在主电源VDD掉电的情况下,这两个时钟来源都会受到影响,因此没法保证RTC正常工作.所以RTC一般都时钟低速外部时钟LSE,频率为实时时钟模块中常用的32.768KHz,因为32768 = 2^15,分频容易实现,所以被广泛应用到RTC模块.(在主电源VDD有效的情况下(待机),RTC还可以配置闹钟事件使STM32退出待机模式).

RTC复位过程
除了RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器外,所有的系统寄存器都由系统复位或电源复位进行异步复位。
RTC_PRL、RTC_ALR、RTC_CNT和RTC_DIV寄存器仅能通过备份域复位信号复位。

系统复位后,禁止访问后备寄存器和RCT,防止对后卫区域(BKP)的意外写操作

RTC中断
秒中断:
这里时钟自带一个秒中断,每当计数加一的时候就会触发一次秒中断,。注意,这里所说的秒中断并非一定是一秒的时间,它是由RTC时钟源和分频值决定的“秒”的时间,当然也是可以做到1秒钟中断一次。我们通过往秒中断里写更新时间的函数来达到时间同步的效果

闹钟中断:
闹钟中断就是设置一个预设定的值,计数每自加多少次触发一次闹钟中断

二、配置工程

配置RCC
在这里插入图片描述
配置sys
在这里插入图片描述
配置RTC
在这里插入图片描述
设定初始时间
在这里插入图片描述
配置串口
在这里插入图片描述
配置时钟
在这里插入图片描述

代码部分

添加头文件

#include "main.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"
#include "stdio.h"
  • 1
  • 2
  • 3
  • 4
  • 5

添加定义

int fputc(int ch,FILE *f){
 uint8_t temp[1]={ch};
 HAL_UART_Transmit(&huart1,temp,1,2);
 return ch;
}
RTC_DateTypeDef GetData;  //获取日期结构体

RTC_TimeTypeDef GetTime;   //获取时间结构体
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

在while循环里添加

while (1)
  {
    /* USER CODE END WHILE */
/* Get the RTC current Time */
	    HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
      /* Get the RTC current Date */
      HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);

      /* Display date Format : yy/mm/dd */
      printf("%02d/%02d/%02d\r\n",2000 + GetData.Year, GetData.Month, GetData.Date);
      /* Display time Format : hh:mm:ss */
      printf("%02d:%02d:%02d\r\n",GetTime.Hours, GetTime.Minutes, GetTime.Seconds);

      printf("\r\n");

      HAL_Delay(1000);

    /* USER CODE BEGIN 3 */
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这里插入图片描述

2.显示温湿度和日历

1.简介:
DHT11作为一款低价、入门级的温湿度传感器,常用于我们的单片机设计实例中;它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。
DHT11为 4 针单排引脚封装,如下图,采用单线制串行接口,只需加适当的上拉电阻,信号传输距离可达20米以上,使其成为各类应用甚至最为苛刻的应用场合的最佳选则。

接口:建议连接线长度短于20米时用5K上拉电阻,大于20米时根据实际情况使用合适的上拉电阻。
在这里插入图片描述
2.DHT11实物图
在这里插入图片描述
在这里插入图片描述
3.单总线工作原理:DATA 输出线用于单片机与DHT11之间的通讯,一次通讯时间4ms左右;单片机发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取数据,采集数据后转换到低速模式;如果没有接收到主机发送的开始信号,DHT11不会主动进行温湿度采集。
一次完整的数据传输为40bit,高位先出;
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据+8bit校验;
DHT11数据分小数部分和整数部分,当前小数部分用于以后扩展,现读出为零; 测量分辨率分别为8bit(温度)、8bit(湿度)。
数据传送正确时校验位等于“8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据”之和;
在这里插入图片描述
数据信号:每一bit数据都以50us低电平开始,高电平的长短决定数据位是0还是1,如下图所示:
结束信号:当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。
在这里插入图片描述
在这里插入图片描述

代码部分

DHT11.c文件

#include "stm32f10x.h"                  // Device header
#include  "dht11.h"
#include  "Delay.h"
//数据
unsigned int rec_data[4];


//对于stm32来说,是输出
void DH11_GPIO_Init_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);

}

//对于stm32来说,是输入
void DH11_GPIO_Init_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);

}



//主机发送开始信号
void DHT11_Start(void)
{
	DH11_GPIO_Init_OUT(); //输出模式
	
	dht11_high; //先拉高
	Delay_us(30);
	
	dht11_low; //拉低电平至少18us
	Delay_ms(20);
	
	dht11_high; //拉高电平20~40us
	Delay_us(30);
	
	DH11_GPIO_Init_IN(); //输入模式
}


//获取一个字节
char DHT11_Rec_Byte(void)
{
	unsigned char i = 0;
	unsigned char data;
	
	for(i=0;i<8;i++) //1个数据就是1个字节byte,1个字节byte有8位bit
	{
		while( Read_Data == 0); //从1bit开始,低电平变高电平,等待低电平结束
		Delay_us(30); //延迟30us是为了区别数据0和数据1,0只有26~28us
		
		data <<= 1; //左移
		
		if( Read_Data == 1 ) //如果过了30us还是高电平的话就是数据1
		{
			data |= 1; //数据+1
		}
		
		while( Read_Data == 1 ); //高电平变低电平,等待高电平结束
	}
	
	return data;
}

//获取数据

void DHT11_REC_Data(void)
{
	unsigned int R_H,R_L,T_H,T_L;
	unsigned char RH,RL,TH,TL,CHECK;
	
	DHT11_Start(); //主机发送信号
	dht11_high; //拉高电平
	
	if( Read_Data == 0 ) //判断DHT11是否响应
	{
		while( Read_Data == 0); //低电平变高电平,等待低电平结束
		while( Read_Data == 1); //高电平变低电平,等待高电平结束
		
		R_H = DHT11_Rec_Byte();
		R_L = DHT11_Rec_Byte();
		T_H = DHT11_Rec_Byte();
		T_L = DHT11_Rec_Byte();
		CHECK = DHT11_Rec_Byte(); //接收5个数据
		
		dht11_low; //当最后一bit数据传送完毕后,DHT11拉低总线 50us
		Delay_us(55); //这里延时55us
		dht11_high; //随后总线由上拉电阻拉高进入空闲状态。
		
		if(R_H + R_L + T_H + T_L == CHECK) //和检验位对比,判断校验接收到的数据是否正确
		{
			RH = R_H;
			RL = R_L;
			TH = T_H;
			TL = T_L;
		}
	}
	rec_data[0] = RH;
	rec_data[1] = RL;
	rec_data[2] = TH;
	rec_data[3] = TL;
}
#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"                  // Device header



#define dht11_high GPIO_SetBits(GPIOB, GPIO_Pin_12)
#define dht11_low GPIO_ResetBits(GPIOB, GPIO_Pin_12)
#define Read_Data GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)

void DHT11_GPIO_Init_OUT(void);
void DHT11_GPIO_Init_IN(void);
void DHT11_Start(void);
unsigned char DHT11_REC_Byte(void);
void DHT11_REC_Data(void);
#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136

DHT11.h文件

#ifndef __DHT11_H
#define __DHT11_H
#include "stm32f10x.h"                  // Device header



#define dht11_high GPIO_SetBits(GPIOB, GPIO_Pin_12)
#define dht11_low GPIO_ResetBits(GPIOB, GPIO_Pin_12)
#define Read_Data GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12)

void DHT11_GPIO_Init_OUT(void);
void DHT11_GPIO_Init_IN(void);
void DHT11_Start(void);
unsigned char DHT11_REC_Byte(void);
void DHT11_REC_Data(void);

#endif


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

主函数

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include  "dht11.h"
#include  "usart.h"
#include "rtc.h"
//PB12
extern unsigned int rec_data[4];
extern u8 rmon,rday,rhour,rmin,rsec,rweek; //2位月日时分秒周
extern u16 ryear; //4位年
int main()
{
	Delay_ms(100);

  OLED_Init();
	uart_init(9600);
	OLED_Clear();
  RCC_Configuration();
	RTC_Config();
  OLED_ShowChinese(3, 1,0);						//温
	OLED_ShowChinese(3, 2, 1); 	          //度
	OLED_ShowString(3,5,":");						//:
  OLED_ShowString(3,9,".");	
	OLED_ShowChinese1(4, 1,0);						//湿	
	OLED_ShowChinese1(4, 2, 1); 	          //度
  OLED_ShowString(4,5,":");	
	OLED_ShowString(4,9,".");	
	RTC_Set(2023,11,15,15,20,00);
	while(1)
	{
		Delay_ms(1000);
		if(RTC_Get()==0)
		{
			OLED_ShowNum(1,1,ryear/1000,1);
			OLED_ShowNum(1,2,ryear%1000/100,1);
			OLED_ShowNum(1,3,ryear%100/10,1);
			OLED_ShowNum(1,4,ryear%10,1);
			OLED_ShowString(1,5,"-");
			
			OLED_ShowNum(1,6,rmon%100/10,1);
			OLED_ShowNum(1,7,rmon%10,1);
			OLED_ShowString(1,8,"-");
			
			OLED_ShowNum(1,9,rday%100/10,1);
			OLED_ShowNum(1,10,rday%10,1);
			
			OLED_ShowNum(2,1,rhour%100/10,1);
			OLED_ShowNum(2,2,rday%10,1);
			OLED_ShowString(2,3,":");
			OLED_ShowNum(2,4,rmin%100/10,1);
			OLED_ShowNum(2,5,rmin%10,1);
			OLED_ShowString(2,6,":");
			
			OLED_ShowNum(2,7,rsec%100/10,1);
			OLED_ShowNum(2,8,rsec%10,1);
		}
	
		DHT11_REC_Data(); //接收温度和湿度的数据
		
	  OLED_ShowNum(3,7,rec_data[2],2);
		OLED_ShowNum(3,10,rec_data[3],1);
		OLED_ShowNum(4,7,rec_data[0],2);
		OLED_ShowNum(4,10,rec_data[1],2);

	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

如果需要代码可以自己提取
链接:https://pan.baidu.com/s/156nDVwW1cGqyLpRFZ0rfYg?pwd=1234
提取码:1234


结果

9

总结

我使用的是DHT11温湿度传感器模块,在实验中需要找到或者下载一个DHT11.c文件,再初始化定义和始能。OLED对应的引脚是PB8,9。DHT11对应的引脚是PB12.由于一开始是利用杜邦线连接OLED和DHT模块发现使用不稳定,索性直接插在了面包板上,还有对于OLED显示的时候在初始化之前写一个延时函数,一开始OLED上电不稳定会导致显示不出来,写一个延时函数确保OLED上电,就可以解决OLED闪烁的问题。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号