2012/04/05

Arduino練習:猜猜哪一個

有5個開關,一開始會隨機選出一個當做正確答案,然後讓使用者猜猜看按按看哪個才是對的,若按中正確的就點亮LED;另外有個開關是重置鍵。

接線:
從Arduino板的5V與GND接到麵包板。

Arduino腳位2、3、4、5、6、9,各接到開關的右上腳,
開關的右下腳接電阻後接地,
開關的左下腳接5V。

Arduino腳位8接電阻後接LED長腳,LED短腳接地。



程式碼如下(可到這裡下載):

/* inpin1到inpin5,讓使用者猜猜哪個才是正確的 */
int inpin1=2;
int inpin2=3;
int inpin3=4;
int inpin4=5;
int inpin5=6;

int led=8; /* LED的腳位 */
int inpinReset = 9; /* 重置 */

int randnum; /* 代表哪個才是正確答案 */

/* 重置,以亂數從新選出一個正確答案 */
/* 並熄滅LED */
void reset() {
        randnum = random(1, 6);
        digitalWrite(led, LOW);
        Serial.print("randnum=");
        Serial.println(randnum);
        delay(500);
}

void setup() {
    pinMode(inpin1, INPUT);
    pinMode(inpin2, INPUT);
    pinMode(inpin3, INPUT);
    pinMode(inpin4, INPUT);
    pinMode(inpin5, INPUT);


    pinMode(led, OUTPUT);
    pinMode(inpinReset, INPUT);
    Serial.begin(115200);
   
    reset();
}

void loop() {
    /* 檢查使用者有沒有按下正確的答案(開關) */
    switch (randnum) {
        case 1:
            if(digitalRead(inpin1) == HIGH){
                digitalWrite(led, HIGH);
                Serial.println("inpin1");
            }
            break;
        case 2:
            if(digitalRead(inpin2) == HIGH){
                digitalWrite(led, HIGH);
                Serial.println("inpin2");
            }
            break;
        case 3:
            if(digitalRead(inpin3) == HIGH){
                digitalWrite(led, HIGH);
                Serial.println("inpin3");
            }
            break;
        case 4:
            if(digitalRead(inpin4) == HIGH){
                digitalWrite(led, HIGH);
                Serial.println("inpin4");
            }
            break;
        case 5:
            if(digitalRead(inpin5) == HIGH){
                digitalWrite(led, HIGH);
                Serial.println("inpin5");
            }
            break;
    }

    /* 若按下inpinReset就重置 */
    if(digitalRead(inpinReset) == HIGH){
        Serial.println("inpinReset");
        reset();
    }
}

上面這份程式碼,還有很多可以改進的地方。

首先是亂數的部分,應該要先用randomSeed(analogRead(0)),才不會每次產生出來的亂數序列都是一樣的。

然後是switch的部份,可利用陣列儲存腳位,就不需要重複寫那麼多個case了。

另外,開關會有bounce問題,不過就這裡的情況來說,沒關係。

另外,可以增加「最多猜三次」這樣的行為,三次都猜錯後就失敗、重置。

可以增加揚聲器,發出猜對、猜錯的音效

32 comments:

  1. 請問一下,我想寫一個程式,然後有兩個不同的執行迴圈,我想在序列埠監控視窗輸入不同數字然後執行相對應的迴圈,本來想說試試看switch case 但我用了以後程式卻只能執行一次,而不能重複持續迴圈,可否給小弟一點如何寫這程式的提點,拜託了!

    ReplyDelete
    Replies
    1. 大概是這樣子吧
      int x = 0;
      void loop(){
      switch(x){
      case 0:
      break;
      case 1:
      迴圈一
      break;
      case 2:
      迴圈二
      break;
      }
      }
      從序列埠接收數字,然後設定全域變數x,
      根據x的值,執行相對應的迴圈。

      Delete
  2. 第一次接觸有個地方看不太懂
    從Arduino板的5V與GND接到麵包板,接在上面的正負極是要幹嘛?
    看沒有其他接線接過去,還是說上面的正負極和下面的正負極是相通的?
    煩請指教

    ReplyDelete
    Replies
    1. 是的,如你所說。文中照片沒有秀出來。

      Delete
  3. 如果要把上面的按鈕改成紅外線遙控器上的按鈕要怎麼辦

    ReplyDelete
    Replies
    1. 請參考
      Arduino練習:紅外線傳送與接收
      http://yehnan.blogspot.tw/2013/05/arduino.html

      Delete
  4. 請問這電阻是接多少的阿?
    圖片看不太出來
    謝謝

    ReplyDelete
    Replies
    1. 開關的電阻是10k,
      LED的電阻是220。

      Delete
    2. 請問這電阻是怎麼知道該使用多少的啊?
      如果我沒有這些可以用哪些電阻來代替嗎?
      謝謝

      Delete
    3. 請參閱 Arduino小知識:為什麼LED需要串聯的電阻值是220 ohm?
      http://yehnan.blogspot.tw/2012/03/arduinoled220-ohm.html

      以這篇文章裡的電路而言,220 ohm可以換成150~300,應該都可以,不過會影響LED亮度。10k ohm可以換成8k~12k,應該都可以。

      Delete
  5. 亂數的部分,應該要先用randomSeed(analogRead(0))
    請問這句能否在解釋的詳細一點呢
    遇到亂數一直都跑同一個的問題
    謝謝~

    ReplyDelete
    Replies
    1. Arduino提供的是假亂數(pseudo-random),

      你把它想像成:Arduino內建有一長串的亂數值,呼叫random時、預設會從第一個拿出來給你,下次呼叫random時會拿第二個給你,若如此,每次都會得到相同的亂數序列。
      所以要先呼叫randomSeed,作用是跳到一長串亂數值的某個位置,然後從該位置開始。

      當腳位A0沒有接東西時,呼叫analogRead讀取的話,會讀到空氣,值不定。

      Delete
    2. 了解!!
      非常感謝

      Delete
  6. 請問一下 如果不只要隨機一個亂數
    想要改成每次隨機個數不同
    不知能怎麼改呢 謝謝!!

    ReplyDelete
    Replies
    1. > 每次隨機個數不同
      你問的是這一篇嗎?

      你說的是需求,不是問題。


      Delete
    2. 對 我的意思是要每次隨機個數不同
      好像找不到這一篇的文章耶~
      不知道要怎麼改才有辦法達成
      謝謝

      Delete
    3. 喔,了解。

      請參考這篇
      Arduino練習:Simon Says請你跟我這樣做
      http://yehnan.blogspot.tw/2012/02/arduinosimon-says.html

      Delete
  7. 請問一下,不能讓每個開關共電阻嗎?

    ReplyDelete
    Replies
    1. 這樣不就互相影響?

      Delete
  8. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. 只要跳到控制馬達的部分就好,看不太懂隨機的寫法,馬達該怎麼控制我已經知道了

      Delete
    2. 不斷地呼叫random(1, 3);取得介於1~3之間的亂數,
      使用switch根據該亂數值,執行你想要的馬達控制指令。

      Delete
  9. #include

    Servo myservo ;
    Servo myservo1 ;

    void setup() {
    myservo.attach(9);
    myservo1.attach(10);

    }
    void p()
    {
    myservo.write(25);
    myservo1.write(5);

    }
    void st()
    {
    myservo.write(150);
    myservo1.write(65);

    }
    void sc()
    {
    myservo.write(25);
    myservo1.write(75);

    }
    void loop(){
    }


    ReplyDelete
    Replies
    1. 請問要加上什麼程式碼才能隨機執行這三個迴圈呢?

      Delete
    2. switch(random(1,3)){
      case 1:
      p();
      break;
      case 2:
      st();
      break;
      case 3:
      sc();
      break;
      }

      大概如此吧。

      Delete
    3. 感謝,我試試看

      Delete
    4. 他只會跳到st耶
      為什麼會這樣?

      Delete
    5. #include

      Servo myservo ;
      Servo myservo1 ;
      Servo myservo2 ;
      Servo myservo3 ;
      Servo myservo4 ;

      void setup() {
      myservo.attach(9); // 食指 9
      myservo1.attach(10); // 大拇指 10
      myservo2.attach(11); // 中指 11
      myservo3.attach(6); // 無名指 6
      myservo4.attach(5); // 小拇指 5
      }
      void p()
      {
      myservo.write(25);
      myservo1.write(5);
      myservo2.write(40);
      myservo3.write(20);
      myservo4.write(15);
      delay(200);
      }
      void st()
      {
      myservo.write(150);
      myservo1.write(65);
      myservo2.write(155);
      myservo3.write(160);
      myservo4.write(80);
      delay(200);
      }
      void sc()
      {
      myservo.write(25);
      myservo1.write(75);
      myservo2.write(40);
      myservo3.write(160);
      myservo4.write(90);
      delay(200);
      }
      void loop(){
      switch(random(1,3)){
      case 1:
      p();
      break;

      case 2:
      st();
      break;

      case 3:
      sc();
      break;
      }
      }

      Delete
    6. 這是我完整的程式碼

      Delete