Arduino有數百款相容開發板,它們有不同的名稱和微控器。以Arduino官方的 UNO R3與R4為例,兩種開發板採用不同廠商、不同架構的微控器,UNO R3採用ATmega328,屬於AVR系列,Arduino Micro, Leonardo(李奧納多)和MEGA 2560開發板,也都採用AVR系列微控器。
UNO R4開發板採用日本瑞薩電子(Renesas Electronics)的RA4M1微控器,除了R4,Arduino原廠的一款,定位在「工業級」高階產品的Portenta C33開發板,也採用瑞薩電子的微控器。
Arduino IDE會根據我們選用的開發板,編譯出能在特定微控器執行的二進位檔(也就是「可執行檔」)。
雖然大多數的Arduino原始程式碼都是相通的,但有些程式只能在特定開發板運作,例如,只有Arduino UNO R4 WiFi板內建12 × 8 LED點陣,所以操控這些LED點陣的程式,也只能用於UNO R4 WiFi開發板。如果選用UNO R3開發板,編譯操控UNO R4點陣LED的程式,將在編譯階段發生錯誤。
另一個例子是《超圖解Arduino互動設計》第五版,5-30頁「控制UNO R4 Minima的TX和RX LED燈」的程式,選用UNO R3和UNO R4 WiFi開發板編譯該程式,也會發生編譯錯誤。
依據「開發板名稱」選擇編譯目標
我們可以用前置處理器指令,在程式編譯階段檢測目前選用的開發板(也就是「目標開發板」),若不符合要求,則顯示「這不是◯◯◯開發板」之類的錯誤訊息並停止編譯。
底下列舉供前置處理器使用的三款開發板識別名稱常數:
- Arduino UNO R3板:ARDUINO_AVR_UNO
- Arduino UNO R4 Minima板:ARDUINO_UNOR4_MINIMA或ARDUINO_MINIMA
- Arduino UNO WiFi板:ARDUINO_UNOR4_WIFI或ARDUINO_UNOWIFIR4
開發板的識別名稱紀錄在各個開發平台的boards.txt檔,這是AVR系列處理器的boards.txt檔,這個是採用瑞薩電子微控器系列的開發板的boards.txt檔。
boards.txt檔中的每個開發板都有一個build.board屬性,以UNO R4 Minima和R4 WiFi開發板為例:
在build.board屬性值加上“ARDUINO_”前綴(參閱下文說明),就是該開發板的識別名稱。
加入判斷目標開發板是否為UNO R4 Minima的「控制UNO R4 Minima的TX和RX LED燈」程式碼如下:
#ifndef ARDUINO_MINIMA #error "請選用UNO R4 MINIMA開發板!" #else bool flag = true; void setup() { pinMode(LED_TX, OUTPUT); // TX腳(21)設成「輸出」模式 pinMode(LED_RX, OUTPUT); // RX腳(22)設成「輸出」模式 } void loop() { if (flag) { digitalWrite(LED_TX, HIGH); digitalWrite(LED_RX, LOW); } else { digitalWrite(LED_TX, LOW); digitalWrite(LED_RX, HIGH); } flag = !flag; delay(500); } #endif
第一行可改寫成:
#if !defined(ARDUINO_MINIMA)
同樣地,底下敘述將能編譯適用於UNO R4 Minima, UNO R4 WiFi和其他開發板的程式檔。
#if defined(ARDUINO_MINIMA) // 僅適用於UNO R4 Minima開發板的程式碼 #elif defined(ARDUINO_UNOWIFIR4) // 僅適用於UNO R4 WiFi開發板的程式碼 #else // Arduino平台通用的程式碼 #endif
依據「開發平台」選擇編譯目標
假如要針對UNO R4 Minima或UNO R4 WiFi編譯程式,除了使用底下的前置處理器條件式:
// 若開發板不是UNO R4 Minima,也不是UNO R4 WiF… #if !defined(ARDUINO_MINIMA) && !defined(ARDUINO_UNOWIFIR4) #error "請選用UNO R4 MINIMA或R4 WIFI開發板!" #else // UNO R4 MINIMA或R4 WIFI開發板適用的程式碼 #endif
還可以用「開發平台」的識別名稱或者說「微控器架構」來篩選,例如:
- ARDUINO_ARCH_AVR:代表AVR架構的微控器,例如:UNO R3開發板的ATmega328、Leonardo(李奧納多)板子的ATmega32u4、MEGA 2560開發板的ATmega2560。
- ARDUINO_ARCH_ESP32:泛指所有採用ESP32系列晶片的開發板。
- ARDUINO_ARCH_ESP8266:泛指所有採用ESP8266系列晶片的開發板。
- ARDUINO_ARCH_RENESAS:代表採用瑞薩電子的微控器的開發板,如:UNO R4 Minima和UNO R4 WiFi。
開發平台的識別名稱定義在Arduino開發環境的platform.txt檔,例如,底下是AVR架構的platform.txt檔的其中一行敘述:
其中定義了幾個編譯時期使用的巨集:
- -DF_CPU={build.f_cpu}:從boards.txt取得定義微控制器時脈頻率的 build.f_cpu參數,定義 F_CPU 巨集。
- -DARDUINO={runtime.ide.version}:以Arduino IDE版本的值定義 ARDUINO 巨集。
- -DARDUINO_{build.board}:從boards.txt取得 build.board 參數,定義開發板識別名稱的巨集,例如ARDUINO_UNO。
- -DARDUINO_ARCH_{build.arch}:定義微控器架構的巨集,例如:ARDUINO_ARCH_AVR。
所以,判斷目標開發板是否為UNO R4 Minima或UNO R4 WiFi開發板的前置處理器指令的敘述可寫成:
#ifndef ARDUINO_ARCH_RENESAS #error "請選用UNO R4 MINIMA或R4 WIFI開發板!" #else // UNO R4 MINIMA或R4 WIFI開發板適用的程式碼 #endif
依據「微控器名稱」選擇編譯目標
boards.txt裡的build.mcu屬性定義了微控器的名稱,例如:
這個屬性值將在編譯階段,由一節platform.txt裡的-mmcu參數讀取,並產生微控器名稱,例如:
- __AVR_ATmega328P__:代表ATmega328P微控器
- __AVR_ATmega2560__:代表ATmega2560微控器
- __AVR_ATmega32U4__:代表ATmega32U4微控器
因此,底下的前置處理器指令可判斷是否為採用ATmega328P微控器的開發板:
#ifndef __AVR_ATmega328P__ #error "請選用UNO R3開發板!" #else // UNO R3開發板適用的程式碼 #endif