Arduino 有 林 林 總 總 各 式 各 樣 的 Sensors,絕 大 部 分 Sensors 的 店 家 ,都 會 提 供 能 在 Arduino 上 使 用 的 libraries。但 偏 偏 這 些 Arduino libraries 都 不 能 夠 直 接 在 mBlock 上 面 使 用 ,對 廣 大 的 入 門 使 用 者 造 成 了 相 當 的 困 難 。
但 其 實 ,mBlock 本 身 亦 有 擴 展 功 能 ,不 過 它 不 叫 libraries,而 是 叫 做 extensions。其 實 我 們 只 要 通 過 幾 個 簡 單 的 步 驟 ,就 可 以 把 sensor 的 arduino library 自 己 改 寫 成 mblock 用 的 extension。下 面 我 們 一 起 實 作 幾 個 例 子 吧 。
筆 者 手 邊 正 好 有 幾 個 不 同 類 型 的 顯 示 器 ,正 好 拿 來 作 示 範 用 途 。
第 一 個 就 是 在 之 前 《我 的 Stem Project (八 )》也 有 用 過 的 4 位 數 碼 管 ,它 是 由 一 個 TM1637 晶 片 去 推 動 的 。之 前 第 八 課 ,那 個 由 店 家 提 供 的 Arduino Library 其 實 很 不 好 用 ,所 以 這 一 次 ,我 就 選 了 另 一 個 在 Arduino 網 頁 找 得 到 的 TM1637 Arduino Library,名 字 就 叫 TM1637Display。
介 紹 :https://playground.arduino.cc/Main/TM1637
介 紹 :https://github.com/avishorp/TM1637
下 載 :https://github.com/avishorp/TM1637/releases/
我 下 載 的 是 v1.1.0,解 壓 之 後 裡 面 有 很 多 檔 案 ,也 有 例 子 之 類 的 。要 自 己 改 寫 成 mBlock extension,我 們 只 需 要 裡 面 的 TM1637Display.h 和 TM1637Display.cpp。.h 檔 和 .cpp 檔 才 是 arduino library 真 正 的 source code 所 在 。
有 了 源 材 料 ,我 們 就 可 以 開 始 打 造 我 們 的 第 一 個 mBlock extension 了 。每 一 個 mBlock extension 其 實 就 是 一 個 folder,有 其 相 關 的 獨 特 格 式 。
首 先 ,我 們 會 有 一 個 *.s2e 檔 ,這 檔 案 是 用 來 定 義 整 個 extension 的 ,可 以 說 是 整 個 extension 的 靈 魂 。然 後 分 別 會 有 兩 個 sub-folder。第 一 個 是 src ( 指 source ),就 是 存 放 Arduino Library 的 地 方 ,亦 即 是 前 面 所 說 的 *.h 檔 和 *.cpp 檔 。另 一 個 是 js,是 存 放 javascript 碼 的 地 方 。
src 的 Arduino Library 是 在 Arduino Mode 時 用 的 ,而 js 內 的 javascript,則 是 Scratch Mode 時 使 用 的 。因 為 我 不 太 理 解 ( 也 覺 得 沒 有 需 要 ) Scratch Mode 的 運 作 方 式 ,所 以 我 不 打 算 花 時 間 去 寫 javascript 的 部 分 ,所 以 在 這 裡 下 載 的 mBlock extension 只 會 在 Arduino Mode 有 用 。
首 先 ,我 們 先 在 電 腦 上 建 立 一 個 「TM1637Display」的 folder,作 為 這 個 mBlock extension 的 根 目 錄 。然 後 我 們 建 立 一 個 「src」的 sub-folder,然 後 就 把 「TM1637Display.h」和 「TM1637Display.cpp」兩 個 檔 案 複 製 到 src 目 錄 裡 面 。
因 為 mBlock 和 Arduino IDE 的 引 用 方 式 不 同 ,所 以 我 們 要 對 這 個 library 作 出 一 點 點 的 小 改 變 。首 先 ,我 們 打 開 TM1637Display.cpp 檔 ,在 第 24 行 會 有 引 用 header 檔 ( *.h 檔 ) 的 一 句 。
1 |
#include <TM1637Display.h> |
我 們 要 把 它 改 成 下 面 的 樣 子 ,即 是 那 個 「單 書 名 號 」( < > ) 要 改 成 「雙 引 號 」( double quotes )。
1 |
#include "TM1637Display.h" |
如 果 沒 有 更 正 ,那 我 們 在 mBlock 按 下 Upload to Arduino 時 ,就 會 見 到 一 些 找 不 到 檔 案 之 類 的 錯 誤 。值 得 注 意 的 是 ,所 有 其 它 的 include 行 ,都 是 不 用 修 改 的 。只 有 在 引 用 src 目 錄 裡 面 的 檔 案 的 時 候 ,我 們 才 要 把 「書 名 號 」改 為 「雙 引 號 」。
改 好 之 後 就 保 存 檔 案 ,然 後 我 們 就 可 以 開 始 寫 那 個 s2e 檔 案 。
s2e 檔 亦 有 自 己 的 特 定 格 式 。整 個 s2e 檔 案 ,其 實 就 是 一 個 JSON object。裡 面 又 分 成 幾 個 部 分 ,首 先 是 basic information,就 是 基 本 資 料 ,例 如 名 稱 ,作 者 等 等 的 資 訊 。然 後 就 是 block definition,就 是 定 義 我 們 在 mBlock 裡 面 會 使 用 的 積 木 。然 後 就 是 menus,values 和 translators,這 3 項 我 們 後 面 再 講 。
首 先 我 們 在 extension 的 根 目 錄 建 立 一 個 叫 TM1637Display.s2e 的 純 文 字 檔 。然 後 按 照 mBlock 提 供 的 例 子 寫 好 了 我 們 的 基 本 資 料 。這 裡 面 最 重 要 的 是 extensionName,因 為 這 個 是 不 可 以 和 別 的 extension 相 同 的 ,所 以 要 改 得 有 技 巧 一 點 。我 自 己 的 習 慣 ,就 是 用 回 Arduino Library 的 名 字 。一 來 是 易 記 ,二 來 也 不 容 易 撞 名 ( 所 以 你 見 到 我 的 folder 名 和 檔 名 都 是 跟 library 名 的 ,在 此 例 中 就 是 「TM1637Display」)。
再 來 就 是 重 頭 戲 ,寫 block definition 了 。所 有 的 block 就 放 在 blockSpecs 裡 面 ,是 一 個 Array,Array 就 意 味 著 你 想 放 多 少 個 block 都 可 以 。那 究 竟 這 個 extension 我 們 需 要 多 少 個 積 木 呢 ?
在 TM1637Display 的 說 明 文 件 裡 ,我 們 知 道 這 個 library 有 4 個 方 法 給 我 們 去 用 ,但 其 實 我 們 不 一 定 需 要 把 library 的 所 有 方 法 都 改 寫 成 積 木 的 。例 如 我 就 覺 得 setSegments 沒 什 麼 用 ,而 我 的 display 也 沒 有 小 數 點 ,也 就 不 去 改 寫 showNumberDecEx 了 。( 這 些 留 給 讀 者 自 己 去 補 回 ,哈 哈 )
如 果 大 家 是 完 全 沒 有 寫 Arduino IDE 的 經 驗 ,可 能 會 覺 得 吃 力 一 點 。但 其 實 只 要 讀 一 次 header 檔 ( *.h 檔 ),所 有 的 functions 都 會 在 裡 面 的 了 。然 後 再 仔 細 看 一 下 library 裡 面 的 examples,應 該 都 可 以 了 解 到 發 生 了 什 麼 事 。
一 般 來 說 ,extension 的 第 一 個 積 木 ,大 都 是 初 始 化 那 個 extension,例 如 include library,initialize 個 class,設 定 使 用 的 針 腳 ,諸 如 此 類 的 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[ "w", "TM1637Display Initialize CLK pin %d.pin DIO pin %d.pin", "TM1637Display", "2", "3", { "setup":"display.setBrightness(2);\n", "inc":"#include \"TM1637Display.h\"\nTM1637Display display({0},{1});\n", "def":"", "work":"", "loop":"" } ], |
在 上 面 的 例 子 中 ,第 一 行 的 w,是 指 積 木 的 種 類 。w 是 指 write blocks,是 發 送 command 去 電 子 零 件 的 ,一 般 來 說 ,最 常 用 的 積 木 就 是 write blocks。r 則 是 reading blocks,是 由 電 子 零 件 讀 取 一 個 數 值 回 來 。b 是 binary blocks,它 跟 reading block 很 相 似 ,但 傳 回 的 只 是 true / false 的 值 。
第 二 行 就 是 定 義 積 木 的 文 字 和 輸 入 。例 如 %n 和 %d 是 輸 入 number,%s 和 %m 是 string。%n 和 %d 都 是 輸 入 數 字 ,它 們 的 分 別 在 於 %d 可 以 加 入 一 個 選 單 ,給 使 用 者 去 選 擇 。而 這 些 選 單 ,就 是 在 後 面 的 menus 部 分 去 定 義 。
1 |
TM1637Display Initialize CLK pin %d.pin DIO pin %d.pin |
例 如 我 在 menus 裡 面 定 義 了 一 個 叫 pin 的 menu,選 項 內 容 就 是 由 1 到 13。然 後 我 用 %d.pin 的 語 法 來 使 用 它 。
兩 者 加 在 一 起 ,就 會 造 出 下 面 這 個 樣 子 的 積 木 了 。
然 後 就 是 第 三 行 ,那 是 javascript function name,因 為 我 不 寫 javascript 的 部 分 ,所 以 我 都 是 隨 便 改 個 不 重 覆 的 名 字 就 算 了 。
第 四 行 和 第 五 行 ,是 輸 入 的 預 設 值 ( default values )。這 裡 大 家 要 非 常 小 心 ,因 為 我 這 個 積 木 是 兩 個 輸 入 ,所 以 必 須 是 寫 兩 行 ,兩 個 預 設 值 。如 果 你 的 積 木 只 有 一 個 輸 入 ,就 寫 一 行 ,兩 個 輸 入 就 寫 兩 行 ,三 個 輸 入 就 寫 三 行 ,如 此 類 推 。如 果 你 的 積 木 沒 有 輸 入 ,就 一 行 也 不 用 寫 。這 個 千 萬 不 要 出 錯 。
然 後 由 我 的 第 七 行 至 第 十 一 行 ,分 別 是 setup、inc、def、work 和 loop。是 分 別 定 義 把 程 式 碼 寫 到 Arduino Sketch 的 不 同 部 分 。inc 就 是 放 置 include 語 句 和 初 始 化 語 句 的 地 方 。def 就 是 定 義 變 數 和 常 數 的 地 方 。setup 就 是 程 式 開 始 時 會 執 行 一 次 的 地 方 ,有 時 會 把 一 些 設 定 放 在 這 裡 做 。work 就 是 正 常 放 置 這 個 積 木 相 關 巧 能 的 程 式 碼 的 地 方 。loop 反 而 我 很 少 用 到 。
1 |
TM1637Display(uint8_t pinClk, uint8_t pinDIO); |
再 回 到 上 面 的 例 子 ,因 為 是 初 始 化 的 積 木 ,所 以 只 有 inc 和 setup 才 有 內 容 。在 inc 裡 面 就 是 先 include 了 library,然 後 用 library 的 constructor 建 立 一 次 。在 初 始 化 的 時 候 ,我 們 要 用 到 CLK pin 和 DIO pin 的 號 碼 ,這 時 候 我 們 需 要 用 到 使 用 者 輸 入 。使 用 者 在 積 木 中 的 輸 入 ,會 變 成 一 組 特 殊 的 變 數 ,由 第 一 個 輸 入 開 始 ,分 別 會 變 成 {0},{1},{2},…. ,如 此 類 推 。只 要 把 它 們 替 代 到 相 關 的 地 方 使 可 以 了 。
1 |
TM1637Display display({0},{1});\n |
大 家 特 別 留 意 一 下 兩 個 特 殊 字 符 ,第 一 個 是 「\”」,要 在 內 容 中 使 用 「雙 引 號 」,「雙 引 號 」前 面 要 加 上 「\」。第 二 個 是 「\n」,這 是 代 表 new line ( 分 行 ) 的 意 思 。這 些 是 JSON 的 語 法 ,就 不 用 深 究 為 什 麼 了 。
1 |
display.setBrightness(2);\n |
而 在 setup 裡 面 ,我 順 手 在 程 式 開 始 時 把 顯 示 器 的 光 度 設 定 為 2。
我 的 第 二 個 積 木 ,就 是 set brightness 積 木 。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[ "w", "TM1637Display Set Brightness %d.brightness", "displayBrightness", "2", { "setup":"", "inc":"", "def":"", "work":"display.setBrightness({0});\n", "loop":"" } ], |
同 樣 是 w 類 的 積 木 ,但 今 次 只 有 一 個 輸 入 。輸 入 亦 在 menus section 做 了 一 個 menu,就 叫 birghtness,數 值 由 0 去 到 7。預 設 值 只 有 一 個 ,數 值 是 2。因 為 這 是 功 能 性 的 積 木 ,所 以 只 在 work 裡 面 有 內 容 。
最 後 就 是 Display 積 木 ,這 是 用 來 顯 示 數 字 到 顯 示 器 的 ,所 以 同 樣 是 w 積 木 。這 個 積 木 亦 只 有 一 個 輸 入 ,預 設 值 為 1234。這 個 積 木 亦 是 只 有 在 work 才 有 內 容 。
在 這 個 我 們 寫 的 第 一 個 Library,我 們 就 不 加 入 values 和 translators 了 。保 存 好 TM1637Display.s2e 檔 之 後 ,我 們 把 整 個 extension 的 folder ( TM1637Display ) 做 成 一 個 zip 檔 ( TM1637Display.zip )。這 個 zip 檔 就 是 你 的 extension 的 安 裝 檔 了 ,你 要 送 給 親 朋 好 友 用 ,又 或 者 想 要 發 佈 到 互 聯 網 ,都 是 發 一 個 zip 檔 出 去 就 行 。
mBlock extension 下 載 : TM1637Display.zip
要 在 mBlock 使 用 這 個 extension,只 要 在 mBlock 選 Extensions >> Manage Extensions。然 後 按 下 Add Extension,在 File name 後 面 的 檔 案 格 式 改 為 zip,再 選 取 上 面 的 TM1637Display.zip 檔 案 ,再 按 一 下 Open 就 完 成 了 。
完 成 之 後 ,你 就 可 以 見 到 自 己 的 extension 了 。關 上 對 話 閘 ,在 Arduino Mode,去 到 Robots 類 別 ,就 可 以 見 到 新 增 加 的 積 木 了 。
然 後 當 然 第 一 時 間 接 駁 好 顯 示 器 ,寫 個 小 程 式 ,測 試 一 下 各 個 新 積 木 的 功 能 。
如 果 一 切 正 常 ,你 應 該 可 以 見 到 顯 示 器 由 0000,1111,….,7777 這 般 循 環 顯 示 ,而 且 也 會 由 最 暗 ,一 直 增 加 到 最 光 。
這 個 TM1637Display library 雖 說 好 使 好 用 ,但 它 原 來 是 給 有 小 數 點 的 4 位 顯 示 器 用 的 ,和 我 的 4 位 時 間 顯 示 器 不 太 兼 容 。至 少 ,它 不 能 點 亮 那 個 時 間 的 冒 號 。其 實 很 多 電 子 零 件 的 Arduino library 都 不 只 得 一 套 ,大 家 其 實 可 以 多 看 幾 套 ,才 決 定 用 那 一 套 來 製 作 自 己 的 mBlock extension。
其 實 我 的 4 位 時 間 顯 示 器 真 正 的 library 是 下 面 這 個 ,但 要 把 它 改 成 mBlock extension 是 有 一 點 點 難 度 的 ,未 必 適 合 作 為 入 門 的 教 材 ,所 以 在 這 一 篇 我 們 就 暫 時 不 討 論 它 。
Grove – 4-Digit Display ( time display ) Library
接 下 來 我 們 看 看 如 何 實 作 一 個 1602 LCD 的 extension 吧 。
>> Next: 自 己 寫 個 mBlock extension (二 ) 1602 I2C LCD Module <<
延 伸 閱 讀 :
1. Writing a Library for Arduino ;
2. Create Extensions for mBlock ;
3. Getting Start with mBlock (PDF) ;
4. The Programing Structure of an Arduino Sketch ;
5. Arduino – Wire Library ( I2C ) ;
6. Arduino Playground – I2C Scanner ;
請問在前面的步驟中有個說有副檔名為s2e的部分還有src和js的資料夾應該去哪裡找到呢?我下載後用電腦搜尋也沒有找到這部分,在你的說明裡面有沒有找到能夠去哪裡找到這些檔案。希望可以了解這部分。
Well… 首先我得問問,究竟你下載了什麼?我這文的 link 也不少。
假如你是說我為 TM1637 寫的 mblock extension,那是一個 zip 檔,zip 檔裡面就有齊你所問的一切。
難道說,你不會打開 zip 檔??應該不會吧?