找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1313|回复: 13
收起左侧

DHT11这类需要大量延时操作的传感器读取问题

[复制链接]
ID:1057946 发表于 2023-7-10 21:04 | 显示全部楼层 |阅读模式
现在是100毫秒读取一次传感器的值,但是在读取期间,大量的延时操作会阻塞中断函数的Key_slow_down按键消抖计时操作
能设置中断优先级解决吗,或者是设置两个定时器、两个中断,在触发中断时会互相影响吗
void TIM3_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
                {
                        if(++Key_slow_down==10) Key_slow_down=0;
                        if(++DHT11_slow_down==100) DHT11_slow_down=0;
                        TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
                }
}
void DHT11_Start(void)
{
        Delay_s(1);//传感器上电后,要等待 1s 以越过不稳定状态在此期间无需发送任何指令
        DHT11_DataPin_Init(MCU_Output);//IO口输出模式
        GPIO_SetBits(GPIOA,GPIO_Pin_10);
        GPIO_ResetBits(GPIOA,GPIO_Pin_10);
        Delay_ms(20);//拉低总线必须大于18毫秒,保证DHT11能检测到起始信号
        GPIO_SetBits(GPIOA,GPIO_Pin_10);
        Delay_us(30);//延时等待20-40us后,读取DHT11的响应信号
        DHT11_DataPin_Init(MCU_Input);//IO口输入模式
        if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_10)==0)
        {
                DHT11_exist_Plag=1;
                while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_10)==0);
                while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_10)==1);
        }
}
/****
        *@brief DHT11温湿度测量
        *@parameter 无
        *@ReturnValue 无
        */
void DHT11_GetData(void)
{
        int8_t i,j,Temp=0x00;
        if(DHT11_exist_Plag==1)// 检测DHT11是否存在,若DHT11不存在,则不必进行下面步骤
        {
                for(j=0;j<5;j++)//一次完整的数据传输为40bit,高位先出
                {
                       
                        for(i=0;i<8;i++)
                        {
                                while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_10)==0);
                                Delay_us(30);
                                if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_10)==1)
                                {
                                        Temp=Temp|(0x80>>i);// 从高位开始接收
                                        while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_10)==1);
                                }
                        }
                        Hum_Tem_Data[j]=Temp;
                        Temp=0x00;
                }
                if(Hum_Tem_Data[0]+Hum_Tem_Data[1]+Hum_Tem_Data[2]+Hum_Tem_Data[3]!=Hum_Tem_Data[4])// 校验数据是否正确,若不正确则数组全部写1
                {
                        Hum_Tem_Data[0]=0xff;
                        Hum_Tem_Data[1]=0xff;
                        Hum_Tem_Data[2]=0xff;
                        Hum_Tem_Data[3]=0xff;
                       
                }
        }else
        {
                DHT11_Start();
        }
}

回复

使用道具 举报

ID:1085441 发表于 2023-7-10 23:56 | 显示全部楼层
是的,延时时间比较长,好像有400uS,受一些中断间隔时间短(小于400uS)的程序影响。我后来换了I2C接口的芯片避免了这个问题,型号好像是SHT30
回复

使用道具 举报

ID:420836 发表于 2023-7-11 06:52 | 显示全部楼层
请注意,读取传感器的时间间隔与读取寄存器的时间不同。 读取寄存器并不需要花费太多时间。
回复

使用道具 举报

ID:584195 发表于 2023-7-11 07:12 | 显示全部楼层
100ms 好象DH11都没有转换完成。别读太快了,太快了也没有意义。
回复

使用道具 举报

ID:213173 发表于 2023-7-11 07:21 | 显示全部楼层
对于DHT11这类外设,一个完整的工作周期比较长,长时间的阻滞延时操作会影响其它需要及时响应的程序的正常运行。这种情况并不是使用中断就能够完美避免。这就需要换一种编程思路,使用轮询法。假设你这个设备使用了DHT11温湿度测量,时钟芯片1302,按键扫描,8位数码管动态显示等。那么使用定时器将主函数循环周期以最小时间单位要求的外设来设置。例如8位数码管动态显示为参考取2~2.5ms,2*8=16ms,时间再长码管就要闪烁了。我们用switch-case-break分支语句编写(如有必要)上述各外设的子程序,每次主循环只执行各子函数的一部分代码,这就把各子函数中需要长延时的时间用于执行其它程序,提高运行效率,避免互相干扰。
回复

使用道具 举报

ID:1057946 发表于 2023-7-11 08:54 | 显示全部楼层
zyluglugl 发表于 2023-7-11 07:12
100ms 好象DH11都没有转换完成。别读太快了,太快了也没有意义。

确实,但是怎么解决读取传感器期间按键不能用的问题呢
回复

使用道具 举报

ID:1057946 发表于 2023-7-11 08:55 | 显示全部楼层
TTQ001 发表于 2023-7-11 06:52
请注意,读取传感器的时间间隔与读取寄存器的时间不同。 读取寄存器并不需要花费太多时间。

什么意思,能具体说一下吗,新手求指教
回复

使用道具 举报

ID:1057946 发表于 2023-7-11 09:04 | 显示全部楼层
wulin 发表于 2023-7-11 07:21
对于DHT11这类外设,一个完整的工作周期比较长,长时间的阻滞延时操作会影响其它需要及时响应的程序的正常 ...

但是这样会出现一个问题,假如该诗序要求在固定时间段内发送一个字节,那么轮询的方法就会打乱这个时序
回复

使用道具 举报

ID:161164 发表于 2023-7-11 09:10 | 显示全部楼层
1. 代码开头那1s delay是不必要的
2. 18ms的低电平是最少时间,即是说,你可以先拉低电平,然后去干其他事,超过18ms后再回来继续剩下的动作
3. 40bit x (50us + 70us(max)) = 4.8ms, 如果4.8ms的耗时也不能接受,可以改为用定时器捕获下降沿时间差
回复

使用道具 举报

ID:69038 发表于 2023-7-11 10:00 | 显示全部楼层
温湿传感器100ms读一次值毫无意义!1分钟读一次就够了。
回复

使用道具 举报

ID:123289 发表于 2023-7-11 11:10 | 显示全部楼层
1、合理规划时序。这与你对逻辑的的架构方案有关。
2、禁用DELAY函数,因为DELAY期间,其它程序被迫等待,误事。改用中断实现延时(希望你会这一着)。
3、如果调用的函数库中有用到DELAY,请改之,自己写函数。
4、不要在中断服务程序中进行复杂运算等耗时大的程序运行。因为中断有优先执行的权利,会占用其它程序的时间。这些程序移至MAIN中运行(也希望你会这一着)。
以上,需要你对单片机有较深的理解。没有一定的功底,是解决不了你提出的问题的。
例如:
不会用中断实现延时。只会用DELAY。
不会将中断服务程序中的非紧要程序分离出来。
死等硬件(温度传感器)的返回信息。未预计等不到怎么办。
对他人的函数缺点,无法改动。
……
回复

使用道具 举报

ID:155507 发表于 2023-7-11 11:41 | 显示全部楼层
读取DHT11这类需要大量延时操作的传感器时,可以结合定时器和中断来解决问题。以下是一种可能的解决方案:

1.配置一个定时器,让它以较高的频率触发中断,例如每隔1毫秒触发一次中断。

2.在中断服务函数中,进行按键消抖计时操作。

3.在主循环中使用轮询法读取DHT11传感器的值。每次主循环迭代中,只读取传感器值的一部分,并确保不会阻塞太长时间。

4.如果需要在固定时间段内发送一个字节,可以利用定时器的输出比较功能生成一个精确的时序。可以将要发送的字节数据预先存储在一个缓冲区中,并在定时器的比较中断中逐个发送字节。通过设置合适的定时器频率和比较值,可以满足时序要求。

下面是一个伪代码示例,演示了上述思路:


// 定时器中断服务函数
void TIM_IRQHandler() {
    if (TIM_GetITStatus(TIMx, TIM_IT_Update) != RESET) {
        // 按键消抖计时操作

        // 清除中断标志位
        TIM_ClearITPendingBit(TIMx, TIM_IT_Update);
    }
}

// 主循环
while (1) {
    // 读取DHT11传感器的值的一部分
    // 不要阻塞太长时间

    // 执行其他任务

    // 如果需要发送字节
    if (isSendByteRequired) {
        // 通过定时器的输出比较来生成时序
        // 逐个发送字节
    }
}
通过结合定时器中断和主循环的轮询,可以实现同时进行传感器读取、按键消抖和其他任务的处理。同时,通过合理设置定时器的频率和比较值,可以满足发送字节的精确时序要求。

请注意,以上示例代码为伪代码,实际的实现可能会因具体的STM32系列和使用的开发环境而有所不同。您需要根据实际情况进行相应的配置和编程。
回复

使用道具 举报

ID:213173 发表于 2023-7-13 16:41 | 显示全部楼层
ZZZZZ134679 发表于 2023-7-11 09:04
但是这样会出现一个问题,假如该诗序要求在固定时间段内发送一个字节,那么轮询的方法就会打乱这个时序

微妙级的阻滞延时一般不影响其它程序运行,毫秒级阻滞延时就要考虑用其它方法避免。给你一个示例参考。 无标题.jpg

DHT11温湿度上下限报警 仿真.rar (146.88 KB, 下载次数: 6)
回复

使用道具 举报

ID:1054554 发表于 2023-7-13 17:39 | 显示全部楼层
上述各外设的子程序,每次主循环只执行各子函数的一部分代码,这就把各子函数中需要长延时的时间用于执行其它程序,提高运行效率,避免互相干扰。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表