如何在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+ 次瀏覽

啟動您的職業生涯

透過完成課程獲得認證

開始學習
廣告
© . All rights reserved.