本系列文已改編成書「Arduino 自造趣:結合 JavaScript x Vue x Phaser 輕鬆打造個人遊戲機」,本書改用 Vue3 與 TypeScript 全面重構且加上更詳細的說明,
在此感謝 iT 邦幫忙、博碩文化與編輯小 p 的協助,歡迎大家前往購書,鱈魚在此感謝大家 (。・∀・)。
若想 DIY 卻不知道零件去哪裡買的讀者,可以參考此連結 。( •̀ ω •́ )✧
電子助教:「(大包小包)窩準備好了 (≖‿ゝ≖)✧」
鱈魚:「東西放下,我們沒有要轉生。」
電子助教:「說好的香香妹子們呢?(́⊙◞౪◟⊙‵)」
鱈魚:「別瞎掰好嗎」
電子助教:(每天眼前只有一隻肥宅魚,我的電生怎麼這麼歹命 ( ´•̥̥̥ ω •̥̥̥` ))
鱈魚:「你心裡是不是在想甚麼很失禮的事情... (´ー`)」
接下來我們將慢慢研讀 Firmata Protocol,並自行設計 Firmata 收發套件。
首先打開 Firmata Protocol 的 Github,並點擊「protocol.md」文件。
此文件便是 Firmata 的基礎內容,詳細說明 Firmata 之 MIDI 格式、數位類比資料響應等等。
我們不要從頭開始啃(以免大家都跑光 ...(ˊДˋ;)),循序漸進地一步一步來。
讓我們回到 D03 串列埠監控視窗那一串奇怪的文字開始吧。
串列通訊傳輸資料時,都是一個 byte 一個 byte 進行傳輸,一個 byte 表示 0~255 的數值,意思是不管甚麼文字或符號,都會被轉換成 0~255 之間的數值。
數值與字元之前的對照關係就是「ASCII」,每個符號都有自己對應的數值,如下表(圖片只包含部分內容):
中文或其他語系文字則會使用多個 byte 進行表示,詳細資料請見連結。
意思是「hi」這段文字透過串列通訊傳輸時會是「104 105」,而 Arduino IDE 的串列埠監控視窗會自動將數值轉換成字元,所以 Firmata 的內容看起來會是一堆亂碼,因為他並不是傳文字字元。
不過我們希望可以直接觀察原始數值內容,所以這裡要請出另一個工具 — 「AccessPort」。
(其實不下載 AccessPort 也沒關係,,因為只用這一次 ( ´∀` ))
下載、解壓縮完成後,打開程式,會跑出以下畫面:
如果長的不一樣,請確認紅框選項為「Terminal」
接著按下橘框的「齒輪」按鈕,打開設定,並檢查紅框內的設定是否相符。
「串口」請選擇 Arduino Uno 對應的 COM
設定完成後按下確定,AccessPort 會自動開啟 Port,這個時候應該會跑出一串數值,如下圖。
如果是一串亂碼,請確認紅框內的 Hex 選項被啟用。
讓我們來好好分析這串數值。
第一個數值
⇙
F9 02 05 F0 79 02 05 53 00 74 00 61 00 6E 00 64 00 61 00 72 00 64 00 46 00 69 00 72 00 6D 00 61 00 74 00 61 00 50 00 6C 00 75 00 73 00 2E 00 69 00 6E 00 6F 00 F7
在 protocol.md 中搜尋第一個數值「F9」,就會在「Message Types」找到他。
可以發現其實前 3 個 Byte 是用來描述協定版本,也就是說:
F9 02 05
意思為:
所以我們可以得出此韌體協定版本為 2.5 版。
接著讓我們去除已知意義的數值,接下來的第一個數值是「F0」
F9 02 05 // 協定版本
接下來的第一個數值
⇙
F0 79 02 05 53 00 74 00 61 00 6E 00 64 00 61 00 72 00 64 00 46 00 69 00 72 00 6D 00 61 00 74 00 61 00 50 00 6C 00 75 00 73 00 2E 00 69 00 6E 00 6F 00 F7
一樣會在「Message Types」找到「F0」。
會發現「F0」為 sysex 的起始值,所以甚麼是「sysex」呢?讓我們移駕到「Sysex Message Format」的部分。
System exclusive (sysex) messages are used to define sets of core and optional firmata features. Core features are related to functionality such as digital and analog I/O, querying information about the state and capabilities of the microcontroller board and the firmware running on the board. All core features are documented in this protocol.md file. Optional features extend the hardware capabilities beyond basic digital I/O and analog I/O and also provide APIs to interface with general and specific components and system services. Optional features are individually documented in separate markdown files.
從以上文檔的說明中,我們可以知道 sysex 表示一種用來描述並定義核心功能與各種 I/O 的訊息格式。
所以我們可以在 SysEx commands 中找到第二個數值「79」的蹤影:
並在「Query Firmware Name and Version」中找到詳細的回應內容說明:
大家會注意到裡面出現了 LSB、MSB,我們先解釋一下這是甚麼,他們分別為:
接著探討一個問題。
將超過 1 bye 的數值拆分成多個 byte 傳輸,接收時再將數值組裝回來即可,具體過程如下:
接下來根據以下說明:
0 START_SYSEX (0xF0)
1 queryFirmware (0x79)
2 major version (0-127)
3 minor version (0-127)
4 first char of firmware name (LSB)
5 first char of firmware name (MSB)
6 second char of firmware name (LSB)
7 second char of firmware name (MSB)
... for as many bytes as it needs
N END_SYSEX (0xF7)
我們可以得知:
所以我們將剛才的數值分類、整理一下,得:
F9 02 05 // 協定版本
F0 // 起始值
79 // 查詢韌體命令
02 // major version
05 // minor version
53 00 // firmware name
74 00
61 00
6E 00
64 00
61 00
72 00
64 00
46 00
69 00
72 00
6D 00
61 00
74 00
61 00
50 00
6C 00
75 00
73 00
2E 00
69 00
6E 00
6F 00
F7 // 結束值
firmware name 的部分,因為 MSB 都是 00,所以數值組合後也等於 LSB,我們接著比對 ASCII 表(注意數值為 16 進位),就可以得出數值表示的字元,得:
F9 02 05 // 協定版本
F0 // 起始值
79 // 查詢韌體命令
02 // major version
05 // minor version
53 00 // 53 = S
74 00 // 74 = t
61 00 // 61 = a
6E 00 // 6E = n
64 00 // 64 = d
61 00 // 61 = a
72 00 // 72 = r
64 00 // 64 = d
46 00 // 46 = F
69 00 // 69 = i
72 00 // 72 = r
6D 00 // 6D = m
61 00 // 61 = a
74 00 // 74 = t
61 00 // 61 = a
50 00 // 50 = P
6C 00 // 6C = l
75 00 // 75 = u
73 00 // 73 = s
2E 00 // 2E = .
69 00 // 69 = i
6E 00 // 6E = n
6F 00 // 6F = e
F7 // 結束值
firmware name 的部分合併之後就會得到「StandardFirmataPlus.ino」。
最後總結一下,我們知道原本的那一大串數值其實有兩個部分:
// 第一部分
F9 02 05
// 第二部分
F0 79 02 05 53 00 74 00 61 00 6E 00 64 00 61 00 72 00 64 00 46 00 69 00 72 00 6D 00 61 00 74 00 61 00 50 00 6C 00 75 00 73 00 2E 00 69 00 6E 00 6F 00 F7
第一部分:
第二部分:
以上我們成功邁出看懂 Firmata 的第一步了!