Embedded AVR中断去抖动问题

Embedded AVR中断去抖动问题,embedded,avr,blink,debouncing,atmega32,Embedded,Avr,Blink,Debouncing,Atmega32,我不知道当按下开关时如何消除小振荡的影响。我有一个基本开关和一个led,我试图创建一个中断,使led在按下开关时闪烁。我这样做是为了在输入信号的下降沿触发中断 #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> ISR(INT0_vect){ PORTD ^= 1; } int main(void) { DDRD = 1;//we set for i

我不知道当按下开关时如何消除小振荡的影响。我有一个基本开关和一个led,我试图创建一个中断,使led在按下开关时闪烁。我这样做是为了在输入信号的下降沿触发中断


#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

ISR(INT0_vect){
    PORTD ^= 1;
}

int main(void)
{
    DDRD = 1;//we set for input D port
    PORTD |= 1<<2;//pull-up for interrupt pin
    EICRA &= ~3;//clear EICRA and activate INT0 on LOW
    EICRA |= 2;//activate INT0 on falling edge
    SREG |= 1<<7;//I bit from SREG has to be enabled
    EIMSK |= 1;//enable INT0
    while (1) 
    {
        EIFR |= 1;//I've tried to clear the corresponding flag, but in vain
    }
}


#包括
#包括
#包括
情报、监视和侦察(国际矢量){
PORTD^=1;
}
内部主(空)
{
DDRD=1;//我们设置了输入D端口

PORTD |=1要正确地去抖动,您必须以某种方式测量时间,您可以做两件事:

  • 确保某个东西是稳定的(这实际上不是去抖动)。例如,如果您的按钮有很长的电线,您可能会担心噪音会污染信号。因此,您先读取一次信号,然后稍后再读取第二次,以检查信号是否仍然存在且没有噪音。最好是在一段时间内监视信号,并且仅在信号没有变化的情况下在一段时间内,将其视为有效

  • 正确的去抖动。当信号从非活动状态变为活动状态时,必须忽略信号的短路(活动-非活动-活动)

  • 当你按下按钮时,它会给你一个低电平,你可以忽略噪音。因此,一旦信号变低,你就知道按钮被按下了。这是中断的完美场景。但是,如果按钮反弹,它会很快地降低和升高信号-对人来说太快,但对MCU来说不会太快。你知道什么我们需要做的是忽略进一步的“压力”一段时间,例如1毫秒,5秒,或1/100秒左右。然后,你必须计算时间(大概是另一个中断)

    假设您有一个每毫秒触发一次的中断例程。在该例程中,减小计数器(如果大于0)。当按下按钮时,且计数器为零时,,接受按下按钮并将计数器设置为一个值。按钮的进一步压力将被忽略,直到计数器“缓慢”运行由于另一个测量时间的例程(在中断中),衰变为零

    这只是一个想法,有很多方法可以做到相同甚至更好(噪声消除)

    在您的情况下,您也可以在已有的中断例程(不美观)中只执行sleep()(或执行延迟循环),或在给定时间内禁用该中断(因此您必须测量时间)。

    更正的代码是:

    #define F_CPU 16000000UL
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    
    ISR(INT0_vect){
        PORTD ^= 1;
        _delay_ms(10);
        EIFR |= 1;
    }
    
    int main(void)
    {
        DDRD = 1;//we set for input D port
        PORTD |= 1<<2;//pull-up for interrupt pin
        EICRA &= ~3;//clear EICRA and activate INT0 on LOW
        EICRA |= 1;//activate INT0 on change
        SREG |= 1<<7;//I bit from SREG has to be enabled
        EIMSK |= 1;//enable INT0
        while (1) 
        {
            
        }
    }
    
    #定义F#U CPU 1600000UL
    #包括
    #包括
    #包括
    情报、监视和侦察(国际矢量){
    PORTD^=1;
    _延迟时间(10);
    EIFR |=1;
    }
    内部主(空)
    {
    DDRD=1;//我们设置了输入D端口
    
    PORTD |=1首先感谢您的解释。不过,我尝试了一个技巧并清除了相应的中断标志。我不知道为什么它不起作用。此外,我尝试在ISR中设置延迟,同样没有改进。我真的不知道如何处理此问题。此外,如何在interru中触发另一个中断pt?有没有办法做到这一点?此外,只要边缘触发的外部中断属于类型1,延迟就无法工作,也就是说,当处理中断时,用于启用全局中断的位被清除,因此无法捕获其他中断,但是,当在这种情况下遇到中断时,来自内部中断的标志设置了rupt标志寄存器,以便在处理当前中断后立即发出中断请求。@pauk注意中断标志和中断启用之间的差异。您不应清除标志(请求),您应该禁用IRQ0中断。确实,全局中断已清除,但一旦再次启用,将使用挂起标志…因此必须以正确的顺序管理两个标志。因此,我尝试清除特定于中断的标志,以便忽略在上一个中断被关闭时遇到的中断请求由CU处理。不要在中断例程中使用延迟。我开始感到困惑…不清楚您想要实现什么。您显示的代码实际上应该实现您想要的:去盎司(10毫秒)按下按钮。如果您愿意,可以看看清除标志是否有效,因为在等待10毫秒时,标志可能会因为反弹而再次升起,但由于中断被禁用,因此不会重新进入IRQ0处理程序。然后,您可以清除标志(avr很奇怪,因为必须写入1才能清除!)。它是有效的。相反,通过触摸EIMSK,您可以阻止设置标志-几乎是相同的。好吧,这是一个区别:当调用IRQ0处理程序时,该标志会自动清除;此时,可以在您有时间禁用IRQ0之前再次设置该标志。讨厌…但可能很少发生。不要在中断中设置延迟t!如果在中断中设置延迟,则会阻止正常执行以及任何低优先级或同等优先级的中断(或禁用嵌套时的所有中断)。因此,使用中断变得毫无意义,您最好在正常线程中轮询和取消触发开关。问题是,取消触发延迟将对整个系统的计时产生不利影响,从而破坏了最初使用中断的目的。这只是一种不好的做法。我不这么认为,因为:首先,whet如果我进行轮询,那么MCU必须执行一项任务,即轮询交换机,同时不能执行其他任务。此外,如果我选择轮询技术,为什么我要关注去抖动,只要轮询是定期进行的,并且建立了延迟,这样就不会遇到振荡。另外,什么是softwar在这种情况下应该使用e方法,因为去抖动是一个经常出现的问题,我认为不需要额外的硬件来避免这种情况。有无数的文章介绍如何在固件或硬件中使用施密特触发器来实现这一点。你拥有谷歌搜索吗。这是一个简单的例子