上 一 課 我 們 學 會 了 如 何 用 Arduino 來 控 制 single digit 的 seven-segment display,今 次 我 們 還 是 玩 seven-segment display,我 會 為 大 家 介 紹 兩 個 深 一 點 的 用 法 。
上 半 部 分 ,我 們 先 來 學 習 如 何 使 用 4 位 的 數 碼 管 吧 。下 圖 是 我 手 頭 上 的 4 位 共 陽 數 碼 管 3641BH,很 典 型 的 ,一 共 有 12 個 接 腳 ,pins 1 – 12。
下 面 是 它 的 接 線 圖 ,很 複 雜 是 不 是 ?
其 實 這 牽 涉 到 multiplex 這 一 個 概 念 。Multiplex 原 本 是 指 把 多 個 獨 立 的 訊 號 組 成 一 個 訊 號 去 傳 送 ,典 型 例 子 是 電 話 公 司 鋪 設 一 條 電 話 線 ,卻 可 以 同 時 接 通 多 個 不 同 的 通 話 。
數 碼 管 有 兩 種 的 顯 示 方 式 ,一 種 叫 作 static,另 一 種 就 叫 multiplexed。Static ( 靜 態 ) 的 數 位 管 可 以 同 時 顯 示 所 有 位 數 ,multiplexed 的 數 位 管 一 次 只 能 顯 示 一 位 數 。
一 位 的 數 碼 管 ,當 然 就 是 使 用 static 的 顯 示 方 式 。一 位 的 static 數 碼 管 要 使 用 9 個 pins 去 接 駁 ,而 一 個 4 位 的 static 數 碼 管 ,就 會 需 要 36 個 pins 了 。如 果 換 上 一 次 只 顯 示 一 個 位 的 方 式 呢 ?就 像 上 圖 顯 示 的 3641BH 接 線 圖 ,接 線 可 以 大 大 減 少 到 12 pins。3641BH 就 是 使 用 了 multiplexed 的 顯 示 方 式 了 。
Multiplexed 的 接 駁 方 法 ,可 以 大 大 減 少 針 腳 和 簡 化 電 路 ,所 以 亦 能 夠 降 低 成 本 ,所 以 今 時 今 日 ,除 了 single digit 的 數 碼 管 ,絕 大 部 分 多 位 數 的 數 碼 管 都 是 通 過 multiplexed 的 方 式 來 顯 示 的 。
但 係 「咪 住 先 ,我 有 問 題 !」,街 頭 上 大 把 多 位 數 數 碼 管 ,我 從 來 都 無 見 過 佢 地 只 能 顯 示 一 位 數 呀 ,通 通 都 可 以 「同 時 」顯 示 咁 多 個 位 呀 。原 因 其 實 好 簡 單 ,因 為 我 們 會 用 超 快 速 的 循 環 來 連 續 不 停 地 顯 示 各 個 位 的 數 字 ( 1、2、3、4、1、2、…. ),加 上 視 覺 暫 留 現 像 ,所 以 看 起 來 便 以 為 它 們 是 static 的 了 。
Multiplexed 的 顯 示 方 式 當 然 不 止 應 該 於 數 碼 管 ,其 實 ,所 有 點 陣 式 的 顯 示 屏 ( 電 視 機 、電 腦 monitor、…… ),全 部 都 是 multiplexed displays 來 的 ( 它 們 是 飛 快 地 每 次 顯 示 一 個 pixel )。
好 了 ,回 到 我 們 的 四 位 數 碼 管 ,究 竟 是 如 何 達 成 multiplexed 的 顯 示 方 式 的 呢 ?從 上 圖 中 可 以 見 到 ,四 個 位 的 A-G 和 DG,是 接 通 了 在 一 起 的 ,而 每 個 digit 都 有 自 己 的 共 陽 那 一 個 pin ( 12, 9, 8, 6 )。
假 設 我 要 顯 示 8,那 就 A-G 都 提 供 一 個 LOW 的 訊 號 ( 因 為 是 共 陽 ) ,如 果 要 顯 示 在 第 一 位 ,就 在 pin 12 提 供 一 個 5V 的 電 壓 。而 如 果 想 在 第 二 位 顯 示 ,就 在 pin 9 提 供 一 個 5V 的 電 壓 ,第 三 位 和 第 四 位 是 同 理 。
如 果 還 是 不 明 白 ,也 不 要 緊 ,我 們 實 作 出 來 ,一 面 寫 program 一 面 去 理 解 吧 。
四 位 數 碼 管 有 12 pins,其 中 的 pins 1, 2, 3, 4, 5, 7, 10, 11 是 控 制 A-G 和 DP 的 ,這 八 個 pins 我 們 分 別 接 到 Arduino UNO 的 pins 6 – 13 ( 其 中 DP 是 我 們 這 一 課 不 用 的 ,不 接 也 可 以 ),記 得 在 這 八 個 pins 每 一 個 pins 都 要 接 上 一 顆 current limiting resistor ( 300Ω )。數 碼 管 的 pins 6, 8, 9 12 分 別 是 控 制 digit 1 – 4 的 ,這 四 個 pins 我 們 分 別 接 到 Arduino UNO 的 pins 2-5。
最 後 ,我 們 再 接 一 個 push button 在 pin A5 ( 用 pull down resistor 的 方 法 ,10KΩ )。因 為 digital pin 0 和 1 是 留 給 serial port 傳 送 資 料 用 的 ,所 以 最 好 不 要 用 來 作 自 己 program 的 IO port。
4-Digit 7-segment Display [ Pin Number ] | 4 Digit 7-segment Display [ Segment ] | Arduino UNO [ Pin Number ] |
---|---|---|
11 | A | 11 |
7 | B | 13 |
4 | C | 7 |
2 | D | 9 |
1 | E | 10 |
10 | F | 12 |
5 | G | 6 |
3 | DP | 8 |
12 | Digit 1 ( Anode ) | 2 |
9 | Digit 2 ( Anode ) | 3 |
8 | Digit 3 ( Anode ) | 4 |
6 | Digit 4 ( Anode ) | 5 |
連 接 好 電 路 之 後 ,回 到 mBlock 寫 我 們 的 程 序 吧 。首 先 ,我 們 試 試 點 亮 數 碼 管 上 所 有 的 LED 吧 ,因 為 是 共 陽 的 數 碼 管 ,所 以 數 碼 管 的 pins 6, 8, 9, 12 要 HIGH ( 亦 即 Arduino UNO 的 pins 2, 3, 4, 5 ),其 他 的 pins 就 要 LOW。
超 簡 單 的 吧 ?肯 定 沒 問 題 。然 後 我 們 顯 示 4 個 5 字 吧 ,只 要 把 A 和 E 關 上 ,亦 即 是 把 Arduino UNO 的 pins 10 和 13 設 成 HIGH ( 可 快 速 地 參 考 上 面 的 針 腳 對 應 表 )。還 有 ,DP 我 們 也 是 不 要 的 ( UNO 的 pin 8 )。
好 了 ,如 果 只 想 顯 示 第 1 個 位 呢 ?很 簡 單 ,把 數 碼 管 上 的 pins 6, 8, 9 ( 即 Arduino 的 3, 4, 5 ) 都 設 定 成 LOW 吧 。
如 果 想 要 顯 示 在 第 二 位 ,那 只 要 把 相 應 的 digit pins 設 定 成 HIGH 即 可 。好 吧 ,根 據 上 面 的 實 踐 ,我 們 試 試 在 1 – 4 位 ,每 次 1 秒 ,輪 流 顯 示 1, 2, 3, 4 吧 。
我 們 可 以 增 加 一 個 Make a Block,叫 做 displayNumber,使 用 了 兩 個 數 字 參 數 ,第 一 個 參 數 是 digit,即 係 顯 示 在 第 幾 位 ,第 二 個 參 數 就 是 要 顯 示 的 數 字 。例 如 displayNumber(2,5),即 是 在 第 二 位 顯 示 數 字 5。
我 另 外 增 加 了 兩 個 Make a Block,一 個 叫 setDigitPin,一 個 叫 setNumberPin。setNumberPin 其 實 就 很 類 似 第 六 課 的 displayNumber,只 是 因 應 4 digit 7-segment display 的 針 腳 而 作 出 了 調 整 。而 setDigitPin 就 是 設 定 顯 示 在 那 一 個 位 。
我 增 了 一 個 variable 叫 waitTime,就 是 等 多 久 才 顯 示 下 一 位 數 字 ,程 序 開 始 時 把 waitTime 設 定 為 1 。
完 成 後 按 Upload to Arduino,應 該 可 以 看 到 1, 2, 3, 4 在 循 環 顯 示 吧 。好 了 ,假 如 我 們 現 在 把 waitTime 設 定 為 0.1,會 出 玩 怎 麼 的 情 形 呢 ?應 該 會 先 到 1, 2, 3, 4 的 循 環 快 了 很 多 吧 ?大 家 可 以 自 己 去 設 定 不 同 的 值 ,看 看 會 出 現 什 麼 效 果 。
如 果 把 waitTime 設 定 成 飛 快 ,例 如 0.005,你 就 會 看 到 一 個 頗 為 穩 定 的 1234 了 。
之 前 就 說 過 ,wait block 不 是 好 東 西 ,那 我 們 索 性 移 除 wait block 吧 。順 道 把 要 顯 示 的 4 位 數 ( 1234 ) 變 成 一 個 變 數 ,方 便 以 後 操 作 。
首 先 我 把 要 顯 示 的 數 變 成 一 個 variable counter,並 在 一 開 始 把 counter 設 為 1234。然 後 我 增 加 了 兩 個 變 數 currentDigit 和 currentNumber,作 為 displayNumber 的 輸 入 參 數 。currentNumber 是 用 一 個 新 的 Make a Block – getCurrentNumber 計 算 出 來 。
例 如 getCurrentNumber(1, 1234),那 currentNumber 就 會 是 1,如 果 getCurrentNumber(3, 1234),那 currentNumber 就 會 是 3,如 此 類 推 。getCurrentNumber 還 有 另 外 一 個 用 處 ,就 是 對 較 短 的 數 值 補 零 ,例 如 getCurrentNumber(1, 123) 會 得 出 0,所 以 123 就 會 顯 示 為 0123。
好 了 ,現 在 upload 到 Arduino 看 看 結 果 如 何 ?雖 然 勉 強 見 得 到 1234,但 是 鬼 影 應 該 很 嚴 重 吧 ?這 是 因 為 我 們 移 除 了 wait block,而 我 們 每 一 個 set digital pin 指 令 並 不 是 同 時 執 行 的 。要 移 除 鬼 影 ,只 要 我 們 在 每 一 次 顯 示 之 間 ,熄 滅 所 有 LED 一 次 就 可 以 了 。
我 們 在 setDigitPin 和 setNumberPin,兩 者 都 加 上 例 外 的 狀 況 ( 就 是 setDigitPin 唔 係 1-4, setNumberPin 唔 係 0-9),將 四 位 數 碼 管 上 的 digit pins ( 陽 極 ) 設 定 為 LOW,並 且 將 所 有 number pins ( A-G ) 設 定 為 HIGH。這 樣 ,整 個 數 碼 管 都 不 會 顯 示 任 何 野 。
要 使 用 這 個 「全 黑 」設 定 ,只 要 執 行 displayNumber(5,10) 這 句 程 式 就 可 以 了 ( 唔 一 定 要 5 和 10,6 和 27 亦 可 以 的 ,只 要 唔 係 1-4 和 0-9 就 得 )。改 好 之 後 ,數 碼 管 應 該 沒 有 鬼 影 了 吧 ?不 過 ,用 這 個 方 法 去 除 鬼 影 ,會 令 數 碼 管 有 一 個 短 時 間 無 顯 示 任 何 野 ,所 以 ,整 體 的 光 度 是 會 暗 了 一 點 的 。
終 於 能 夠 正 確 地 用 4 位 數 碼 管 來 顯 示 數 值 ,那 我 們 就 加 點 變 化 ,將 它 變 為 每 秒 自 動 加 1 的 計 時 器 吧 。
我 們 用 timer 來 計 時 ,每 1 秒 就 將 counter 加 1。如 果 counter 大 於 9999,就 reset 去 0。因 為 我 們 之 前 就 寫 好 了 顯 示 counter 的 程 序 ,所 以 顯 示 的 部 分 是 完 全 唔 駛 改 任 何 野 的 ,爽 吧 ?
現 在 再 把 程 序 改 為 使 用 push button 來 加 1,將 它 變 成 一 個 4 位 數 的 counter ( 計 數 器 )。把 push button 接 在 Analog IN,在 程 式 上 會 有 少 許 分 別 。首 先 ,我 們 要 改 用 另 一 個 read analog pin (A) 的 block。另 外 ,它 讀 出 來 的 值 亦 不 會 是 True / False,而 會 是 由 0 – 1023 總 共 1024 級 的 數 值 。
當 把 analog input pin 當 成 digital input pin 使 用 時 ,按 照 pull down resistor 的 接 法 ,如 果 沒 按 鍵 時 ,讀 出 來 的 數 值 是 0,而 按 下 鍵 時 ,所 讀 出 來 的 值 是 1023。所 以 檢 查 現 在 是 按 鍵 的 語 法 可 以 是 buttonState = 1023 又 或 者 buttonState > 0,兩 者 都 得 。
檔 案 下 載 : lesson07_counter.zip
Multiplex 可 以 為 我 們 省 下 大 量 針 腳 ( 4位 7-segment display 就 是 由 36 針 腳 減 少 到 12 針 腳 ),但 區 區 一 個 小 小 的 4 位 數 碼 管 ,就 用 盡 了 我 們 Arduino 上 面 的 所 有 digital pins,那 很 多 其 他 零 件 都 不 用 接 了 ,還 怎 麼 去 研 發 不 同 的 產 品 呢 ?
其 實 我 們 還 有 另 一 個 方 法 可 以 減 少 針 腳 的 使 用 的 ,那 就 是 使 用 shift register ( 移 位 暫 存 器 )。Shift register 有 好 多 好 多 種 ,74HC595 就 是 一 種 非 常 常 見 的 shift register,很 多 數 碼 管 的 電 路 亦 會 見 到 它 。74HC595 究 竟 是 什 麼 來 的 呢 ?Datasheet 上 面 的 description 一 般 會 是 8-bit serial-in, parallel-out shift regiester with 3 state。簡 單 點 說 ,它 就 是 可 以 把 串 行 輸 入 ( serial in ) 的 資 料 ,並 行 輸 出 ( parallel out ),而 它 一 次 過 可 以 處 理 8-bit 的 資 料 ( 每 一 個 bit 即 是 0 或 1 )。
從 74HC595 的 針 腳 圖 表 ,DS ( pin 14 ) 是 串 行 資 料 輸 入 ( serial data input ),而 Q0 – Q7 ( pins 1-7, pin 15,共 八 個 pins ) 則 是 並 行 輸 出 ( parallel data output )。可 想 而 知 ,我 們 只 需 要 用 1 個 pin 來 輸 入 8 個 bit 的 data ( 例 如 11001100 ),它 就 會 把 資 料 分 開 而 並 行 地 輸 出 到 8 個 output pins。
74HC595 的 8 個 output pins,正 好 可 以 對 應 1 位 數 碼 管 的 8 個 輸 入 ( A-G, DP ),所 以 ,假 如 我 們 先 把 數 碼 管 接 在 shift register 上 ,然 後 才 接 到 Arduino,就 可 以 省 回 很 多 IO pins 了 。
首 先 ,我 們 把 一 個 共 陽 1 位 數 碼 管 接 駁 到 74HC595。接 駁 的 方 法 是 ,把 數 碼 管 的 A 接 到 74HC595 的 Q1,把 B 接 到 Q2,把 C 接 到 Q3,把 D 接 到 Q4,把 E 接 到 Q5,把 F 接 到 Q6,把 G 接 到 Q7,最 後 把 DP 接 到 Q0。別 忘 記 了 ,要 給 數 碼 管 供 電 ,把 pins 3 或 者 8,接 到 5V。
如 果 把 我 的 發 送 的 8 個 bit 的 次 序 寫 成 0 – 7,我 們 輸 入 的 第 0 bit ( 亦 即 是 第 1 個 bit ) 會 在 Q0 輸 出 ,第 1 bit 在 Q1,…,第 7 bit 則 在 Q7。當 然 ,這 8 個 pin 你 是 可 以 隨 便 打 亂 來 接 的 ,但 如 果 按 順 序 來 接 ,之 後 在 程 序 裡 編 碼 會 直 觀 一 點 。
至 於 74HC595 餘 下 的 pins,Vcc ( Pin 16, 供 電 ) 就 接 5V,GND ( Pin 8 ) 就 接 地 。MR 是 reset,當 把 它 設 定 為 LOW 時 ,可 以 把 74HC595 的 資 料 歸 零 。OE 就 output enable,如 果 HIGH 就 不 輸 出 ,LOW 就 輸 出 ,控 制 它 可 以 產 生 閃 爍 等 效 果 。為 了 簡 單 一 點 ,我 們 把 MR ( Pin 10 ) 接 到 5V ( 長 期 為 HIGH ), OE ( Pin 13 ) 則 接 GND ( 長 期 為 LOW )。
然 後 ,我 們 把 74HC595 的 DS ( data pin, Pin 14 ) 接 到 Arduino UNO 的 Pin 8,ST_CP ( latch pin, Pin 12 ) 接 到 Pin 9,SH_CP ( clock pin, pin 11 ) 接 到 pin 10。Data pin 是 用 來 傳 data 的 ,clock pin 就 是 告 訴 74HC595 把 資 料 移 動 一 個 位 ( Q0->Q1, Q1->Q2, …. ),而 latch pin 就 是 告 訴 74HC595 把 輸 入 的 資 料 儲 存 到 內 部 的 storage。
74HC595 ( Shift Register ) [ Pin ] | 7-segment Display [ Segment / Pin Number ] | Arduino UNO [ Pin Number ] |
---|---|---|
Q1 ( output, Pin 1 ) | A [ Pin 7 ] | --- |
Q2 ( output, Pin 2 ) | B [ Pin 6 ] | --- |
Q3 ( output, Pin 3 ) | C [ Pin 4 ] | --- |
Q4 ( output, Pin 4 ) | D [ Pin 2 ] | --- |
Q5 ( output, Pin 5 ) | E [ Pin 1 ] | --- |
Q6 ( output, Pin 6 ) | F [ Pin 9 ] | --- |
Q7 ( output, Pin 7 ) | G [ Pin 10 ] | --- |
Q0 ( output, Pin 15 ) | DP [ Pin 5 ] | --- |
Vcc ( Power Supply, Pin 16 ) | --- | 5V |
GND ( Ground, Pin 8 ) | --- | GND |
MR ( reset, Pin 10 ) | --- | 5V |
OE ( output enable, Pin 13 ) | --- | GND |
DS ( data pin, Pin 14 ) | --- | Pin 8 |
ST_CP ( latch pin, Pin 12 ) | --- | Pin 9 |
SH_CP ( clock pin, Pin 11 ) | --- | Pin 10 |
--- | Common Anode [ Pins 3, 8 ] | 5V |
最 後 ,我 們 把 兩 個 push button 接 到 Arduino UNO 的 pin 2 和 pin 3。
建 立 好 電 路 後 ,回 到 mBlock,我 們 先 試 試 最 簡 單 的 循 環 顯 示 數 字 吧 。74HC595 一 個 簡 單 的 工 作 周 期 如 下 ( 8 個 bit 按 bit 0 至 bit 7 去 計 ):
latch pin – LOW ( 開 始 輸 入 資 料 )
data pin – 輸 出 第 7 bit 資 料 ( HIGH = 1 / LOW = 0 )
clock pin – HIGH ( 把 輸 入 的 資 料 移 到 Q0 )
clock pin – LOW
data pin – 輸 出 第 6 bit 資 料 ( HIGH = 1 / LOW = 0 )
clock pin – HIGH ( 把 剛 輸 入 的 資 料 移 到 Q0, 之 前 的 Q0 移 到 Q1 )
clock pin – LOW
……
……
data pin – 輸 出 第 0 bit 資 料 ( HIGH = 1 / LOW = 0 )
clock pin – HIGH ( 把 剛 輸 入 的 資 料 移 到 Q0, 之 前 的 Q0 移 到 Q1, ….., 之 前 的 Q6 移 到 Q7 )
clock pin – LOW
latch pin – HIGH ( 已 完 成 輸 入 全 部 8-bit 資 料 ,保 存 資 料 並 把 它 輸 出 )
例 如 是 數 字 1 的 話 ,總 共 要 輸 出 的 8 個 bit 就 應 該 是 00110000。第 0 個 bit 就 是 DP,然 後 bit 1-7 就 對 應 A – G。要 記 得 74HC595 是 由 第 7 bit ( Q7 ) 開 始 傳 送 ,一 直 倒 數 至 第 0 bit ( Q0 ) 的 。變 成 Scratch 程 序 就 會 像 下 面 的 樣 子 。
我 們 設 定 了 sendBit 來 傳 送 每 一 個 bit ( 要 記 得 因 為 我 用 的 是 共 陽 數 碼 管 ,所 以 要 LOW 才 會 發 亮 ,所 以 1 = LOW ),然 後 用 displayNumber 來 一 次 過 發 送 8 個 bit,要 記 得 相 反 次 序 。
如 果 能 成 功 顯 示 ,我 們 就 可 以 加 點 小 變 化 ,用 我 們 的 push button 去 再 做 一 個 counter 吧 。
檔 案 下 載 : lesson07_counter02.zip
好 了 ,上 完 這 一 課 ,係 唔 係 頭 都 大 晒 呢 ?所 以 ,我 就 唔 比 功 課 大 家 了 ,哈 哈 哈 。如 果 這 一 課 對 你 來 說 太 難 ,其 實 唔 一 定 要 實 作 出 來 的 。這 一 課 的 重 點 是 ,如 何 節 省 針 腳 。在 硬 件 開 發 上 ,針 腳 是 非 常 珍 貴 的 資 源 ,不 可 能 隨 便 插 個 4 位 display 就 用 去 全 部 針 腳 的 。所 以 大 家 可 以 用 multiplexed display 和 增 加 shift register 這 兩 個 方 法 去 減 少 針 腳 ,那 這 兩 者 可 不 可 以 一 齊 用 呢 ?當 然 是 可 以 的 ,下 一 堂 再 講 。