中断触发时数组偶现重复添加元素问题排查求助
问题原因分析与解决方案
核心问题原因
1. 机械按键抖动导致重复触发
普通机械按键按下时,触点会产生10-50ms的弹跳过程,这会让button.rise()中断多次触发——单次物理按压被识别为多次按键事件,进而重复记录同一个LED颜色值。
2. 共享变量的竞态条件
全局变量n和l同时被主循环和中断回调访问,且无同步保护:
- 当中断触发时,主循环可能正在修改
l,导致记录的l处于不确定状态; n的递增操作并非原子性,极端情况下多次中断触发会导致n递增异常,重复写入同一数组位置。
3. 缺乏边界检查
中断回调未判断n是否已达到sequence_length,序列已满后仍继续写入会导致数组越界,引发未知问题。
修复方案
1. 添加软件消抖
通过时间过滤忽略短时间内的重复触发,同时仅在序列未满时执行记录逻辑:
#include "mbed.h" #include <vector> // Green LED DigitalOut led1(LED1); // Blue LED DigitalOut led2(LED2); // Red LED DigitalOut led3(LED3); // Button Interrupt InterruptIn button(USER_BUTTON); // 消抖定时器 Timer debounce_timer; // Initialise counter for button presses (n), and selector for the lit LED (l) int n = 0; int l = 1; // Define sequence length int sequence_length=5; // Create vector/list for recorded LED's to go into int sequence[5]; // Callback function to associate with the press button event void onButtonPress() { // 过滤20ms内的重复触发 if (debounce_timer.read_ms() < 20) { return; } debounce_timer.reset(); // 仅在序列未满时记录 if (n < sequence_length) { // 禁用中断,保护共享变量读写 __disable_irq(); sequence[n] = l; n++; __enable_irq(); // 按键反馈 led1 = true; led2 = true; led3 = true; wait_ms(50); select_led(l); // 恢复当前LED循环状态 } } // 'Decoding' what LED's should be lit up for different 'l' values void select_led(int l) { if (l==0) { led1 = false; led2 = false; led3 = false; } else if (l==1) { led1 = true; led2 = false; led3 = false; } else if (l==2) { led1 = false; led2 = true; led3 = false; } else if (l==3) { led1 = false; led2 = false; led3 = true; } } int main() { debounce_timer.start(); // attach the address of the callback function to the rising edge button.rise(onButtonPress); while (true) { int current_n; // 安全读取n的值 __disable_irq(); current_n = n; __enable_irq(); while (current_n >= sequence_length) { select_led(0); wait(1); for (int i = 0; i < current_n; i++) { select_led(sequence[i]); wait(0.5); select_led(0); wait(0.5); } // 更新当前n值,避免无限循环 __disable_irq(); current_n = n; __enable_irq(); } select_led(l); wait(1); // 安全修改l的值 __disable_irq(); l = l + 1; if (l==4) { l = 1; } __enable_irq(); } }
2. 关键优化点说明
- 消抖定时器:过滤按键弹跳产生的重复中断;
- 临界区保护:用
__disable_irq()和__enable_irq()包裹共享变量的读写,避免竞态条件; - 边界检查:仅在序列未满时执行记录,防止数组越界;
- 按键反馈:短暂点亮所有LED提示按键有效,提升交互体验。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

