该文章以DHT11模块进行分析
目录
1.模块复位(时序图)
2.DHT11的应答信号
3.读取1bit数值(比较高电平的时间是否大于40us)
4.读取一个字节
5.把读取的字节放入单片机
6. 寄存器设置IO口方向
1.模块复位(时序图)
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //设置IO为输出
DHT11_DQ_OUT=0; //IO口置为低电平
delay_ms(20); //至少18ms
DHT11_DQ_OUT=1; //IO口置为高电平
delay_us(30);
}
2.DHT11的应答信号
u8 DHT11_Check(void)
{
u8 retry=0;
DHT11_IO_IN();//SET INPUT
while (DHT11_DQ_IN&&retry<100)
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
else retry=0;
while (!DHT11_DQ_IN&&retry<100)
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
return 0;
}
这个地方时一个难点,巧妙读取io口电平的持续时间是否为80us,首先设置IO状态为输入,读取io电平,当io口为低电平时,DHT11_DQ_IN&&retry<100为true,执行retry++,延时1us;当跳变到高电平则DHT11_DQ_IN&&retry<100为false,若retry>100就提前结束。
3.读取1bit数值(比较高电平的时间是否大于40us)
u8 DHT11_Read_Bit(void)
{
u8 retry=0;
while(DHT11_DQ_IN&&retry<100)
{
retry++;
delay_us(1);
}
retry=0;
while(!DHT11_DQ_IN&&retry<100)
{
retry++;
delay_us(1);
}
delay_us(40);
if(DHT11_DQ_IN)return 1;
else return 0;
}
如果经过40us后,电平认为高则是1,反之为0。
4.读取一个字节
u8 DHT11_Read_Byte(void)
{
u8 i,dat;
dat=0;
for (i=0;i<8;i++)
{
dat<<=1;
dat|=DHT11_Read_Bit();//按位异或,与0异或=本身
}
return dat;
}
5.把读取的字节放入单片机
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++)
{
buf[i]=DHT11_Read_Byte();
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4]) //校验
{
*humi=buf[0];
*temp=buf[2];
}
}else return 1;
return 0;
}
6. 寄存器设置IO口方向
#define DHT11_IO_IN() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=8<<12;}
#define DHT11_IO_OUT() {GPIOG->CRH&=0XFFFF0FFF;GPIOG->CRH|=3<<12;}
#define DHT11_DQ_OUT PGout(11)
#define DHT11_DQ_IN PGin(11)
|= 常用于位操作,目的是把值放入指定位置
&=0的目的是把该位置的位全部清0
操作高八位CR寄存器