嵌入式设计与开发项目-DHT11温湿度传感器程序设计


知识普及
DHT11是单线接口数字温湿度传感器,温度测量 范围是0 ~ 50℃,湿度测量 范围是20% ~ 90%RH,温度测量精度是 ±2℃,湿度测量精度是 ±5%RH
DHT11包含一个 电阻式感湿元件和一个 NTC(负温度系数)测温元件,通过双向单线输出温度、湿度数据,一次数据输出40位(高位在前,大约需要4ms),数据格式为: 8位湿度整数 + 8位湿度小数(0) + 8位温度整数 + 8位温度小数(0) + 8位校验和(其中检验和是前4个8位数据之和的后8位)。
在这里插入图片描述

时序学习流程:
①单线空闲时为高电平,MCU读取数据时首先发送开始信号(输出低电平,持续时间必须大于18ms),然后切换到输入模式(单线由上拉电阻拉为高电平)等待DHT11;
②DHT11检测到开始信号后触发一次数据采集,并等待单线变为高电平后输出响应信号(低电平,持续时间80us)

一、实现的功能

  • ①完成DHT11温湿度传感器数据的实时采集显示;
  • ②8个LED的流水灯控制,每隔1s点亮一个灯,按以上步骤重复进行;
  • ③编写DHT11温湿度的底层驱动;

二、根据功能实现代码

1、主文件main.c

#include"key.h"
#include"led.h"
#include"lcd.h"
#include"stdio.h"
#include"dht11.h"

unsigned int uiDht_Val;
unsigned char ucSec,ucSec1;
unsigned char pucStr[21];
unsigned long ulTick_ms;

void DHT_Proc(void);

int main(void)
{
	SysTick_Config(72000);	//定时1ms(HCLK = 72MHz)
	KEY_Init();
	LED_Init();
	
	STM3210B_LCD_Init();
	LCD_Clear(Blue);
	LCD_SetBackColor(Blue);
	LCD_SetTextColor(White);
	while(1)
	{
		LED_Disp(ucSec);
		DHT_Proc();
	}
}
	void DHT_Proc(void)
	{
		if(ucSec != ucSec1)
		{
			ucSec1 = ucSec;
			
			uiDht_Val = dht11_read();
			sprintf((char *)pucStr," Humidity: %2d%%",uiDht_Val >> 24);
			LCD_DisplayStringLine(Line3,pucStr);
			sprintf((char *)pucStr," Temperature: %dC",(uiDht_Val >> 8)&0xff);
			LCD_DisplayStringLine(Line5,pucStr);
		}
	}
	
//SysTick 中断处理程序
	void SysTick_Handler(void)
	{
		ulTick_ms++;
		if(ulTick_ms % 1000 ==0)
		ucSec++;
	}
	
	

主函数分析:❤️ ❤️ ❤️

  1. dht11_read()返回的是36位数据,已经把DHT11的低八位校验和阉割掉,所以湿度的整数位是采集到的数据右移24位;
  2. 温室的整数数据是采集到的数据uiDht_Val右移8位取低八位数据;

2、DHT11温湿度的头文件“dht11.h”

#ifndef __DHT11_H
#define __DHT11_H

void dht11_init (void );
void delay(unsigned int n);

unsigned int dht11_read(void);
void DisplayDht11(void);

#endif

简要分析:❤️ ❤️

  1. DHT11对于的引脚进行初始化
  2. 设定延时函数根据时序进行接收函数;
  3. 获取温湿度数据,返回一个无符号整型的数据

3、DHT11温湿度的源文件“dht11.c”

#include "stm32f10x.h"

#define delay_us(X)  delayd(X*72/5)

void delayd(unsigned int n)
{
  while (n--);
}

void dht11_init (void )
{
  GPIO_InitTypeDef GPIO_InitStructure;
  /* Enable  clock */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA  , ENABLE);
  
  /* Configure Ports */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_SetBits(GPIOA, GPIO_Pin_7);

}

void mode_input(void )
{
  GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}
void mode_output(void )
{
  GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
}

unsigned int dht11_read(void)
{
  int i;
  long long val;
  int timeout;

  GPIO_ResetBits(GPIOA, GPIO_Pin_7);
  delay_us(18000);  //pulldown  for 18ms
  GPIO_SetBits(GPIOA, GPIO_Pin_7);
  delay_us( 20 );	//pullup for 30us

  mode_input();

  //等待DHT11拉低,80us
  timeout = 5000;
  while( (! GPIO_ReadInputDataBit  (GPIOA, GPIO_Pin_7)) && (timeout > 0) ) timeout--;	 //wait LOW

  //等待DHT11拉高,80us
  timeout = 5000;
  while( GPIO_ReadInputDataBit (GPIOA, GPIO_Pin_7) && (timeout > 0) ) timeout-- ;	 //wait HIGH	

#define CHECK_TIME 28

  for(i=0;i<40;i++)
  {
	timeout = 5000;
	while( (! GPIO_ReadInputDataBit  (GPIOA, GPIO_Pin_7)) && (timeout > 0) ) timeout--;	 //wait HIGH

	delay_us(CHECK_TIME);
	if ( GPIO_ReadInputDataBit (GPIOA, GPIO_Pin_7) )
	{
	  val=(val<<1)+1;
	} else {
	  val<<=1;
	}

	timeout = 5000;
	while( GPIO_ReadInputDataBit (GPIOA, GPIO_Pin_7) && (timeout > 0) ) timeout-- ;	 //wait LOW
  }

  mode_output();
  GPIO_SetBits(GPIOA, GPIO_Pin_7);

  if (((val>>32)+(val>>24)+(val>>16)+(val>>8) -val ) & 0xff  ) return 0;
    else return val>>8; 

}


简要分析:❤️ ❤️

  1. DHT11温湿度传感器连接到芯片的PA7引脚,dht11_init()初始化即时初始化PA7引脚为推挽输出模式,并设置PA7为高电平
  2. 同时配置PA7引脚推挽输出模式上拉输入模式,根据时序图进行相对应的发送和接收;
  3. **#define delay_us(X) delayd(X*72/5)**可能通过调试计算出来相对准确的延时函数;
  4. MCU首先发送开始数据(输出低电平,持续时间必须大于18ms,保证DHT11能检测到开始信号),然后切换到输入模式(单线由上拉电阻拉为高电平),等待DHT11响应;
  5. DHT11检测到开始信号后,触发一次数据采集,并等待单线变为高电平后输出响应信号低电平,持续时间80us),然后输出高电平持续时间80us)准备输出40位数据
  6. 每位数据都以低电平(持续时间为50us)开始,输出0时高电平持续时间为26~28us,输出1时高电平持续时间为70us。
  7. 最后一位数据输出后输出低电平持续时间50us),单线由上拉电阻拉为高电平进入空闲状态
  8. MCU检测到响应信号从单线读取40位数据,并判断校验是否正确,如果正确则有效,否则丢弃数据。

三、实现功能过程的注意与学习点

1、注意点

  1. dht11_read()返回的是32位数据,已经把8位校验和数据除掉了;
  2. 分别获取温湿度时,注意向右移的位数

2、学习的知识点

  1. 根据DHT11传输数据的时序,编写获取DHT11温湿度的驱动;
  2. 掌握通过移位获取相对应的温湿度数据;
  3. 学会使用while循环等待特定的响应信号;
  4. 判断传感器数据输出0或者1时,可以通过判断输出0最大持续时间28us;

❤️ ❤️ ❤️ ❤️ ❤️ ❤️

基于温度湿度一体的传感器DHT11 以下是在51单片机上测试成功的代码 #include<at89x52.h> #include<intrins.h>//加上这句下面的 _nop_();就能用 bit xianshiqiehuan; // sbit dht11_dat=P1^6; //开发板用 sbit dht11_dat=P2^0; //使用版用 unsigned char c,count, dht11temp,dht11dat; unsigned char dht11value[5]; unsigned int x,y,z; unsigned char code dat[]={ 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,}; delay() { unsigned char a; for(a=200;a>0;a--); } display(unsigned char x) //使用版用 { P0=dat[(x0)/10];//十位 P2_3=0; delay(); P2_3=1; P0=dat[(x0)];//个位 P2_2=0; delay(); P2_2=1; } /*display(unsigned char x) //开发板用 { P0=dat[(x0)/10];//十位 P1_2=0; delay(); P1_2=1; P0=dat[(x0)];//个位 P1_3=0; delay(); P1_3=1; } */ delay_1s() { unsigned int i=50000; while(i--); } delay_10us() //10us { _nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); } void delayms(unsigned char x) //1ms单位延时程序 { unsigned char j; while(x--) { for(j=0;j<123;j++){;} } } read_dht11() { unsigned char i; dht11_dat=1; _nop_(); //起始 dht11_dat=0;//拉低总线 delayms(18);//手册要求大于18ms dht11_dat=1;//拉高总线等待dht11回应 while(dht11_dat); // 等待dht11回应 若有回应 dht11_dat=0;往下执行 while(!dht11_dat);//回应后dht11将总线拉低80us,过后又将总线拉高,进入下一步 while(dht11_dat); //拉高80us 又变低,往下执行 进入50us延时 for(i=0;i<24;i++) { while(!dht11_dat);//50us过后...... dht11_dat=1;往下执行 delay_10us();delay_10us();delay_10us();//延时30us,查看总线是高是低, dht11temp=0; //先默认为0处理 if(dht11_dat) dht11temp=1; //1处理 dht11dat=dht11dat<<1; //必须先移动再或 若先或再移本次数据就移动了 dht11dat=dht11dat|dht11temp; dht11value[i/8]=dht11dat; while(dht11_dat);//如果处理的是1,30us过后总线还是1,那就在此等待总线变为0进入下一个50us低电平,不然会重复进行0处理 } } main() { delay_1s(); //要求上电等1秒,让dht11稳定 EA=1;//开放中断 TMOD=0x01;//设T0 为16位计数方式 ET0=1;//定时0中断允许 TR0=1;//开启TR0 while(1) { if(!xianshiqiehuan) //显示温度 display(dht11value[2]) ; else {display(dht11value[0]) ; //显示湿度 P0=0x92&0x7f; //千位显 S.代表湿度 P2_5=0; delay(); P2_5=1; } } } dingshi() interrupt 1 //定时器0服务程序 { TH0=0; TL0=0; count++; if(count==55){count=0;read_dht11();xianshiqiehuan=~xianshiqiehuan; } //在切换显示时采集,以防中断采样带来的显示闪烁 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序小鹿

博主不差钱,点个赞就行哈哈

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值