上次用的温湿度传感器是AHT10,我看课程里用的是DHT11,我画的PCB上也刚好有DHT11,两者有点区别,AHT11是IIC采集,而DHT11是单总线采集,也就是一个IO口就可以采集到温湿度,今天就来搞一下这个单总线.先看数据手册




再细看读取步骤



总结一下: 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,温度差别不大,但湿度差别很大,差的有点不敢相信哈哈
我要赚赏金
