如何在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; }
广告