Arduino 演練 - 開關電路與LED跑馬燈效果加強版

最近摸了一下Arduino的書籍及天瓏官網上的Arduino基本入門套件,來過過癮以前大學時可

以動手接的電路板,再加上還可以寫code燒錄到控制板上面,如根據程式邏輯來控制LED

二極體的明滅,感覺比起以前只是單純接電路來說顯得比較有趣的說!!

由於小弟我電路不太會接,因此頂多有能力在code上面做一些變化,電路的部分接的都很簡

單說! 甚至只是將兩個範例電路混在一起接通,因此在這邊只是純分享加強範例的code來做

個展示!

PS. 這不是教學文,因為我也是初學者XD,若有問題請不吝指正! 並一起學習囉!

在此使用的素材如下:
1. Arduino Uno R3
2. 麵包板
3. 10KΩ*1
4. 220Ω*4
5. LED燈(藍)*4
6. 按鍵開關*1
7. 麵包線*8

這個演練合併範例中的開關電路+跑馬燈電路,可參閱超圖解 arduino 互動設計入門第3版

第4章部分的4-1, 4-2小節。由於套件與書本是不同來源,因此並不一定會按照書中的電阻及

開關都一致囉!

實際電路接法

一、演練效果說明

當使用者按下按鍵開關時,由左至右的LED燈會依序亮起來;直到放開按鍵後,LED燈才

會反方向依序滅掉! 在這之中,若再次按下按鍵會從最左邊暗的LED繼續亮起來!

二、簡單說明一下電路接法

首先,開關按鍵部分需在接地之中接上一10K電阻,避免造成輸入腳位2讀到0 or 1產生浮動

訊號! 也就是初始時沒按下按鍵燈就亮了。 再來是四顆LED分別對應四根220電阻,設定輸

出的腳位是8 ~ 11 ! 

三、程式說明

原則上arduino program有一個初始化的setup method及不斷repeat來執行動作的loop method

在method外宣告的變數則為全域變數
void setup() {
// put your setup code here, to run once:
}

void loop() {
// put your main code here, to run repeatedly:
}

在setup()內通常可以先指定您要針對哪些腳位進行輸入or輸出的設定
void setup() {
  for(byte i = 0 ; i < COUNT ; i++){
     pinMode(LED_START + i, OUTPUT);
  }
  pinMode(SW, INPUT);
}

在loop()內您可以定義程式執行邏輯
const byte LED_START = 8;
const byte COUNT = 4;
const byte SW = 2;
byte last = 0;

void loop() {
   boolean on = digitalRead(SW);
   if(on){
    //display LED on
    if(last != COUNT){
      for(byte i = 0 ; i < COUNT ; i++){
        digitalWrite(LED_START + i, HIGH);
        if(last <= 4)last++;
        i = checkIfClicked(i, on);
      }
    } 
  }else{
    //display LED off
    if(last != 0){
      for(byte i = last ; i > 0 ; i--){
        digitalWrite(LED_START + (i - 1), LOW);
        if(last > 0)last--;
        i = checkIfClicked(i, on);
      }
    }  
  }
}

3.1 當按鍵按下時

首先從腳位2讀到的訊號為1 or 0,若為1表示user按下按鍵,on變數為true

digitalRead - Reads the value from a specified digital pin, either HIGH or LOW. (官網說明)

判斷last是否等於COUNT,目的是防堵LED燈都亮起來後,繼續進入此區域重複執行!

但若有一盞燈沒有亮起來,就可以進入!

digitalWrite - Write a HIGH or a LOW value to a digital pin. (官網說明)

當呼叫到checkIfClicked表示檢查按鍵按下當下,傳入的參數分別為執行迴圈的變數i及當下

的boolean變數此時為true。若user鬆開按鍵,此時區域變數on => 0 or false,如此一來

在else區塊內使得current = COUNT,當回傳並assign至i變數後,將會立即跳出for迴圈執行!!

byte checkIfClicked(byte i, boolean currentOn){
  delay(100);
  boolean on = digitalRead(SW);
  byte current = i;
  if(!currentOn){
    if(on)current = 1;
  }else{
    if(!on)current = COUNT;
  }
  return current;
}

3.2 當按鍵鬆開時

從3.1跳出迴圈之後,回到loop()起始,此時on => false便進入else區塊內

這個時候last變數會記錄剛剛亮起了幾盞LED燈,進入迴圈後會依續從最後一盞燈往回暗去

此時一樣會進入checkIfClicked method,若還沒有全部暗去之前user又按下了按鍵,此時

current = 1,當回傳並assign至i變數後,將會立即跳出for迴圈執行!!

但若是全部的燈都暗去了且user沒有任何動作,程式又會回到loop()內且無法再次進入

display LED off區塊內,因為last變數已為0!

DEMO影片如下:


PS. 由於影片與上面的圖片兩個上下顛倒過來,因此影片中燈是由右至左亮起來!

參考資料
趙英傑著 超圖解 arduino 互動設計入門第3版第四章節

留言

  1. 請問有完整的程式嗎?我還是看不懂程式的解釋....

    回覆刪除
    回覆
    1. 請問是哪個部分不解?

      刪除
    2. 就是根據上面的程式,我不知道如何打出像上面完整的程式讓他形成按鈕按下去會有跑馬燈,總之就是不知道怎麼把上面的程式整合成一個程式

      刪除
    3. 原則上這支程式就三個function
      void setup() {
      ...
      }
      void loop() {
      ...
      }
      byte checkIfClicked(byte i, boolean currentOn){
      ...
      }
      裡面的內容都完整的貼在文章內

      還有這四個global variables
      const byte LED_START = 8;
      const byte COUNT = 4;
      const byte SW = 2;
      byte last = 0;

      請問這樣有了解?

      刪除
  2. 您好,驗證的時候,setup當中的
    void setup() {
    for(byte i = 0; i < COUNT; i++){
    好像有錯誤,它說是COUNT was not declared in this scope
    請問您是如何解的?

    回覆刪除
    回覆
    1. 請問您有把COUNT這個global variable的宣告加入到您的程式碼內?在上面貼上的程式碼有提到
      如下:
      const byte LED_START = 8;
      const byte COUNT = 4;
      const byte SW = 2;
      byte last = 0;

      刪除

張貼留言