arduino 官網 arduino uno

Arduino 物聯網應用 - 上課教材

動畫互動網頁程式設計 > 課程內容 > 第 03 章 - 控制發光二極體

第 03 章 - 控制發光二極體

上次更新日期 2022/09/23

大致上了解了一些 arduino 的程式碼,接下來就是要動作將一些物聯網經常會用到的元件連結到 arduino 上面了! 我們首先來玩一下發光二極體,其實,就是簡單的 LED 小小燈光~透過多個燈光的連結,理解到如何以程式碼, 簡單的控制小元件的動作吧!

學習目標:

  1. 了解發光二極體與 arduino 的電力輸出關係
  2. 了解 digitalWrite 與 analogWrite 的差異
  3. 使用按鈕進行 LED 的互動測試

3.1: 發光二極體與 arduino 腳位關係

發光二極體 (Light Emitter Diode, LED) 是經常用在各種展示的小燈光工具,用在我們 arduino 學習上面的 LED, 則是一個小燈光連接兩條腳位的小元件,兩隻腳有長有短,長的需要輸入正電而短的則是負極~一般來說, 要讓這種 LED 發亮,大致需要 1.5 ~ 2.0V 之間的電壓,而亮度則與電流量有關。當電流太大,將可能導致 LED 的燒毀! 而電流太小,又會讓 LED 太黯淡...那 LED 到底會不會燒毀呢?根據強者我同事蔡董的說明,arduino 其實無法輸出太大的電量, 所以,基本上,不太需要擔心 LED 燒毀的問題~但是...一般正常的接法,我們還是需要使用電阻來處理比較妥當!

  • arduino 的腳位

再次仔細看下 arduino nano 的針腳,你會發現到上面有 D0~D13 的號碼,也有 A1 到 A7 的號碼,分別是使用數位、類比傳輸訊號的針腳功能。 再看下去,你也會發現有 3.3V 及 5V 的電量,同時也有接地 (GND) 的針腳。如果你想要讓某個元件一直供電,而且也不要限制其供電能力, 那就將正極接到 5V (或 3.3V) 上面,然後將負極接到接地 (GND) 上面即可。不過要特別注意, 5V, 3.3V 的針腳會輸出到 100mA 的電流, 跟一般 D0~D13 只提供 40mA 不太一樣!所以,有些元件一定要接電阻喔!

例題 3.1.1:測試連接
  1. 取得需要的物件:
    • 從百寶袋拿出 LED,並且觀察長、短腳
    • 從百寶袋拿出麵包版,小麵包板通常 5 孔一組,請進行觀察。
    • 從百寶袋拿出一個電阻器
    • 從百寶袋拿出一公一母杜邦線
  2. 開始進行連線:
    • 注意:麵包板上,每一組 5 孔當中,每組最多只能有 2 孔使用!
    • 連線方式:arduino 5V -- 電阻器 -- LED 正極
    • 連線方式:arduino GND -- LED 負極
  3. 將 arduino 安插到電腦上,看看 LED 會不會亮燈即可!亮燈之後,就可以拔除 arduino 了!

3.2: 使用 pinMode 與 digitalWrite 控制供電與停電

以我們的使用情況來說,想要讓 LED 燈在某些時刻亮、某些時刻暗,使用剛剛的持續供電就不太適合! 這時,可以透過 D0~D13 來提供電力喔!不過要注意的是,D0~D13 是提供電力輸出 (OUTPUT) 還是電力輸入 (INPUT), 這就得要事先做好設定!這時,就得要使用 pinMode 了!

  • pinMode(第幾腳位, 輸入還是輸出)

使用 pinMode 時,內部有兩個參數,第一個參數是第幾個腳位,例如,我們要使用 D5 腳位時,那這裡就是寫 5 這個數值。 而輸入還是輸出等,就有底下的幾個常見設定:

  • INPUT:高阻抗 (high-impedance) 輸入模式
  • INPUT_PULLUP:內含上升電阻的輸入模式
  • OUTPUT:輸出模式
pinMode(5, OUTPUT)     // 設定 D5 為輸出模式
pinMode(7, INPUT)      // 設定 D7 為高阻抗輸入模式
  • 使用 digitalWrite(第幾腳位, 高電壓/底電壓)

指定了腳位的輸出/輸入模式之後,那麼如何控制該腳位的電位呢?基本上,就是使用 digitalWrite 去提供高電壓 (HIGH) 或低電壓 (LOW) 。如果以 pinMode(5, OUTPUT) 為例,如果第 5 腳位要供電,則使用 digitalWrite(5, HIGH), 如果不要供電 (停電) 時,就改寫成 LOW 即可!

例題 3.2.1:設計一個閃爍的 LED 燈
  1. 先設計硬體連接方式:
    • 注意:麵包板上,每一組 5 孔當中,每組最多只能有 2 孔使用!
    • arduino D5 -- 電阻器 -- LED 正極
    • arduino 接地 -- LED 負極
  2. arduino IDE 程式設計 (code-led-1)
    • 設計名為 led 的全域變數,設計為整數 5
    • 在 setup() 當中,使用 pinMode 設計 led 變數為 OUTPUT 模式
    • 在 loop() 當中:
      • 預設使用 digitalWrite 設計 led 變數為 HIGH
      • 延遲大約 1 秒鐘
      • 預設使用 digitalWrite 設計 led 變數為 LOW
      • 延遲大約 1 秒鐘
  3. 將 arduino 安插到主機 USB 插槽,並將 code-led-1 燒錄並上傳

上面就是個簡單的單顆 LED 處理方案~現在,讓我們來玩一下,如果有 4 顆以上的 LED 燈,要怎麼處理!?

例題 3.2.2:連續閃爍的四個 LED 燈光
  1. 先設計硬體連接方式:
    • arduino D5 -- 電阻器 -- LED1 正極
    • arduino D6 -- 電阻器 -- LED2 正極
    • arduino D7 -- 電阻器 -- LED3 正極
    • arduino D8 -- 電阻器 -- LED4 正極
    • LED1 負極與 LED2 負極連接到同一組,該組連接到 arduino 接地-1
    • LED3 負極與 LED4 負極連接到同一組,該組連接到 arduino 接地-2
  2. arduino IDE 程式設計 (code-led-2)
    • 設計名為 led 的全域變數,設計為整數陣列,值為 5, 6, 7, 8
    • 設計名為 i 的整數全域變數
    • 設計名為 j 的整數全域變數,且初始值為 0
    • 在 setup() 當中,使用 for 迴圈,讓 led 陣列所代表的 pinMode 全部都使用 OUTPUT 模式
    • 在 loop() 當中:
      • 先使用 for 迴圈,讓所有的 led 陣列全部的供電為 LOW
      • 使用 digitalWrite 設計 led[j] 變數為 HIGH
      • 讓 j +1
      • 若 j 大於等於 4 時,則設定 j 為 0
      • 延遲大約 1 秒鐘
  3. 將 arduino 安插到主機 USB 插槽,並將 code-led-2 燒錄並上傳

這個是很簡單的燈號持續移動方式。現在,做個小作業:

例題 3.2.3:延續剛剛上一題的方式,只是將 LED 燈光預設為全亮,每次只有一個燈暗的情境!檔名取為 code-led-3 來處理!

現在,讓我們來玩另一個簡單的 LED 移動~讓亮燈先朝東,到底了再朝西,這樣來回變化~這就是所謂的霹靂燈啊~ 連線的方法跟上面的一模一樣,只是,我們要想到的是,陣列是 led[0] 到 led[3],我們用的是 led[j] 來表示。 當朝東時,若 j 到達 3 之後,就要變成減號~那如果是朝西時, j 到達 0 就要變成加號!所以要加判斷式! 同時,加上一個名為 dir 的變數 (direction, 方向),這樣才能知道是朝東還是朝西!

例題 3.2.4:LED 霹靂燈的處理方式
  1. arduino IDE 程式設計 (code-led-4)
    • 設計名為 led 的全域變數,設計為整數陣列,值為 5, 6, 7, 8
    • 設計名為 i 的整數全域變數
    • 設計名為 j 的整數全域變數,且初始值為 0
    • 設計名為 dir 的整數全域變數,初始值為 0
    • 在 setup() 當中,使用 for 迴圈,讓 led 陣列所代表的 pinMode 全部都使用 OUTPUT 模式
    • 在 loop() 當中:
      • 先使用 for 迴圈,讓所有的 led 陣列全部的供電為 LOW
      • 使用 digitalWrite 設計 led[j] 變數為 HIGH
      • 判斷 dir 是 0 才進行
        • 判斷 j 大於等於 3 ,就進行 j--,且將 dir 變成 1
        • 否則就 j++ 即可
      • 當 dir 不是 0 才進行
        • 判斷 j 小於等於 0 ,就進行 j++,且將 dir 變成 0
        • 否則就 j-- 即可
      • 延遲大約 0.2 秒鐘
  2. 將 arduino 安插到主機 USB 插槽,並將 code-led-4 燒錄並上傳

3.3: 使用 analogWrite 控制電量大小

基本上,arduino 的腳位中,僅有 D3, D5, D6, D9, D10, D11 這幾個腳位可以提供可調整式電力輸出的方式, 其他的數位針腳都僅有 HIGH 與 LOW (全供電或全不供電) 的情況而已,因此,底下要進行的實做,務必留意腳位號碼。

  • 使用 analogWrite(腳位, 供電數值) 進行供電量變化

使用 digitalWrite 只能提供全部的電量或全部斷電,如果想要可調整的數據,就得要使用 analogWrite 這個函數了。 這個函數的第二個數值,可以從 0~255,0 是最小輸出,255 是最大輸出!所以,你要變化的時候, 數字要在 0 到 255 之間變化。基本上,你就想成 0 是 LOW 而 255 是 HIGH,其他的數值就是在 LOW 與 HIGH 之間而已。

例題 3.3.1:設計一個可以亮度變化的 LED 燈
  1. 先設計硬體連接方式:
    • 注意:麵包板上,每一組 5 孔當中,每組最多只能有 2 孔使用!
    • arduino D5 -- 電阻器 -- LED 正極
    • arduino 接地 -- LED 負極
  2. arduino IDE 程式設計 (code-led-11)
    • 設計名為 led 的全域變數,設計為整數 5
    • 設計名為 light 的全域變數,預設值為 0
    • 設計名為 lightgo 的全域變數,預設值為 5
    • 在 setup() 當中,使用 pinMode 設計 led 變數為 OUTPUT 模式
    • 在 loop() 當中:
      • 預設使用 analogWrite 設計 led 變數為 light
      • 讓 light = light + lightgo
      • 判斷 light 有沒有大於 255,若大於,則讓 light 變成 0
      • 延遲大約 0.05 秒鐘
  3. 將 arduino 安插到主機 USB 插槽,並將 code-led-11 燒錄並上傳

接下來,請自行設計一下,讓這個 LED 燈,可以慢慢變亮之後,再慢慢便暗!

例題 3.3.2:連接方式如同上題,只是讓 LED 慢慢到最亮之後,再慢慢變暗。讓程式檔名為 code-led-12。

例題 3.3.3:加上另一個 LED 在 D6 上面,設計程式為 code-led-13,假設第一個 LED 為 LED1 而第二個是 LED2, 當 LED1 變量時,LED2 會變暗,亦即兩者亮度相加會是 255 (或 200),延遲為 0.02 秒~

3.4: 使用序列 (Serial) 方式,互動調整 LED 燈

我們可以透過 Serial 的功能來設定 LED 是否要點亮,甚至於挑選需要的變化與延遲數據等。 先複習一下序列埠的處理方式:

void setup() {
  Serial.begin(9600);
}

void loop() {
  String tmp = Serial.readString();
  tmp.trim();

通常,鳥哥喜歡將全部的資料抓下來,然後再以類似 tmp.toInt() 之類的方式轉成整數,這樣就可以了! 現在,讓我們來思考一下,當使用者輸入 1 的時候,就點亮燈光,當使用者輸入 0 的時候,就關閉 LED 燈光, 基本上,可以這樣簡單的實做:

例題 3.4.1:依據使用者輸入 0 還是 1 來進行判斷!
  1. 先設計硬體連接方式:
    • 注意:麵包板上,每一組 5 孔當中,每組最多只能有 2 孔使用!
    • arduino D5 -- 電阻器 -- LED 正極
    • arduino 接地 -- LED 負極
  2. arduino IDE 程式設計 (code-led-31)
    • 設計名為 led 的全域變數,設計為整數 5
    • 設計名為 light 的全域變數,且預設整數為 0
    • 在 setup() 當中
      • 使用 pinMode 設計 led 變數為 OUTPUT 模式
      • 設計 Serial.begin 為 9600
    • 在 loop() 當中:
      • 設計字串變數 tmp,且 tmp 直接取得 USB 序列的輸入資料為,取得 tmp 之後,去除頭尾的空白
      • 當 tmp 不是空白 "" 時,進行底下的處理:
        • 設計 num 為整數,且內容為將 tmp 轉為整數
        • 判斷 num 是否為 1,若為 1 時,讓 light 變成 1 ,且 println 出 Turn on 的字串
        • 如果 num 是 0 ,則 light 變成 0,且 println 出 Turn off 的字串
      • 如果 light 為 1 ,則使用 digitalWrite 點亮燈光
      • 如果 light 為 0 ,則使用 digitalWrite 關閉燈光
      • 延遲大約 1 秒鐘
  3. 將 arduino 安插到主機 USB 插槽,並將 code-led-21 燒錄並上傳

例題 3.4.2:我們在 code-led-12 當中,可以使用 analogWrite 讓一顆 LED 變量、變暗。當時的延遲 (delay) 是系統自訂的, 現在,可以透過使用者自定義來處理。處理的流程大概是這樣:
  1. 先指定一個 mydelay 的全域變數,整數初始值,大概是 20 左右。
  2. 讀取來自 USB 序列埠的資料,當資料不是空白,就進入處理。先轉換成為整數,數值規定範圍在 10~100 之間, 超過的話,就設定限制到 10 或 100 即可。之後將 mydelay 變更成為該數值
  3. 執行外部函數,例如 myled 這個函數,外帶參數就是 mydelay 即可。
  4. myled 函數使用 while 進行處理,light 歸零時,就代表跑了一次,這個次數會累計!超過 5 次,就結束 while 迴圈。
新的互動程式儲存為 code-led-22 即可。

3.5: 使用按鈕方式,互動調整 LED 燈

一般的按鈕形式,根據是不是持續保持原有狀態而大致分為兩種,一種是會持續保留連線狀態的開關,如滑動開關、搖動開關、撥指開關等等。 另一種則是按下時短路放開時斷路的按鍵開關。我們這裡先使用簡單的按鍵開關來測試一下好了。

  • 利用 pinMode(sw, INPUT_PULLUP) 設定內升電阻

使用開關,最重要的,當然就是判斷開關的狀態了!這時,就得要了解那一隻數位針腳可以提供斷電、短路的資訊。 跟 LED 供電時,使用 pinMode(led,OUTPUT) 不同,按鍵開關需要使用的是 INPUT 或 INPUT_PULLUP 輸入設定。 其中,單純使用 INPUT 模式時,在線路上面需要用到 5V 或 3.3V 以及電阻器,設定上較為複雜。因此, 我們大概會單純的使用 INPUT_PULLUP 模式,該模式可以使用 arduino 內建的電阻功能,因此不用接電源也不用接電阻! 連線上面會比較簡單。如果使用 INPUT,會有點像市電的開關...

不過,大家都知道,每個人的『手速』都不一樣,有的按下開關速度很快,有的很慢!那, arduino 可能有偵測速度的問題, 因此,我們可以透過一個迴圈的功能,讓 arduino 判斷按鈕的狀態是否持續在短路的情況,就可以處理這個問題。

  • digitalWrite 與 digitalRead

前面講過 digitalWrite 可以針對某個腳位提供高電壓或低電壓,針對剛剛的 pinMode(腳位, HIGH/LOW) 來說, 如果使用 INPUT_PULLUP 時,就得要使用高電壓 HIGH,讓它持續供電,等到按下按鍵時,才會知道有短路發生! 而不會燒毀設備,是因為有內升電阻的緣故!那如何知道該腳位是高電壓還是低電壓呢?就透過 digitalRead(腳位) 來判斷。

  • 沒有按下按鍵:當發生高電壓,代表斷路,就是在 HIGH 的狀態
  • 按下按鍵:發生低電壓,因為發生短路 (迴路),電壓送到接地,因此就是 LOW 的狀態

那怎麼判斷使用者是不是按住開關呢?我們可以寫一個迴圈,內容這樣就好:

int qq = digitalRead(hh);
if ( qq == LOW ) {
	while ( digitalRead(hh) == LOW ) ;   // 這個迴圈沒有任何動作,就是一直迴圈!
	....
}

上面那個 while 的功能,就是在偵測 hh 腳位是不是一直在 LOW (短路) 的狀態!透過這個無窮迴圈,就可以告知 arduino, 使用者按住不放按鍵,請暫時停止往下跑的意思!

例題 3.5.1:透過按鍵開關控制 LED 燈號的明、暗
  1. 先設定硬體連線:
    • 按鍵共有 4 隻腳,兩兩成對,請在麵包板中央部份安裝按鍵。觀察按鍵背面,會有兩條線,兩條線段需要分散在麵包板兩側喔! 這個部份不能搞錯。
    • arduino D5 -- 電阻器一端
    • 電阻器另一端 -- LED 正極
    • LED 負極, 按鍵一端, 接地,連在一起
    • 按鍵另一端 -- arduino D2
  2. 設定整數全域變數, sw 在 2 號, led 在 5 號, ledgo 設定為 LOW (就是 0)
  3. 設定 setup() 函數
    • 設定 led 針腳為 OUTPUT
    • 設定 sw 針腳為 INPUT_PULLUP
    • 設定 sw 針腳在高電壓 (digitalWrite(sw, HIGH))
  4. 設定 loop() 函數
    • 宣告整數 bn 變數,內容為 digitalRead(sw)
    • 判斷 bn 變數,當按下按鈕 (LOW) 時,才進行動作:
      • 判斷 sw 是不是還是 LOW,用 while 進行迴圈判斷
      • 設定 ledgo 的狀態為 !ledgo (如果是 LOW 就變 HIGH,如果是 HIGH 就變 LOW )
      • 使用 digitalWrite 改變 led 的狀態
  5. 燒錄,上傳!檔名就取做 code-led-31 好了!

3.6: 課後作業

設計名為 code-led-bn 的程式,使用者可以按下按鍵,共有 3 種循環,第一種恆暗,第二種恆亮,第三種緩慢變亮後變暗 (code-led-12)。 基本設計的思考可以這樣想看看:

  • 先設計一個名為 myled 的函數,帶有 ledstat 這個狀態整數,ledstat 為 0, 1, 2 進行循環來的。 這個函數的內容根據上述說明,分別帶入 digitalWrite, digitalWrite 以及 analogWrite 加上迴圈等功能來處理即可。
  • 在 loop 當中,跟按鍵範例差不多,但是, ledstat 使用累加的方式,同時判斷如果大於等於 3 ,就回復到 0 的方式來處理。 最後執行 myled(ledstat) 函數即可。

其他的整數變數,請自行宣告處理了!