首页 > 解决方案 > 在STM32 Nucleo上多次触发上升沿中断

问题描述

我正在使用 STM32 NUCLEO-F401RE 微控制器板。

我有一个扬声器,它被编程为在向上/向下推动操纵杆时按设定的量改变频率。我的问题是,有时(通常情况下)当向上/向下推动操纵杆时,频率会增加/减少多次,这意味着 ISR 正在执行多次。此外,InterruptIn 对象设置为在上升沿触发,但有时它也会在下降沿执行(当向上/向下推动操纵杆返回空档时)。对克服这个有什么帮助吗?

void upISR()
{
    if (greenLED.getStatus())
    {
        myTicker.detach();
        frequency+=200;   
        myTicker.attach(callback(&spkr, &Speaker::toggle), 0.5/frequency); 
    }
}

'

int main()
{
    InterruptIn up(A2);
    InterruptIn down(A3);
    InterruptIn fire(D4);

    up.rise(&upISR);
    down.rise(&downISR);
    fire.rise(&toggleISR);

    redLED.on();

    while (1){}
}

标签: c++embeddedstm32microcontrollermbed

解决方案


机械开关弹跳或多或少是所有机械开关的一个特征。通常需要在软件中实现“去抖动”,尤其是在这种情况下开关直接驱动中断的情况下。

快速谷歌搜索软件谴责技术会产生一些相当糟糕的技术 IMO。不幸的是,我看到它做得不好的次数多于做得好。

我建议您在开关 ISR 中启动(或在“反弹”的情况下重新启动)一个硬件计时器,持续时间为 20 毫秒左右(比开关反弹时间长,但比您可能真正做到的时间短)松开开关)。然后在定时器 ISR 中,您测试开关的状态并相应地更改频率:

伪代码:

void upISR()
{
    debounceTimerRestart() ;
}

void downISR()
{
    debounceTimerRestart() ;
}

void debounceTimerISR()
{
    debounceTimerStop() ;

    tDirection dir = getJoystickDir() ;
    swithc( dir )
    {
        case UP :
        {
            increaseFrquency() ;
        }
        break ;

        case DN :
        {
            decreaseFrquency() ;
        }
        break ;
    }
}

这样做是在开关停止弹跳后不久触发定时器中断(“去抖时间”) 。请注意,计时器是“单次”的,不是周期性的。

下面我根据@BenVoigt 的建议(在评论中)提出了一项改进。我把它分开来表明这是他的作品。上面的方法通常可以工作,但如果你的开关特别差,下面的方法可以解决问题,而且成本很低,所以你也可以:

void debounceTimerISR()
{
    debounceTimerStop() ;

    static tDirection previous_dir = CENTRE ;
    tDirection dir = getJoystickDir() ;

    // If the state changed...
    if( previous_dir != dir )
    {
        previous_dir = dir ;

        switch( dir )
        {
            case UP :
            {
                increaseFrquency() ;
            }
            break ;

            case DN :
            {
                decreaseFrquency() ;
            }
            break ;
        }
    }
}

推荐阅读