如何在 Arduino 中使用易失性变量?
就像在C和C++中一样,如果变量可以在中断例程中修改,则需要使用volatile关键字对其进行限定。
当您将变量限定为volatile时,这就是幕后发生的事情-
编译器被指示变量应该加载到RAM而不是存储寄存器(程序变量通常存储/操作)
这确保了对外部变量的任何更改loop()(例如在中断服务例程中),立即反映在loop()
如果您有一个大于一个字节的变量(int或long),那么8位微控制器(如ArduinoUno)将以8个字节的步长读取该变量。这可能会导致问题(当微控制器读取前8个字节时,变量的下一个8个字节可能已更改)。这可能会导致一些随机错误。为避免这种情况,您可以使用以下方法之一-
使用ATOMIC_BLOCK宏(这将读取操作转换为原子操作,其中内容在读取时不能更改)。为此,您需要包含
noInterrupts()在读取变量时禁用中断使用。
示例
下面给出了一个带有volatile变量的例子-
#includevolatile 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) { //中断被阻塞的代码(连续的原子操作将 not get interrupted) flagValue = flag; } if (flagValue == 1) {6305298009 flag = 0; flagValue = 0; Serial.println("遇到中断!"); } } void interruptFunction() { flag = 1; }
请注意,只有标志被定义为易失性,因为它是唯一一个值在中断内发生变化的变量。与上面相同的代码,使用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("遇到中断!"); } } void interruptFunction() { flag = 1; }