在 第 三 課 ,我 們 學 了 Push button 的 其 中 一 種 用 法 ,就 是 按 下 作 為 一 個 狀 態 ,放 手 作 為 另 一 個 狀 態 。但 其 實 在 現 實 生 活 中 ,在 很 多 情 況 ,push button 都 不 是 這 麼 用 的 。試 想 像 一 下 mouse click,又 或 者 keyboard 的 keypress,都 是 按 一 下 算 一 下 的 ,並 不 需 要 長 按 著 那 個 push button 的 。
首 先 ,我 們 用 回 上 一 課 的 電 路 ,整 個 系 統 只 有 一 個 push button 和 一 個 LED。
程 式 要 能 夠 知 道 我 們 按 了 幾 次 的 鍵 ( 例 如 打 了 3 個 A 字 ,又 或 者 mouse 的 single click / double click ),就 需 要 有 一 個 變 數 來 記 錄 按 鍵 的 狀 態 。我 們 新 增 一 個 變 數 buttonState,用 來 記 錄 這 一 次 的 按 鍵 狀 態 。另 外 新 增 一 個 變 數 lastButtonState,用 來 記 錄 上 一 個 狀 態 。
在 無 限 循 環 裡 面 ,每 個 循 環 開 始 我 們 都 檢 查 現 在 的 buttonState 是 什 麼 ( 是 True 還 是 False,即 是 按 下 定 放 開 )。在 每 個 循 環 結 束 ,我 們 都 把 現 在 的 buttonState 轉 給 lastButtonState。
這 次 我 們 只 希 望 在 按 鍵 狀 態 出 現 變 化 時 才 做 野 ,所 以 if block 的 比 對 條 件 就 是 not ( buttonState = lastButtonState )。
好 了 ,我 們 先 把 program upload 去 Arduino,看 看 結 果 如 何 。當 你 按 下 push button 時 ,LED 會 閃 一 下 ,而 當 你 放 開 push button 時 ,LED 會 閃 另 一 下 。而 無 論 你 按 多 久 ( 長 按 ),LED 都 只 會 閃 一 下 的 ,因 為 push button 的 狀 態 只 改 變 了 一 次 。
用 專 業 一 點 的 說 法 ,就 是 你 已 經 用 程 式 捕 捉 到 那 個 push button 的 keyDown event 和 keyUp event 了 。
但 這 好 像 依 然 沒 有 什 麼 實 際 用 途 。好 ,我 們 可 以 再 加 一 個 ledState 的 變 數 ,去 記 錄 LED 的 狀 態 。
在 上 圖 的 第 二 例 中 ,當 button 的 狀 態 改 變 的 時 候 ,我 們 會 檢 查 buttonState 是 0 還 是 1,如 果 是 1 ( = True ),即 時 button 是 按 下 的 ,亦 即 是 keyDown event 發 生 了 。這 時 候 ,我 們 就 會 去 改 變 LED 的 state ( 亮 著 ,還 是 熄 滅 )。
我 們 再 把 program upload 到 Arduino UNO。這 一 次 ,我 們 按 一 次 按 鈕 ,LED 就 會 亮 著 ,再 按 一 次 ,LED 就 會 熄 滅 。這 就 跟 市 面 上 一 般 的 輕 觸 式 開 關 一 樣 了 ,按 一 次 ON,再 按 一 次 就 OFF。
第 二 例 中 也 運 用 了 一 個 小 技 巧 ,在 每 次 扭 鍵 狀 態 轉 變 之 後 ,我 們 都 會 延 遲 0.1 秒 。很 多 時 候 ,物 理 按 鈕 在 按 下 時 都 會 產 生 一 些 抖 動 ,做 成 錯 誤 的 輸 出 ,例 如 你 按 下 一 次 ,但 按 鈕 又 自 己 彈 跳 了 一 次 ,做 成 兩 次 輸 出 。這 情 況 在 英 文 叫 bouncing。我 們 在 每 一 個 讀 取 循 環 最 後 加 入 一 個 wati 0.1 secs block,令 到 程 序 不 會 過 快 地 讀 取 下 一 個 buttonState,這 樣 就 可 以 有 效 減 少 bouncing。這 樣 的 編 程 技 巧 就 叫 做 debouncing。
不 過 wait block 並 不 是 好 東 西 ,會 令 整 個 程 序 停 頓 ,不 能 輸 入 輸 出 ,做 不 了 任 何 事 。所 以 ,雖 然 是 麻 煩 一 點 ,還 是 應 該 養 成 使 用 timer block 而 不 用 wait block 的 良 好 習 慣 。經 改 良 後 的 程 式 如 下 。
用 timer 而 不 用 wait 的 最 大 分 別 ,就 是 雖 然 兩 者 都 是 等 待 了 0.1 秒 ,但 timer 並 不 會 鎖 死 程 序 ,最 外 面 那 個 循 環 ,還 是 一 路 在 執 行 的 。
到 了 第 四 課 ,大 家 應 該 都 熱 好 身 的 了 。上 半 堂 講 了 輸 入 的 技 巧 ,下 半 堂 就 再 多 講 一 個 輸 出 的 技 巧 吧 。
電 腦 是 digital 的 世 界 ,什 麼 都 是 0 與 1,所 有 的 analog 輸 出 ,其 實 都 只 要 模 擬 出 來 的 。那 我 們 又 如 何 用 Arduino 來 模 擬 analog 輸 出 呢 ?
記 得 在 第 二 課 ,我 們 學 了 set digital pin 9 output as HIGH 這 個 block,它 只 能 選 擇 HIGH 或 者 LOW 兩 個 輸 出 ,所 以 很 明 顯 這 只 能 是 digital 的 輸 出 。但 是 ,在 mBlock 裡 面 ,還 有 另 一 個 output 的 block 的 。
另 一 個 output block 就 是 set pwm pin 5 output as 0。這 個 block 的 重 點 在 PWM,究 竟 什 麼 是 PWM 呢 ?它 的 全 名 是 Pulse Width Modulation。
PWM 是 一 種 用 digital output 去 模 擬 analog output 的 方 法 ,它 的 做 法 是 將 output 分 成 很 多 個 好 短 好 短 的 cycle,然 後 在 cycle 裡 面 ,按 照 要 輸 出 的 power 的 百 分 比 去 決 定 輸 出 多 少 時 間 。例 如 如 果 要 輸 出 百 分 之 五 十 的 power,就 只 在 50% 時 間 做 輸 出 ,其 餘 時 間 就 不 輸 出 。
如 果 你 把 輸 出 想 像 成 LED,如 果 輸 出 是 50%,那 就 是 有 一 半 時 間 LED 是 亮 的 ,有 一 半 時 間 LED 是 熄 的 。但 因 為 那 個 cycle 是 超 級 短 的 ,所 以 你 不 會 看 到 LED 閃 爍 ,因 為 有 些 時 間 它 是 不 亮 的 ,所 以 你 會 覺 得 它 暗 淡 了 。
mBlock 的 PWM block 的 輸 出 由 0 – 255,一 共 分 作 256 級 。pwm pin 輸 出 0 的 話 ,就 跟 digital pin 是 LOW 一 樣 。如 果 pwm pin 輸 出 255,那 就 和 digital pin 輸 出 HIGH 是 一 樣 的 。
不 過 ,並 不 是 所 有 digital pin 都 可 以 設 定 為 pwm pin 的 。根 據 Arduino 的 documentation,在 Arduino UNO 上 面 ,PWM 只 能 在 pins 3, 5, 6, 9, 10 和 11 上 面 啟 用 。
好 了 ,說 了 這 麼 多 ,現 在 試 試 實 際 操 作 吧 。還 是 用 回 上 面 一 顆 LED 和 一 個 push button 的 電 路 ,不 過 ,因 為 pin 13 並 不 支 援 PWM,所 以 ,請 把 LED 改 接 到 pin 11,而 程 式 則 作 出 如 下 修 改 。
Upload 到 Arduino 之 後 ,當 你 每 按 一 下 push button,變 數 ledState 都 會 加 1。如 果 ledState 大 於 4,則 會 自 動 歸 0。然 後 ,我 們 自 定 的 CHANGE_LED_STATE block,就 會 根 據 ledState 去 改 變 LED 的 亮 度 ,由 0, 31, 63, 127, 255,周 而 復 始 。
( 功 課 :1. 試 試 新 增 一 個 buttonCount 變 數 ,從 而 令 到 每 按 三 次 按 鈕 ,LED 的 亮 度 才 會 產 生 一 次 變 化 。2. 試 試 用 算 式 簡 化 CHANGE_LED_STATE block,例 如 output = 2^(ledState+4) – 1。 )