You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

中断触发时数组偶现重复添加元素问题排查求助

问题原因分析与解决方案

核心问题原因

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 08:10:23