善用 arduino 的指令行參數
Tags: arduino, cli
Published: 2021-07-30 09:08:28

許多人每天都在使用 Arduino IDE, 但都是從開始功能表或是工作列用滑鼠按一下執行, 卻不知道 Arduino IDE 其實有[指令行](https://github.com/arduino/Arduino/blob/master/build/shared/manpage.adoc)的參數, 可以讓你進行許多特別的工作, 這裡我們介紹幾個我個人覺得相當有用的參數給大家參考。

## 執行 Arduino IDE 的指令在哪裡？

要使用指令行參數, 就需要知道啟動 Arduino IDE 的指令到底在哪裡？我們分別依照不同的平台來說明。

### Windows

在 Windows 下, 你可以在 Arduino 安裝資料夾下 (我建議下載 zip 格式的檔案解開使用) 找到 arduino.exe 與 arduino_debug.exe 這 2 個執行檔, 差別在於 arduino.exe 只是一個跳板, 執行後本身會立刻結束, 不會等待 Arduino IDE 執行, 例如：

![](https://i.imgur.com/BDDCwhv.png)

你可以看到下達 arduino 指令後, 它本身就結束了, 但是 Arduino IDE 還在執行。但如果是使用 arduino_debug.exe, 就會等待 Arduino IDE 執行：

![](https://i.imgur.com/A1njgl1.png)

你會發現下達指令後不但不會馬上結束, 還會噴出一大堆訊息, 這也表示如果你希望能擷取輸出訊息 (例如用其他自動化工具執行 Arduino) 的話, 就一定要使用 arduino_debug.exe。

### MacOS

Mac 上因為應用程式封裝格式的關係, 整個 Arduino 資料夾結構和 Windows/Linux 不一樣, 下載回來的 Arduino 是一個壓縮檔, 解開後看起來好像是一個單一執行檔 (會顯示 Arduino 圖示), 但其實只是一個有特定結構的資料夾, 這種資料夾在 finder 中看起來就像是一個執行檔, 用滑鼠雙按不會開啟資料夾, 而是執行其中的程式。

如果你要在終端機中使用指令執行 Arduino, 可以先切換到放置 Arduino 的路徑, 然後在以下位置找到真正的執行檔：

```
./Arduino.app/Contens/MacOS/Arduino
```

在 MacOS 下並沒有區分 Arduino 與 Arduino.exe。

### Linux

Linux 下的 Arduino 跟 Windows 基本上是相近的, 只要在 Arduino 安裝的資料夾下就可以找到 arduino 可執行檔, 也沒有區分 arduino 與 arduino_debug。

## 使用 --preferences-file 參數執行不同設定的 Arduino IDE

不知道各位有沒有遇過這樣的狀況, 想要同時使用 UNO 和 Mega 開發板, 或者同時使用兩個 UNO 板, 但接在不同的序列埠, 若用同一個 Arduino IDE 開兩個視窗個別撰寫程式, 每次要上傳程式時就得根據開發板修改設定, 不然兩個視窗都會同步變更設定, 更改任何一個視窗的設定, 就會讓所有的視窗都變成一樣的設定。


要解決這個問題, 可以使用指令行執行兩次 arduino 啟動兩個獨立的 Arduino IDE, 在兩個 Arduino 視窗分別設定, 就可以分別針對不同的開發板或是序列埠上傳程式。不過這樣的作法, 因為是使用同一個設定檔, 在關閉 Arduino IDE 時, 最後關閉的 Arduino IDE 會用它目前的設定儲存到設定檔中, 所以下次即使再用指令行開啟兩次 Arduino IDE, 這兩個 Arduino IDE 都會讀取同一個設定檔, 因此會是一樣的設定。

若要測底解決上述的問題, 可以在指令行加上 `--preferences-file` 參數指定不同設定檔的方式來啟動 Arduino IDE, 例如：

```
❯ .\arduino --preferences-file D:\temp\MySketch\setting1.txt
❯ .\arduino --preferences-file D:\temp\MySketch\setting2.txt
```

我們分別指定以 setting1.txt 和 setting2.txt 為設定檔啟動 Arduino IDE, 這時就可以為兩個 Arduino IDE 設定不同的開發板或是序列埠, 而且因為是使用不同的設定檔, 所以即使關閉 Arduino IDE 後, 只要再指定相同的設定檔, 就會回復原本的設定, 彼此不會打架。如果你希望能在不同情境下使用不同的 Arduino IDE 設定, 那這個功能就非常適合。

## 使用 --pref 與 --save-prefs 指定草稿碼資料夾

剛剛介紹的功能可以客製化設定檔, 如果你希望進一步客製化 Arduino 的執行環境, 還可以使用 --seve-prefs 和 --pref 參數, 例如：

```
❯ .\arduino --preferences-file D:\temp\MySketch\setting2.txt --pref sketchbook.path=d:\temp\MySketch --save-prefs
```

其中 `--save-prefs` 參數是將偏好設定寫入設定檔的意思, 而 `--pref` 參數則可以用來指定要變更的設定項目, 其中 `sketchbook.path` 指的就是預設的草稿碼資料夾, 也就是你要儲存草稿碼時 Arduino IDE 會選取的預設位置。用到 `--pref` 參數的指令並不會啟動 Arduino IDE, 你必須自行啟動 Arduino IDE, 啟動後如果你按儲存, 就會發現預設的資料夾已經變成你剛剛指定的路徑了：

![](https://i.imgur.com/E4z0WeC.png)

不過預設儲存位置並不是我們關心的功能, 大多數情況下我也不會把草稿碼儲存在這裡。真正重要的是草稿碼資料夾也是 Arduino IDE 安裝程式庫的地方。舉例來說, 如果我有 A、B 兩個不同版本的同一個程式庫, 有個專案一定要使用 A 版本, 另一個專案卻一定要使用 B 版本, 那我們就可以在不同的資料夾中安裝個別版本的程式庫, 並依據開發的專案指定不同的草稿碼資料夾。例如以下是沒有指定草稿碼資料夾時 Arduino IDE 的**匯入程式庫**畫面：

```
❯ .\arduino
```

![](https://i.imgur.com/0Z6ir0Z.png)

你可以看到除了預設的程式庫外, 並沒有任何第三方的程式庫。現在我們直接複製多個程式庫到 d:\temp\MySketch 的 libries 資料夾下：

![](https://i.imgur.com/BxHpZ2k.png)

接著再使用前面介紹的方式更改草稿碼資料夾後啟動 Arduino IDE：

```
❯ .\arduino --preferences-file D:\temp\MySketch\setting2.txt --pref sketchbook.path=d:\temp\MySketch --save-prefs
❯ .\arduino --preferences-file D:\temp\MySketch\setting2.txt
```

再查看 Arduino IDE 的**匯入程式庫**畫面：

![](https://i.imgur.com/VpjzOk3.png)

就會發現放在 libraries 下的程式庫通通出現了。利用這種方式, 即使有同樣名稱的程式庫, 只要出現在不同的草稿碼資料夾下, 就不會打架了, 也可以控制到底要用哪一個版本的程式庫。

## 使用 --upload 上傳程式

你也可以使用 `--upload` 上傳程式, 如果你只是要編譯程式, 確認程式是否語法正確, 可以改用 `--verify`。例如以下是上傳程式到 UNO 開發板的指令：

```
❯ .\arduino_debug --upload --board arduino:avr:uno --port com11 D:\temp\MySketch\Blink\Blink.ino
```

要注意的是, 若是 Windows 平台, 一定要使用 arduino_debug。這裡的 `--upload` 就是上傳程式、`--port` 則是指定序列埠, 而 `--board` 則是指定開發板, 格式是`套件名稱：架構名稱：開發板名稱：參數`, 如果是 Arduino 官方標準開發板, 這些名稱可以在 Arduino 資料夾下的 hardware 下找到 (MacOS 是在 Arduino.app/Contents/Java/hardware)。

以 UNO 為例, 在 Arduino\hardware 下只有 arduino 與 tools 資料夾, tools 是工具程式的資料夾, 因此 UNO 的套件名稱就是 arduino。在 arduino 資料夾下就是以架構名稱建立的個別資料夾, 這裡只有 avr 資料夾, 所以架構名稱就是 avr。開發板名稱則是放在架構名稱資料夾下的 boards.txt 檔中, 只要搜尋其中包含有 "name=" 字樣的每一行, 就可以知道個別開發板的名稱：

```
❯ findstr "name=" hardware\arduino\avr\boards.txt
yun.name=Arduino Y繳n
uno.name=Arduino Uno
diecimila.name=Arduino Duemilanove or Diecimila
nano.name=Arduino Nano
...
unowifi.name=Arduino Uno WiFi
```

在 ".name=" 左邊的是開發板的名稱, 右邊的是在 Arduino IDE 開發板功能表顯示的名稱, `--board` 要用的是左邊的名稱。因此, 要上傳程式到 UNO 開發板時 `--board` 參數值就要指定為 `arduino:avr:uno`。

如果是額外安裝的開發板套件, 安裝位置在`使用者資料夾\AppData\local\Arduino15\packages` 下 (MacOS 的位置在 ~/Library/Arduino15/packages/、Linux 在 ~/.arduino15/packages/)：

```
❯ ls C:\Users\ShinWei\AppData\Local\Arduino15\packages\

    Directory: C:\Users\ShinWei\AppData\Local\Arduino15\packages

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----         2021/7/28 下午 04:01                esp8266
```

這裡的第一層資料夾名稱就是套件名稱, 上例中我安裝有 esp8266 套件。下一層是 hardware 資料夾, 再下一層資料夾就是架構名稱, 再下一層可能會有版本編號的資料夾, 其中一樣有 boards.txt 紀錄各種開發板的名稱。我們可以查看看有哪些 esp8266 的開發板：

```
❯ findstr name= C:\Users\ShinWei\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\3.0.2\boards.txt
generic.name=Generic ESP8266 Module
...
d1_mini.name=LOLIN(WEMOS) D1 R2 & mini
d1_mini_clone.name=LOLIN(WEMOS) D1 mini (clone)
d1_mini_lite.name=LOLIN(WEMOS) D1 mini Lite
d1_mini_pro.name=LOLIN(WEMOS) D1 mini Pro
d1.name=LOLIN(WeMos) D1 R1
agruminolemon.name=Lifely Agrumino Lemon v4
nodemcu.name=NodeMCU 0.9 (ESP-12 Module)
nodemcuv2.name=NodeMCU 1.0 (ESP-12E Module)
...
cw01.name=XinaBox CW01
```

所以如果要上傳程式到 D1 mini 開發板, 就可以利用以下指令：

```
❯ .\arduino_debug --upload --board esp8266:esp8266:d1_mini --port com4 D:\temp\MySketch\Blink\Blink.ino
```

### 顯示詳細編譯上傳資訊

如果你覺得下完指令後不知道到底現在進行到什麼步驟, 那也可以加上 `--verbose-build` 在編譯期間顯示詳細資訊, 或者加上 `--verbose-upload` 在上傳程式期間顯示詳細資訊, 如果以上兩者都要, 可以使用 `--verbose` 來替代, 例如：

```
❯ .\arduino_debug --verbose --upload --board esp8266:esp8266:d1_mini --port com4 D:\temp\MySketch\Blink\Blink.ino
```

你會看到它噴出超多訊息, 如果想知道詳細的編譯上傳步驟, 就可以好好研究其中的一步步指令。

### 加入額外的參數

有些開發板在上傳程式時可能會需要額外的參數, 例如市面上大部分的 NANO 板就可能需要指定使用舊的 bootloader, 這些參數就是你在 Arduino IDE 中開發板下方看到的功能表選項：

![](https://i.imgur.com/qbLNw23.png)

在 boards.txt 中只要用開發板名稱搜尋就會看到相關資料, 例如：

```=
❯ findstr nano .\hardware\arduino\avr\boards.txt
nano.name=Arduino Nano
nano.upload.tool=avrdude
nano.upload.protocol=arduino
nano.bootloader.tool=avrdude
nano.bootloader.unlock_bits=0x3F
nano.bootloader.lock_bits=0x0F
nano.build.f_cpu=16000000L
nano.build.board=AVR_NANO
nano.build.core=arduino
nano.build.variant=eightanaloginputs
nano.menu.cpu.atmega328=ATmega328P
nano.menu.cpu.atmega328.upload.maximum_size=30720
nano.menu.cpu.atmega328.upload.maximum_data_size=2048
nano.menu.cpu.atmega328.upload.speed=115200
nano.menu.cpu.atmega328.bootloader.low_fuses=0xFF
nano.menu.cpu.atmega328.bootloader.high_fuses=0xDA
nano.menu.cpu.atmega328.bootloader.extended_fuses=0xFD
nano.menu.cpu.atmega328.bootloader.file=optiboot/optiboot_atmega328.hex
nano.menu.cpu.atmega328.build.mcu=atmega328p
nano.menu.cpu.atmega328old=ATmega328P (Old Bootloader)
nano.menu.cpu.atmega328old.upload.maximum_size=30720
nano.menu.cpu.atmega328old.upload.maximum_data_size=2048
nano.menu.cpu.atmega328old.upload.speed=57600
nano.menu.cpu.atmega328old.bootloader.low_fuses=0xFF
nano.menu.cpu.atmega328old.bootloader.high_fuses=0xDA
nano.menu.cpu.atmega328old.bootloader.extended_fuses=0xFD
nano.menu.cpu.atmega328old.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex
nano.menu.cpu.atmega328old.build.mcu=atmega328p
nano.menu.cpu.atmega168=ATmega168
nano.menu.cpu.atmega168.upload.maximum_size=14336
nano.menu.cpu.atmega168.upload.maximum_data_size=1024
nano.menu.cpu.atmega168.upload.speed=19200
nano.menu.cpu.atmega168.bootloader.low_fuses=0xff
nano.menu.cpu.atmega168.bootloader.high_fuses=0xdd
nano.menu.cpu.atmega168.bootloader.extended_fuses=0xF8
nano.menu.cpu.atmega168.bootloader.file=atmega/ATmegaBOOT_168_diecimila.hex
nano.menu.cpu.atmega168.build.mcu=atmega168
```

nano.menu 後面就是功能表中選項的名稱, 像這裡 NANO 板只有 cpu 選項 (中文版的功能表會顯示為『處理器』),  cpu 後面就是子選單中的項目, 像是剛剛功能表中看到的 3 個項目就對應到第 12、21、30, 等號右邊就是顯示在功能表中的文字。其他各行就是該選項代表的細部資訊。因此, 如果要指定使用舊的 bootloader, 就要加上 cpu 參數, 參數值為 atmega328old, 如下：

```
❯ .\arduino_debug --upload --board arduino:avr:nano:cpu=atmega328old --port com15 D:\temp\MySketch\Blink\Blink.ino
```

### 保留暫存檔

另外有個選項是 `--preserve-temp-files`, 可以將編譯上傳過程中的暫存檔留下來使用, 不過我測試的結果好像沒有省多少時間, 不論是 UNO 或是 ESP8266, 大概省 3 秒。

### 整合運用

在使用 `--upload` 或是 `--verify` 參數時也可以搭配前面介紹過的 `--pref sketchbook.path=` 來指定草稿碼資料夾, 搭配不同的程式庫或是套件版本運作, 如果沒有同時指定 `--save-prefs` 參數, 那麼就不會把草稿碼資料夾的設定寫入設定檔中, 只會影響此次上傳程式的過程。

## 總結

透過本篇文章的說明, 我們就可以把 arduino 或是 arduino_debug 當成便利的指令, 甚至可以讓你自行採用偏好的程式碼編輯器, 搭配終端機開發專案了。