STM32读取DHT11数据,单总线是真的坑
花了老大的力气,终于搞定DHT11数据的读取了。
主要有三个点需要注意:
1.定时器时钟要准,如果微秒级计时确实不准,那就5us,10us这样延时着看,总之要逻辑分析仪看具体延时时间。
2.主机的GPIO引脚要先推挽输出,再上拉输入。(这是为了要给到从机快速稳定能识别的信号必须的,可能上拉电阻小点也可以直接开漏?)
3.我采样到了41个数据,第一位舍弃,剩下40位读数正确。(其实前40位也能校验通过,后40位也能校验通过,为啥啊)
` uint8_t DHT11_DRIVE(void){
// 1. 先配置成推挽!!!(发信号必须推挽)
DHT11_PP_OUT();
// 2. 发起始信号(必须推挽发)
// HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
// HAL_Delay(18); // 至少18ms
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
HAL_Delay(30);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
// 3. 立刻切换输入模式
DHT11_UP_IN();
// 下面开始读 DHT11 响应
uint16_t count=0;
//等待从机响应低电平,多等会儿
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)==GPIO_PIN_RESET){
if(count<1800)
{
Delay_10us();
count=count+10;
}
else return 0;
}
//等待从机响应高电平,多等会儿
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)==GPIO_PIN_SET){
if(count<1800)
{
Delay_10us();
count=count+10;
}
else return 0;
}
//从机高电平结束,进入第一个50us低电平,开始发数据
for(uint8_t i=0;i<41;i++){
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)GPIO_PIN_RESET){
if(count<100)
{
Delay_5us();
count=count+5;
}
else return 0;
}
count=0;
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_4)GPIO_PIN_SET){
if(count<100)
{
Delay_5us();
count=count+5;
}
else return 0;
}
if(count<=35&&i!=0)
{
DHT11[(i-1)/8]<<=1;
}
else if(i!=0)
{
DHT11[(i-1)/8]<<=1;
DHT11[(i-1)/8]|=1;
}
count=i;//为什么会有41位啊,而且必须将第一个采集到的位丢掉
//读取到的数据才是和现实中比较接近的,真的离谱。
}
printf("进入循环次数:%2d\r\n",count);
return 1;
}
/**
- @brief 将DHT11配置为推挽输出模式
*/
static void DHT11_PP_OUT(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
/**
- @brief 将DHT11配置为上拉输入模式
*/
static void DHT11_UP_IN(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = GPIO_PIN_4;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP; //上拉
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}`
也要感谢这位博主,我搞了好久都没成,看了之后才发现需要先推挽再输入。(我也尝试过先推挽再开漏,但是那个时候大脑已经混乱了,失败了)
https://www.cnblogs.com/zxr-blog/p/18088206
浙公网安备 33010602011771号