gpt4 book ai didi

arduino - 延迟 Arduino ISR 中的限位开关去抖动

转载 作者:行者123 更新时间:2023-12-02 21:11:11 25 4
gpt4 key购买 nike

我有一个限位开关连接到 arduino Mega 2650 用于运动控制。限位开关的两个常开触点连接到 Arduino 引脚和地,因此当限位开关接合时,Arduino 引脚短路到地。

正如预期的那样,我在使用此设置时遇到了弹跳问题。我在我的 ISR 中使用计数器确认了它。最后,我编写了以下代码,似乎可以可靠地识别我的限位开关在任何给定时间点是否接合或脱离。

const int lsOuterLeftIn = 18; // lsOuterLeftIn is my Limit Switch
const int LED = 9;
volatile bool lsEngaged = false; // flag for limit switch engaged
void setup() {
pinMode(lsOuterLeftIn, INPUT_PULLUP);
pinMode(LED, OUTPUT);
attachInterrupt(digitalPinToInterrupt(lsOuterLeftIn), ISR1, FALLING);
attachInterrupt(digitalPinToInterrupt(lsOuterLeftIn), ISR2, RISING);
}
void loop() {
if (lsEngaged) digitalWrite(LED, HIGH);
else digitalWrite(LED, LOW);
}
void ISR1(){
delay(100);
lsEngaged = (digitalRead(lsOuterLeftIn));
}
void ISR2(){
delay(100);
lsEngaged = (digitalRead(lsOuterLeftIn));
}

但是,这是我的问题。我偶然发现了这个Arduino documentation page , 它说

"Since delay() requires interrupts to work, it will not work if called inside an ISR. "

但是,我确实在 ISR 中使用了 delay() 并且它似乎有效,这是怎么回事?我是否遇到过目前一切正常但很容易中断的情况,因为 delay() 函数可能会像文档中所说的那样对我造成故障?

最佳答案

TomKeddie 的回答看起来很正确:您不会有任何问题。无论如何,在我看来,至少出于两个原因,您的代码在概念上是错误的。现在我将向您解释原因。

有两种输入:一种是你必须立即回答的,另一种是你必须回答但不是直接威胁的。例如,安全止动器通常属于第一组,因为一旦你击中它,你就需要停止执行器。另一方面,UI 按钮属于第二组,因为您不需要立即回答。

注意:在一个完善的程序中,您通常可以在十分之一毫秒内响应第二种输入,因此用户永远不会看到延迟。

现在,如果您的输入属于第二组输入,则您不应使用 ISR 来读取它,因为您可能会阻止更重要的内容。而是在主循环中读取它,适本地去抖动它。例如你可以使用 Bounce 库,或者自己实现它:

#define CHECK_EVERY_MS 20
#define MIN_STABLE_VALS 5

unsigned long previousMillis;
char stableVals;

...

void loop() {
if ((millis() - previousMillis) > CHECK_EVERY_MS)
{
previousMillis += CHECK_EVERY_MS;
if (digitalRead(lsOuterLeftIn) != lsEngaged)
{
stableVals++;
if (stableVals >= MIN_STABLE_VALS)
{
lsEngaged = !lsEngaged;
stableVals = 0;
}
}
else
stableVals = 0;
}

...
}

如果值发生变化,这将每 20 毫秒检查一次。但是,只有当值稳定超过 5 个周期(即 100 毫秒)时,该值才会更新。

这样您就不会因为该任务而阻塞您的主程序。

如果另一方面,您的输入对您的设备构成严重威胁(例如终点站),您需要尽快做出回应。如果是这种情况,您需要等待 100 毫秒才能回答,这不符合您输入速度的要求。

当然你不能对这样的输入进行去抖动,因为去抖动会带来延迟。但是,您可以使一种状态优先于另一种状态。在接地端停止的情况下,严重的威胁是输入状态为接地时。所以我建议你以这样的方式设置你的变量:

  1. 当引脚掉落时,您立即将其设置为 0
  2. 当引脚上升时,您等待 100 毫秒(在主循环中),然后进行设置。

执行此操作的代码如下:

#define CHECK_EVERY_MS 20
#define MIN_STABLE_VALS 5

unsigned long previousMillis;
char stableVals;

attachInterrupt(digitalPinToInterrupt(lsOuterLeftIn), ISR1, FALLING);

...

void loop() {
if ((millis() - previousMillis) > CHECK_EVERY_MS)
{
previousMillis += CHECK_EVERY_MS;
if ((digitalRead(lsOuterLeftIn) == HIGH) && (lsEngaged == LOW))
{
stableVals++;
if (stableVals >= MIN_STABLE_VALS)
{
lsEngaged = HIGH;
stableVals = 0;
}
}
else
stableVals = 0;
}

...
}

void ISR1()
{
lsEngaged = LOW;
}

如您所见,唯一的中断是下降中断,最重要的是,它非常短。

如果您需要执行其他指令,例如停止电机,您可以在 ISR1 函数中(如果它们很短)。

请记住:ISR 必须尽可能短,因为当微 Controller 位于其中一个时,它就会对其他一切视而不见

关于arduino - 延迟 Arduino ISR 中的限位开关去抖动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33357578/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com