c++ - 在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){}
}
解决方案
机械开关弹跳或多或少是所有机械开关的一个特征。通常需要在软件中实现“去抖动”,尤其是在这种情况下开关直接驱动中断的情况下。
快速谷歌搜索软件谴责技术会产生一些相当糟糕的技术 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 ;
}
}
}
推荐阅读
- angular - 订阅没有收到下载文件的响应
- python - 如何在谷歌工作表中将逗号分隔的整数字符串写为字符串?
- vb.net - 如何从 utf-8 BinaryWriter 中删除字节顺序掩码?
- wpf - 索引 ArgumentOutOfRangeException 当 DataGrid 在添加项目后刷新自身时
- javascript - 在 jquery-ui 自动完成上设置自定义输入字段值
- kubernetes-ingress - 如何使入口 nginx 在每个请求上返回 200
- python-3.x - 使用 boto3 从 AWS S3 存储桶下载 - 时间戳格式不正确
- symfony - symfony:无法运行功能测试
- python - 从 Keras 模型进行预测
- c# - C# UWP OpenWeatherAPI 使用 mvvm