再细看读取步骤
总结一下: 1.上电先等待1S:此时DATA高电平 2.发送起始信号:先由DATA由高拉低, 持续18ms-30ms,然后拉高 3.DHT11应答:DHT11先拉低83us作为应答,再输出87us通知单片机接收数据 4.接收数据:数据为40为数据, 位数据“0”的格式为:54微秒的低电平和23-27微秒的高电平 位数据“1”的格式为:54微秒的低电平加68-74微秒的高电平。
需要: 单总线要求IO口既要输出也要输入,这是我们可以外加上拉电阻,把DATR引脚设置为开漏输出,此时高电平不输出(由外部上下拉决定),低电平为低电平,同时也能读取IO变化.这就跟51单片机的IO口类似了. ms级延迟函数我们已经有了,就差个us级延迟函数
先写个us级延迟函数,这里我们使用定时器实现先点出来一个定时器
我们不需要中断,使用查询方式即可,生成
因为主频为64MMHz,分频64,定时器的频率为1MHz=1000KHz=1000000Hz,即计数一次周期为1s/1000000=1us
我们直接写个延迟函数
void Delay_us(uint16_t us) { uint16_t differ = 0xffff-us-10;//初值,多减10以防没检测到 __HAL_TIM_SET_COUNTER(&htim17,differ); //设定TIM7计数器起始值 HAL_TIM_Base_Start(&htim17); //启动定时器 while(differ < 0xffff-10)//等于是加了一个us的值,加一次1us { differ = __HAL_TIM_GET_COUNTER(&htim17); //查询计数器的计数值 } HAL_TIM_Base_Stop(&htim17); }
验证一下
HAL_GPIO_TogglePin(LDO_GPIO_Port,LDO_Pin); Delay_us(100);
while(1)中添加代码,100us变换一次IO,用逻辑分析仪抓一下
开起来可能是查了一点,但是其中包括了GPIO操作的时间,改一下数值再测下
HAL_GPIO_TogglePin(LDO_GPIO_Port,LDO_Pin); Delay_us(50);
看起来蛮准的
写驱动点出来DATA引脚设置,开漏输出
void DATA_SET(GPIO_PinState val) { HAL_GPIO_WritePin(DHT_GPIO_Port,DHT_Pin,val); } uint8_t DATA_GET(void) { return HAL_GPIO_ReadPin(DHT_GPIO_Port,DHT_Pin); }
1.发送起始信号:先由DATA由高拉低, 持续18ms-30ms,然后拉高
void DHT11_Start(void)//发送起始信号 { DATA_SET(GPIO_PIN_RESET); //拉低 HAL_Delay(20); //至少18ms DATA_SET(GPIO_PIN_SET); //拉高 Delay_us(30); //至少20~40us }
2.DHT11应答:DHT11先拉低83us作为应答,再输出87us通知单片机接收数据
uint8_t DHT11_Check(void)//检测从机响应信号 { uint8_t retry=0; while (DATA_GET()&&retry<100)//拉低40~80us { retry++; Delay_us(1); }; if(retry>=100) return 1; else retry=0; while (!DATA_GET()&&retry<100)//拉高40~80us { retry++; Delay_us(1); }; if(retry>=100) return 1; return 0; //检测到DHT11返回0 }
3.初始化
uint8_t DHT11_Init(void)//DHT11初始化,成功返回0 { HAL_Delay(1000); DHT11_Start(); return DHT11_Check(); }
4.读取一位
uint8_t DHT11_Read_Bit(void)//读取一位 { uint8_t retry=0; while(DATA_GET()&&retry<100)//等待变为低电平 { retry++; Delay_us(1); } retry=0; while(!DATA_GET()&&retry<100)//等待变为高电平 { retry++; Delay_us(1); } Delay_us(40); //等待40us if(DATA_GET()) return 1; else return 0; }
5.读取一个字节
uint8_t DHT11_Read_Byte(void)//读取一个字节 { uint8_t i,dat; dat=0; for (i=0;i<8;i++){ dat<<=1; dat|=DHT11_Read_Bit(); } return dat; }
6.读取5个字节
uint8_t DHT11_Read_Data(uint16_t *temp,uint16_t *humi)//DHT11读取,成功返回0 { uint8_t buf[5]; uint8_t i; DHT11_Start(); if(DHT11_Check()==0){ for(i=0;i<5;i++){ buf[i]=DHT11_Read_Byte(); } if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]){ *humi=(buf[0]<<8) + buf[1]; *temp=(buf[2]<<8) + buf[3]; } }else return 1; return 0; }测试
while(DHT11_Init()) { printf("DHT11 Checked failed!!!\r\n"); } uint16_t temperature; uint16_t humidity;
while (1) { DHT11_Read_Data(&temperature,&humidity); printf("DHT11 Temperature = %d.%d degree\r\n",temperature>>8,temperature&0xff); printf("DHT11 Humidity = %d.%d%%\r\n",humidity>>8,humidity&0xff); HAL_Delay(500); }
效果如下
对比AHT10和DHT11,温度差别不大,但湿度差别很大,差的有点不敢相信哈哈