中文 | English

Arduino 記憶體不足不用怕,一個函數打天下

寫 Arduino 程式(其實所有程式都會啦)難免會遇到臭蟲。一般而言,臭蟲多和程式語言的的語法( Syntax,例如有左掛號但少了右括弧)或程式邏輯( Logic,例如在宣告變數前就先引用)有關。

左圖: 右圖: 左圖:語法錯誤,漏掉了右括弧而編譯失敗的程式碼
右圖:邏輯錯誤,在宣告變數 led 前就引用而編譯失敗的程式碼

以上兩者的的處理方式一般初學課程都已經教過,不外乎就是仔細檢查程式碼,找出臭蟲所在的那位置並修正它,但有一種臭蟲,就算你程式碼看得再仔細,也還是找不到的。

病歷第 xxxxx 號

病人: Arduino 程式
主訴: 無法正常運作
背景:原本程式運行良好,毫無問題,但自從_______(請從下面的選項自行帶入)後,便無法正常運作,從程式碼也看不出任何問題。

A. 加入一個函數庫
B. 加入更多 LED
C. 從 SD 卡讀如一個檔案
D. 跟另外一個 Arduino 程式合併
E. 加入一個新功能
F. 用 println 函數顯示一些文字

臆斷: 可能是記憶體不足,需安排進一步的檢查

看標題你大概也已經猜到這邊講的就是「記憶體不足註1」這個臭蟲。當程式碼你已經已經檢查再檢查,卻還是找不出問題所在,通常就要開始懷疑是記憶體不足的問題了註2。看完這篇你就可以習得: 1. 如何診斷是記憶體不足所引起的問題; 2. 如何處理這種問題。

首先來一點背景知識。對於剛寫程式不久的人來說,並不會想到記憶體是一種有限的資源。然而,記憶體一旦用盡, Arduino 就會開始不正常地運作,並且做出一些無法預測的行為。不意外的,上面所提出的六種狀況的共同點就是會讓記憶體的用量大量上升註3

以 Arduino UNO 來說,它有 2048 位元組(byte)的記憶體空間,這大約只有現在一般電腦的 1/2000000。若以一個實際一點的例子來說,它連這篇文章都無法塞入記憶體內。所以不意外地,只要一不小心,你就可能把記憶體用完。而診斷記憶體是否不足,沒有別的方法,就是時時詢問 Arduino 還剩多少可用的記憶體。這邊我們用 Adafruit 提供的程式碼,將 Arduino 還剩餘多少可用的記憶體空間顯示出來。

首先把一下這段程式碼加入你的程式裡面

int freeRam () 
{
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

並在你的程式各處,想檢查剩餘的可用記憶體的地方加入這行

Serial.println(freeRam());

如果顯示出來的數字接近 0 ,那就代表程式可能有記憶體不足的問題,但發現記憶體不足也不必驚慌,一下我們提供兩種方法,讓你的 Arduino 程式再度活過來。

  1. F()
    原本如果要序列傳輸 “This string will be stored in flash memory” 這段文字的話,一般來說都會這樣寫。

    Serial.println("This string will be stored in flash memory");

    這將佔用 42 位元組的記憶體空間,所以如果有 50 個這種長度的文字同時在記憶體中,Arduino 就沒有記憶體可以做其他事情了。但其實只要在文字外加上一個神奇的 F 函數呼叫,像下面這樣,

    Serial.println(F("This string will be stored in flash memory"));

    那文字就不再佔用 Arduino 的記憶體,瞬間省了你 42 位元組的空間。可別小看這一點點小節省,累積下來他們也可能非常驚人。

  2. 移除不用的函數庫
    如果在程式碼中看到 #include 的話,代表程式碼有引用額外的函數庫,但是有時候這些額外的函數庫並沒有實際被使用(例如你下載別人寫好的程式碼再修改過),像是明明沒有用伺服馬達,卻在程式碼內看到:

    #include <Servo.h>

    這時伺服馬達的函數庫,就只是白白在佔用你的記憶體,透過刪掉那行引用宣告,就可以把被吃掉的記憶體要回來。如果不確定函數庫有沒有被使用也沒關係,可以試試把引用宣告刪掉,再編譯程式碼。如果編譯成功,代表有很高的機率,那個函數庫並沒有被使用;反之,如果刪掉引用宣告後程式無法成功編譯,那就代表那個函數庫有被使用,這時只要把剛剛被刪掉的那行引用宣告,補回來就行了。

 

參考資料

 

註1. 這邊是指一般稱為 SRAM 的記憶體,跟儲存 Sketch 的 Flash 並不相同,由於篇幅有限這邊就不解釋兩者的差別。

註2. 比較正確的說法應該是「硬體相關」的問題,這包括了電壓不穩、跳線鬆脫、零件損壞等等,記憶體不足也只是「硬體相關」問題的其中一種,並不是唯一可能;但因為本篇的目的是介紹記憶體不足的問題,所以假設硬體運作正常。

註3. 記憶體用量上升是很平常的事情,一般沒什麼好擔心的,但當你的程式的記憶體使用量本來就已經偏高,這時大量增加記憶體用量的情況可能就成為壓垮 Arduino 的最後一根稻草。

分享到社群

SHY

半途出家踏入資工與資安的領域,發現軟體硬體本一家,又玩起 Arduino 與 Raspberry Pi ,基本上什麼都碰一點,夢想是成為一隻駭客犬。

This site or product includes IP2Location LITE data available from https://lite.ip2location.com.