时序图,通信过程就是:
MCU发送起始信号,MCU等待响应,MCU等待DHT11测量完毕,MCU读取测量结果,结束一次通信。
主机发送起始信号:主机发送至少18ms的低电平;
从机等待主机释放总线:主机把总线拉高,延时20~40us;
主机读取响应;
主机读取数据:每一bit数据以5us的低电平开始,数据是0还是1由高电平时长决定;
当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。
温湿度转换:
单片机代码如下:
.c文件
void DHT11_Init()
{
delay_ms(1000); //等待1S以越过不稳定状态在此期间不能发送任何指令
DHT11_Output(); //主机发开始信号
}
void DHT11_Output()
{
GPIO_InitTypeDef dht11;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
dht11.GPIO_Mode=GPIO_Mode_Out_PP; //推挽输出
dht11.GPIO_Pin=GPIO_Pin_6 ;//PB6
dht11.GPIO_Speed=GPIO_Speed_50MHz; //高速
GPIO_Init(GPIOB,&dht11);
}
//主机发起始信号
void DHT11_Start()
{
GPIO_ResetBits(GPIOB,GPIO_Pin_6); //低电平
delay_ms(18); //微处理器的 I/O 设置为输出同时输出低电平,低电平保持时间不能小于18ms(最大不得超过 30ms)
GPIO_SetBits(GPIOB,GPIO_Pin_6); //拉高等待
delay_us(20); //从机等待主机释放总线:主机把总线拉高,延时20~40us
}
//DHT11发出信号,主机接收信号,切换输入模式
void DHT11_Input()
{
GPIO_InitTypeDef dht11;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
dht11.GPIO_Mode=GPIO_Mode_IN_FLOATING; //上拉输入 输入上拉:引脚为输入模式,引脚输入状态默认为高电平
dht11.GPIO_Pin=GPIO_Pin_6 ;
dht11.GPIO_Speed=GPIO_Speed_50MHz; //高速
GPIO_Init(GPIOB,&dht11); //根据key配置的参数初始化外设GPIOA寄存器
}
u8 DHT11_Readbyte()
{
int i;
u8 data=0; //读到保存的一个字节
for(i=0;i<8;i++) //8位
{
while(!(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6))); //等待54us低电平时间过去
delay_us(40); //再延时,判断是否为高电平
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)==1) //延时过后,确定为高电平,把1存起来
{
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)); //等待高电平结束
data |=1<<(7-i);
}
}
return data; //返回读到的字节数据
}
int DHT11_GetTH(u8 buf[])
{
u8 check=0;
int n=0;
DHT11_Output();
DHT11_Start();
DHT11_Input();
//单片机(主机)等待从机响应,单片机读PB6引脚为低电平
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)) //等待从机响应低电平
{
delay_us(1);
n++;
if(n>100)
return 1; //不响应
}
while(!(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6))); //等响应后的低电平时间完全过去
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_6)); //等待80us的高电平过去
//单片机读取40位数据--8位1个字节
buf[0]=DHT11_Readbyte(); //湿度的高位字节
buf[1]=DHT11_Readbyte(); //湿度的低位字节
buf[2]=DHT11_Readbyte(); //温度的高位字节
buf[3]=DHT11_Readbyte(); //温度的低位字节
check=DHT11_Readbyte();
//释放总线
DHT11_Output(); //变成输出模式
GPIO_SetBits(GPIOB,GPIO_Pin_6); //拉高--高电平
if((buf[0]+buf[1]+buf[2]+buf[3])==check)
{
return 0; //采集数据成功
}
else
{
return 2; //校验不成功
}
}
main函数
int main(void) //主函数
{
u8 data[4];
int temp=0;
float T=0,H=0;
systick_init(); //系统滴答时钟初始化
USART1_Init(9600); //串口通信初始化
DHT11_Init();
while (1)
{
temp=DHT11_GetTH(data);
if(temp==0)
{
printf("采集校验成功!%d\r\n",temp);
H=data[0]+(data[1]/100.0);
T=data[2]+(data[3]/100.0);
printf("温度:%.2f,湿度:%.2f\r\n",T,H);
}
delay_ms(2000)
|