如何在Arduino中使用易失变量?


就像在 C 和 C++ 中一样,如果变量可以在中断例程中修改,则需要使用 volatile 关键字限定该变量。

将变量限定为 volatile 时,后台会发生以下情况:

  • 编译器会收到指令,将变量加载到 RAM 中,而不是存储寄存器(程序变量通常存储/操作的地方)。

  • 这确保了在 **loop()** 函数外部(例如,在中断服务例程中)对变量的任何更改都会立即反映在 **loop()** 函数中。

如果变量的大小大于一个字节(**int** 或 **long**),那么像 Arduino Uno 这样的 8 位微控制器将每次读取 8 个字节的变量。这可能会导致问题(在微控制器读取前 8 个字节时,变量的下一个 8 个字节可能已更改)。这可能会导致一些随机错误。为避免这种情况,您可以使用以下方法之一:

  • 使用 ATOMIC_BLOCK 宏(这会将读取操作转换为原子操作,在读取过程中内容不会更改)。为此,您需要包含 **<util/atomic.h>**,语法如下所示 这里

  • 在读取变量时,使用 **noInterrupts()** 禁用中断。

示例

下面给出了一个包含易失变量的示例:

#include <util/atomic.h>
volatile int flag = 0;
int flagValue = 0;
void setup() {
   Serial.begin(9600);
   pinMode(LED_BUILTIN, OUTPUT);
   attachInterrupt(digitalPinToInterrupt(2), interruptFunction, CHANGE);
}
void loop() {
   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
      // code with interrupts blocked (consecutive atomic operations will
not get interrupted)
      flagValue = flag;
   }
   if (flagValue == 1) {6305298009
      flag = 0;
      flagValue = 0;
      Serial.println("Interrupt encountered!");
   }
}
void interruptFunction() {
   flag = 1;
}

请注意,只有 **flag** 被定义为 volatile,因为它是在中断中唯一值会改变的变量。使用 **noInterrupts()** 的相同代码如下所示:

volatile int flag = 0;
int flagValue = 0;
void setup() {
   Serial.begin(9600);
   pinMode(LED_BUILTIN, OUTPUT);
   attachInterrupt(digitalPinToInterrupt(2), interruptFunction, CHANGE);
}
void loop() {
   noInterrupts();
   flagValue = flag;
   interrupts();
   if (flagValue == 1) {
      flag = 0;
      flagValue = 0;
      Serial.println("Interrupt encountered!");
   }
}
void interruptFunction() {
   flag = 1;
}

更新于:2021年7月24日

2K+ 次浏览

启动您的职业生涯

通过完成课程获得认证

开始学习
广告