AVR 中断去抖动问题
AVR interrupt debouncing issues
我不知道如何消除按下开关时的小振荡的影响。我有一个原始开关和一个 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
}
}
要正确去抖动,您必须以某种方式测量时间,您可以做两件事:
确保某个东西是稳定的(这实际上不是去抖动)。例如,如果你的按钮有很长的电线,你可能会担心噪音会污染输入的信号。所以你读取信号一次,然后稍后再读取一次,以检查信号是否仍然存在并且它不是噪音。完美的是监测信号一段时间,只有当信号在那段时间内没有变化时,才认为它有效。
适当的去抖动。当信号从非活动状态变为活动状态时,您必须忽略信号的短路下降(活动-非活动-活动)。
你的按钮在按下时给你一个低电平,你可以忽略噪音。因此,一旦信号变低,您就知道按钮已被按下。这是中断的完美场景。但是,如果按钮弹起,它会非常快速地降低和升高信号 - 对人类来说太快了,但对 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)
{
}
}
我提到它在尝试触发电路的上升沿或下降沿时仍然存在问题。当尝试这样做时,我注意到电路的行为就像它被任何类型的边缘触发一样。
我不知道如何消除按下开关时的小振荡的影响。我有一个原始开关和一个 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
}
}
要正确去抖动,您必须以某种方式测量时间,您可以做两件事:
确保某个东西是稳定的(这实际上不是去抖动)。例如,如果你的按钮有很长的电线,你可能会担心噪音会污染输入的信号。所以你读取信号一次,然后稍后再读取一次,以检查信号是否仍然存在并且它不是噪音。完美的是监测信号一段时间,只有当信号在那段时间内没有变化时,才认为它有效。
适当的去抖动。当信号从非活动状态变为活动状态时,您必须忽略信号的短路下降(活动-非活动-活动)。
你的按钮在按下时给你一个低电平,你可以忽略噪音。因此,一旦信号变低,您就知道按钮已被按下。这是中断的完美场景。但是,如果按钮弹起,它会非常快速地降低和升高信号 - 对人类来说太快了,但对 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)
{
}
}
我提到它在尝试触发电路的上升沿或下降沿时仍然存在问题。当尝试这样做时,我注意到电路的行为就像它被任何类型的边缘触发一样。