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℃
时序流程详解:
1.主机把总线拉低大于18ms,保证DHT11能检测。
2.主机拉高等待延时20us-40us。
3.DHT11若有响应,会返回给主机低电平接近80us,即响应信号。
4.DHT11返回给主机高电平80us,准备发送数据给主机。
5.发送的数据每1bit之间间隙为50us,当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。
数据格式
发送的数据如何判断为0还是1呢,由发送时高电平的持续时长决定。
检测高电平为70us,即为1.
检测高电平为26us-28us,即为0
按照之前的时序详解来说明:
时序流程一,二步:
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);
}
}