STM32F103C8T6通过DHT11获取温湿度数据之初学笔记

STM32F103C8T6通过DHT11获取温湿度数据

dht11简易获取温湿度数据

DHT11数据格式

采集范围:温度0-50°±2°,湿度:20-90%RH。
精度:湿度±5%RH, 温度±2℃

采用单总线双向串行通信协议,每次采集都要由单片机发起开始信号,然后DHT11会向单片机发送响应并开始传输40位数据帧。
如接收到的 40 位数据为:
0011 0101 0000 0000 0001 1000 0000 0100 0101 0001
湿度高 8 位 湿度低 8 位 温度高 8 位 温度低 8 位 校验位

校验位为“8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据” 8bit 校验位等于所得结果的末 8 位

校验计算
0011 0101+0000 0000+0001 1000+0000 0100= 0101 0001 则接收数据正确

湿度: 0011 0101(整数)=35H=53%RH 0000 0000(小数)=00H=0.0%RH =>53%RH + 0.0%RH =
53.0%RH
温度: 0001 1000(整数)=18H=24℃ 0000 0100(小数)=04H=0.4℃ =>24℃ + 0.4℃ = 24.4℃

DHT11时序:

STM32F103C8T6通过DHT11获取温湿度数据之初学笔记_第1张图片

时序流程详解:

1.主机把总线拉低大于18ms,保证DHT11能检测。
2.主机拉高等待延时20us-40us。
3.DHT11若有响应,会返回给主机低电平接近80us,即响应信号。
4.DHT11返回给主机高电平80us,准备发送数据给主机。
5.发送的数据每1bit之间间隙为50us,当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。

数据格式
发送的数据如何判断为0还是1呢,由发送时高电平的持续时长决定。
STM32F103C8T6通过DHT11获取温湿度数据之初学笔记_第2张图片
检测高电平为70us,即为1.
STM32F103C8T6通过DHT11获取温湿度数据之初学笔记_第3张图片
检测高电平为26us-28us,即为0

硬件连接

STM32F103C8T6通过DHT11获取温湿度数据之初学笔记_第4张图片
本实验以PA1连接DHT11的DQ引脚

部分代码

按照之前的时序详解来说明:

时序流程一,二步:

void DHT11_Rst(void)   
{                 
   DHT11_IO_OUT(); //设置GPIOA1为输出
    DHT11_DQ_Low; //DQ=0
    delay_ms(20);    //拉低至少18ms
    DHT11_DQ_High; //DQ=1 
 delay_us(30);     //主机拉高20~40us
}
时序流程三,四步:
u8 DHT11_Check(void)    
{   
u8 retry=0;//定义临时变量
DHT11_IO_IN();//SET INPUT 
    while ((GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==1)&&retry<100)//DHT11会拉低40~80us
	{
		retry++;
		printf("%s %d\n",__FUNCTION__,__LINE__);//方便在串口中观察错误是否DHT11未响应
		delay_us(1);
	}; 
if(retry>=100)return 1; //并无响应
else retry=0;//有响应
		
	while ((GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==0)&&retry<100)//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		delay_us(1);
	};
if(retry>=100)return 1;   //拉高过久还未发送数据给主机 
return 0;
}
时序流程第五部,读取一位:
u8 DHT11_Check(void)    
{   
u8 retry=0;//定义临时变量
DHT11_IO_IN();//SET INPUT 
    while ((GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==1)&&retry<100)//DHT11会拉低40~80us
				{
			retry++;
					printf("%s %d\n",__FUNCTION__,__LINE__);//方便在串口中观察错误是否DHT11未响应
			delay_us(1);
			}; 
if(retry>=100)return 1; //并无响应
else retry=0;//有响应
		
			while ((GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==0)&&retry<100)//DHT11拉低后会再次拉高40~80us
				{
				retry++;
				delay_us(1);
				};
if(retry>=100)return 1;   //拉高过久还未发送数据给主机 
return 0;
}
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void)  
{
 u8 retry=0;
	while((GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==1)&&retry<100)//等待变为低电平,数据间隙
		{
			retry++;
			delay_us(1);
		}
retry=0;
	while((GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==0)&&retry<100)//等待变高电平,数据
		{
			retry++;
			delay_us(1);
		}
delay_us(40);//等待40us
if(GPIO_ReadInputDataBit(GPIO_DHT11,IO_DHT11)==1) return 1;  //若还为高电平,数据为1
else return 0;   //数据为0
}
读取一字节函数:
u8 DHT11_Read_Byte(void)    
{        
    u8 i,dat;
    dat=0;
for (i=0;i<8;i++) 
{
   dat<<=1; 
    dat|=DHT11_Read_Bit(); //8位
    }    
    return dat;  //返回8位
}
读取一次数据函数,校验并存储数据道buf中:
u8 DHT11_Read_Data(u8 *temp,u8 *humi)    
{        
 u8 buf[5];
u8 i;
DHT11_Rst(); //时序流程一,二步。
if(DHT11_Check()==0) //有响应
{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])  //校验成功
		{
		*humi=buf[0];  //湿度高16位
		*temp=buf[2]; // 温度的16位
		}
}
else return 1; //失败
return 0;    //成功
}
各类初始化:
void DHT11_Init(void)
{     
DHT11_Rst();  //复位DHT11
DHT11_Check();//等待DHT11的回应
}

还有初始化PA1位模拟输入和推挽输出的函数,就不列出了
DHT11_IO_IN();//设置输入
DHT11_IO_OUT();//设置输出

main
int main
{	 
	 u8 wd=0;      
     u8 sd=0;
	 DHT11_Init();
	 USART1_config(115200);
	   while(1)
	   {
	   DHT11_Read_Data(&wd,&sd);//读取温湿度值    
	   printf("temp = %d  humi =%d\n",wd,sd);		
	   delay_ms(1000);
	   delay_ms(1000);
	   }
  }

结果

STM32F103C8T6通过DHT11获取温湿度数据之初学笔记_第5张图片

你可能感兴趣的:(stm32,单片机,嵌入式)