2014/03/15

Arduino練習:以開關切換LED是否閃爍

這一篇以「Arduino練習:以開關切換LED明滅狀態」為基礎,但功能改成:按一下開關,LED開始閃爍,再按一下開關,LED熄滅,依此類推。

這一篇不會有太多說明,若對Arduino、程式庫、開關bounce問題等等不熟悉的話,還請參考我其他的文章:Arduino文章列表,或是參考我寫的Arduino入門書:Arduino輕鬆入門:範例分析與實作設計

我的環境:Windows XP、Arduino 1.0.5、板子是Arduino Uno R3。

電路圖很簡單,就是一個LED與一個開關而已。
至於草稿碼方面,我將寫兩個版本,分別運用不同的技巧來達成功能:一個使用millis記錄時間,另一個使用程式庫。

首先是使用millis記錄時間的版本,程式碼可到這裡下載;使用millis記錄時間,比較上次與這次的時間後,決定做什麼事情。注意,程式內沒有使用delay函式

#define LED_PIN 13
#define SWITCH_PIN 12

#define DEBOUNCE_DELAY 200
unsigned long lastDebounceTime;
int ledBlinkStatus;

#define LED_BLINK_TIME 300
unsigned long lastUpdateLedTime;
int ledStatus = LOW;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(SWITCH_PIN, INPUT);
}
void updateLedBlinkStatus(){
  unsigned long currentTime = millis();
  if((currentTime - lastDebounceTime) > DEBOUNCE_DELAY){
    lastDebounceTime = currentTime;
    ledBlinkStatus = !ledBlinkStatus;
  }
}
void updateLed(){
  if(ledBlinkStatus){
    unsigned long currentTime = millis();
    if((currentTime - lastUpdateLedTime) > LED_BLINK_TIME){
      lastUpdateLedTime = currentTime;
      ledStatus = !ledStatus;
    }
  }
  else{
    ledStatus = LOW;
  }
  digitalWrite(LED_PIN, ledStatus);
}
void loop() {
  int switchStatus = digitalRead(SWITCH_PIN);
  if(switchStatus == HIGH){
    updateLedBlinkStatus();
  }
  updateLed();
}


另一個則是使用程式庫TimerBounce的版本,程式碼可到這裡下載,程式庫Timer的用法請參考這篇,程式庫Bounce的用法請看這篇

#include <Bounce.h>
#include <Timer.h>

#define LED_PIN 13
#define SWITCH_PIN 12

#define DEBOUNCE_DELAY 50
int ledBlinkStatus = 0;
Bounce bouncer = Bounce(SWITCH_PIN, DEBOUNCE_DELAY);

#define LED_BLINK_TIME 300
Timer timer;
int8_t timer_id;

void setup() {
  pinMode(LED_PIN, OUTPUT);
  pinMode(SWITCH_PIN, INPUT);
}
void loop() {
  if(bouncer.update() == true && bouncer.read() == HIGH){
    ledBlinkStatus = !ledBlinkStatus;
    if(ledBlinkStatus){
      timer_id = timer.oscillate(LED_PIN, LED_BLINK_TIME, HIGH);
    }
    else{
      timer.stop(timer_id);
      digitalWrite(LED_PIN, LOW);
    }
  }
  timer.update();
}

使用程式庫後,程式碼變短許多。

6 comments:

  1. Anonymous19/3/14 18:35

    想不到老師寫出來了 受益良多 謝謝

    ReplyDelete
  2. 想請問老師
    我在序列埠上輸入的10進位數字與下方顯示的數字不相同?請問是在輸入10進位要加上什麼符號還是我的程式有問題
    例如輸入6 顯示74

    ReplyDelete
    Replies
    1. > 輸入6 顯示74
      嗯,猜不出來。

      你呼叫什麼函式?

      > 下方顯示的數字
      下方是什麼?

      Delete
    2. 我是在練習一個Making a Binary Quiz Game的練習題
      原始碼如下
      //Project 17 - Making a Binary Quiz Game
      #define DATA 6 // connect to pin 14 on the 74HC595
      #define LATCH 8 // connect to pin 12 on the 74HC595
      #define CLOCK 10 // connect to pin 11 on the 74HC595

      int number = 0;
      int answer = 0;

      void setup()
      {
      pinMode(LATCH, OUTPUT); //set up the 74HC595
      pinMode(CLOCK, OUTPUT);
      pinMode(DATA, OUTPUT);
      Serial.begin(9600);
      randomSeed(analogRead(0));
      displayNumber(0);
      }

      void displayNumber(byte a)
      {
      //send byte to be displayed on the LEDs
      digitalWrite(LATCH, LOW);
      shiftOut(DATA, CLOCK, MSBFIRST, a);
      digitalWrite(LATCH,HIGH);
      }

      void getAnswer()
      {
      //receive the answer from the player
      int z = 0;
      Serial.flush();
      while (Serial.available() == 0 );
      {
      //do nothing until someting comes into the serial buffer
      }
      while ( Serial.available() > 0 )
      {
      //move any previous digit to the next column on the left; in
      //other words, 1 becomes 10 while thers is data in the buffer answer = anser * 10;
      // red the next number in the buffer and subtract the character '0'
      z = Serial.read() - '0';
      //ass this digit into the accumulating value
      answer = answer + z;
      //allow a short delay for any more numbers to come into Serial.vaailable
      delay(5);
      }
      Serial.print("you entered:");
      Serial.println(answer);
      }
      void checkAnswer()
      {
      //check the answer form the player and show the results
      if ( answer == number ) //Correct!
      {
      Serial.print("Correct!");
      Serial.print(answer,BIN);
      Serial.print(" equals ");
      Serial.print(number);
      Serial.println();
      }
      else //Incorrect
      {
      Serial.print("Incorrect,");
      Serial.print(number,BIN);
      Serial.print(" equals ");
      Serial.print(number);
      Serial.println();
      }
      answer = 0;
      delay(10000); //give the player time to rrview his or her answer
      }

      void loop()
      {
      number = random(256);
      displayNumber(number);
      Serial.println("What is the binary number in base-10?");
      getAnswer();
      checkAnswer();
      }
      我要在序列埠上輸入監控視窗中用十進位輸入電路板顯示的二進位數值
      我輸入的數值在視窗上顯示看起來像是總和
      輸入0-9 視窗顯示都能正常顯示0-9
      輸入11 視窗顯示2
      輸入123 視窗顯示6
      請問老師這樣是我的原始碼有問題還是我的開發環境設定有問題?

      Delete

    3. answer = answer + z;
      改成
      answer = answer * 10 + z;

      Delete
    4. 謝謝老師我找到問題了
      我在Serial port 輸入文字
      arduino顯示的文字看起來像是數字總和
      後來發現原始碼裡面忘記每個數字要*10
      void getAnswer()
      {
      //receive the answer from the player
      int z = 0;
      Serial.flush();
      while (Serial.available() == 0 );
      {
      //do nothing until someting comes into the serial buffer
      }
      while ( Serial.available() > 0 )
      {
      //move any previous digit to the next column on the left; in
      //other words, 1 becomes 10 while thers is data in the buffer
      answer = answer * 10;
      // red the next number in the buffer and subtract the character '0'
      //from it to convert it to the actual integer number
      z = Serial.read() - '0';
      //ass this digit into the accumulating value
      answer = answer + z;
      //allow a short delay for any more numbers to come into Serial.vaailable
      delay(5);
      }
      Serial.print("you entered:");
      Serial.println(answer);
      }
      來獲得10進位

      Delete