我仍然处于 C++ 的初学者水平。我需要使用中断和计时器对按钮 (PCINT10) 进行去抖动。我正在使用 atmega328p 微控制器。当前使用 timer0 将时间递增 1ms。
到目前为止,这是我的代码的一部分:
ISR(TIMER0_COMPA_vect) {
now++; //increment by 1ms
}
//interrupt setup
PCICR = 0b00000010;
PCIFR = 0b00000010;
PCMSK1 = 0b00000100;// interrupt on PCINT10
//global variables
uint8_t A2 = 0b00000100;
uint32_t A2_time = 0;
uint32_t buttons;
uint32_t oldb = 0;
uint32_t newb;
//ISR
ISR(PCINT1_vect) {
newb = PINC;
int changed = oldb ^ newb; // changed is 1 for buttons that have changed
if (changed & A2) {
if ((now - A2_time) > 10) { // 10 ms debounce
// new S1_A1 press
A2_time = now;
if ((oldb & ~newb) & A2) {
buttons |= A2;
}
}
}
}
//calling button to change states
if (((PINC & A2) == 0)) { //if A2 pressed
current_state = Pause;
}
ISR 对按钮没有影响。仍在检测多个按钮按下。
您不应该将开关放在中断触发的引脚上,因为它会在每次弹跳时触发(以及其他形式的 EMI 噪声)。
相反,您需要从定时器 ISR 内部进行去抖动。对于大多数开关,它最多应每 5 毫秒左右触发一次。 (您可以通过将电压插入开关并使用示波器进行测量来精确测量反弹。)
所以放弃 PINC 中断并将代码从那里移动到定时器 ISR。将当前读数与之前的读数进行比较并等待两者相同是最简单的去抖动形式,在大多数情况下通常就足够了。
另请注意,ISR 和主程序之间共享的所有变量都应声明
volatile
否则您可能会遇到优化编译器生成错误代码的问题。