---
# System prepended metadata

title: 2025陽明交大電機營(公開版)

---

# 2025 陽明交大電機營 Arduino組
### 底下Exercise與Lab的程式碼都會被挖空，請根據題目要求將程式碼完成
---
# Exercise 0 前置作業

## CH340與Arduino IDE
https://drive.google.com/drive/folders/1xobgSl3XplSYGP4RiAqiI1rOKVg4xDGa?usp=drive_link

## 工具箱
1. Arduino UNO版(含連接線)*1
2. 麵包版*1
3. 公對公杜邦線*18
4. 公對母杜邦線*5
6. 色環電阻*4
7. LED*4
8. 可變電阻*1
9. 按鈕*1
10. 超音波感測器*1
11. 伺服馬達*1
12. 無源蜂鳴器*1
13. 搖桿*1
---

# Exercise 1 可變電阻與LED

---

![image](https://hackmd.io/_uploads/rk5hfvm1ee.png)

# Exercise 2 按鈕

---

![image](https://hackmd.io/_uploads/Syfr4zRJel.png)




## 程式碼

```arduino=
int pushbutton = 2;  //設定按鈕的接腳
int buttonState = 1; //代表按鈕現在的狀態
int beforeState = 1; //代表按鈕的前一個狀態
int times = 0; //設定一個用於計次的整數
void setup() {
    Serial.begin(9600); //開始與電腦連接
    ___1___ //設定按鈕並且給予上拉電阻
}
void loop() {
    buttonState = digitalRead(pushbutton); //讀入此時的按鈕狀態
    if(buttonState == 0 && beforeState == 1) { //當按鈕被按下時執行
        ___2___  //讓程式暫停50毫秒後再繼續讀取
        times++; //計次數加1
        ___3___ //在視窗列印出計次數並換行
    }
    beforeState = buttonState; //將此時的按鈕狀態存到前一刻的按鈕狀態
}
```

## Problem 1 設定按鈕給予上拉電阻

```arduino=5
void setup() {
  Serial.begin(9600); //開始與電腦連接
  ___1___ //設定按鈕並且給予上拉電阻
}
```

<aside>

:::success
Problem 1 :
選項 >> 只有一個是對的喔!

</aside>

> A )  `pinmode(pushbutton,INPUT);`
> 
> 
> B )  `pinmode(pushbutton,INPUT_PULLUP);` 
> 
> C )  `pinMode(pushbutton,Input_Pullup);` 
> 
> D )  `pinMode(pushbutton,INPUT_PULLUP);` 
> 
## Problem 2 Debounce

```arduino=11
if(buttonState == 0 && beforeState == 1) { //當按鈕被按下時執行
    ___2___  //讓程式暫停50毫秒後再繼續讀取
    times++; //計次數加1
    ___3___  //在視窗列印出計次數並換行
}
```

<aside>

:::success
Problem 2 :
選項 >> 只有一個是對的喔!

</aside>

> A )  `delay(50);`
> 
> 
> B )  `Delay(50);` 
> 
> C )  `Debounce(times);`
> 
> D )  `Debounce(buttonState);` 
> 
## Problem 3 在序列埠監控視窗列印出計次數並換行

```arduino=11
if(buttonState == 0 && beforeState == 1){ //當按鈕被按下時執行
    ___2___  //讓程式暫停20毫秒後再繼續讀取
    times++; //計次數加1
    ___3___  //在視窗列印出計次數並換行
}
```

<aside>
    
:::success
Problem 3 :
選項 >> 只有一個是對的喔!

</aside>

> A )  `Serial.print(times);`
> 
> 
> B )  `serial.print(times);` 
> 
> C )  `Serial.println("times");`
> 
> D )  `Serial.println(times);` 
> 
# Exercise 3 超音波感測器
![image](https://hackmd.io/_uploads/rk0x9DmJlg.png)

---
### 超音波感測器請這樣接。
![image](https://hackmd.io/_uploads/Sk3c26IBex.png)





## 程式碼

```arduino=
int Trig=13;
int Echo=12;
double distance();

void setup() { 
  Serial.begin(9600);    //設定鮑率為9600
  __1.1__        //將Trig腳位訂為輸出
  __1.2__        //將Echo腳位訂為輸入
}

void loop() {
  Serial.print("Distance : ");
  Serial.print(distance());
  Serial.println("cm");
  delay(2000);
}

double distance(){
  digitalWrite(Trig,__2.1__); //高電位
  delayMicroseconds(10);                //持續10微秒
  digitalWrite(Trig,__2.2__); //回到低電位
  long duration = pulseIn(Echo,HIGH);
  return ___3___;     //套公式
}
```

## Problem 1 設定腳位的模式

```arduino=5
void setup() { 
  Serial.begin(9600);      //設定鮑率為9600
  __1.1__       //將Trig腳位訂為輸出
  __1.2__       //將Echo腳位訂為輸入
}
```

<aside>
    
:::success
Problem 1 :
選項 >> 只有一個是對的喔!
</aside>

```
__1.1__ / __1.2__
```

> A )  `pinMode(Trig,OUTPUT);` / `pinMode(Echo,OUTPUT);`
> 
> B )  `pinMode(Trig,INPUT);`  / `pinMode(Echo,INPUT);`
> 
> C )  `pinMode(Trig,OUTPUT);` / `pinMode(Echo,INPUT);`
> 
> D )  `pinMode(Trig,INPUT);`  / `pinMode(Echo,OUTPUT);`
> 

## Problem 2 發出超音波

```arduino=19
digitalWrite(Trig,__2.1__); //高電位
delayMicroseconds(10);                //持續10微秒
digitalWrite(Trig,__2.2__); //回到低電位
```

<aside>

:::success
Problem 2 :
選項 >> 只有一個是對的喔!

</aside>

```
__2.1__ / __2.2__
```


> A )  `HIGH` / `LOW`
> 
> 
> B )  `LOW`  / `HIGH`
> 
> C )  `INPUT` / `OUTPUT`
> 
> D )  `OUTPUT` / `INPUT`
> 

## Problem 3 發出超音波

```arduino=22
long duration = pulseIn(Echo,HIGH);
return ___3___;     //套公式
```

<aside>

:::success
Problem 3 :
選項 >> 只有一個是對的喔!

</aside>



> A )  `duration * 0.0346`
> 
> 
> B )  `duration * 346 / 2`
> 
> C )  `duration * 0.0346 / 2`
> 
> D )  `duration * 346`
> 

# Exercise 4 伺服馬達

---
![image 1](https://hackmd.io/_uploads/HkOxYwQyle.png)





## 程式碼

```arduino=
#include <Servo.h>

Servo servo;
int spin = 10;
int angle = 0;

void setup() {
  ___1___      //將Servo設定到腳位9
}

void loop() {
  servo.write(angle);    //把angle寫入servo中
  angle += spin;
  if(___2___){       //判斷角度是否超出旋轉範圍
    spin *= -1;      //如果超過範圍就往反方向旋轉
  }
  delay(500);
}
```

## Problem 1 設定伺服馬達的腳位

```arduino=7
void setup() {
  ___1___      //將Servo設定到腳位9
}
```

<aside>

:::success
Problem 1 :
選項 >> 只有一個是對的喔!

</aside>

> A )  `servo.attach(9);`
> 
> 
> B )  `servo.write(9);`
> 
> C )  `pinMode(9,OUTPUT);`
> 
> D )  `pinMode(9,INPUT);` 
> 

## Problem 2 判斷旋轉角度的範圍

```arduino=14
if(___2___){       //判斷角度是否超出旋轉範圍
    spin *= -1;          //如果超過範圍就往反方向旋轉
}
```

<aside>

:::success
Problem 2 :
選項 >> 只有一個是對的喔!

</aside>

> A )  `angle<=0`
> 
> 
> B )  `angle>=180`
> 
> C )  `angle<=0 && angle>=180`
> 
> D )  `angle<=0 || angle>=180`
> 

# Exercise 5 無源蜂鳴器

---



![螢幕擷取畫面 2025-06-22 224415](https://hackmd.io/_uploads/rJv1ucrEle.png)



## 程式碼

```arduino=
int TRIG  = 9; // 超音波模組的Trig腳位
int ECHO = 10; // 超音波模組的Echo腳位
int BUZZER = 5; // 無源蜂鳴器腳位
double distance();

void setup() { 
    pinMode(TRIG, __1.1__); //將Trig腳位訂為輸出
    pinMode(ECHO, __1.2__); //將Echo腳位訂為輸入
    pinMode(BUZZER, __1.3__); 
    Serial.begin(9600); // 開啟序列埠監視器 
}

void loop() { 
    double d = distance();
    /*Debug用
    Serial.print("Distance : ");
    Serial.print(d);
    Serial.println("cm");*/
    if (d > 20) { // 大於 20cm，不發出聲音
        noTone(BUZZER); 
    } else if (d > 10) { // 10-20 cm，1 秒 1000Hz，1 秒靜音
        tone(BUZZER, __2.1__); 
        delay(1000); 
        __2.2__(BUZZER); 
        delay(1000); 
    } else { // 0-10 cm，0.5 秒 2000Hz，0.5 秒靜音
        tone(BUZZER, __2.3__); 
        delay(500); 
        noTone(BUZZER); 
        delay(500); 
    }
}

double distance() {
    digitalWrite(TRIG,HIGH);//產生高電位脈衝
    delayMicroseconds(10); //持續 10 µs
    digitalWrite(TRIG,LOW);  
    long duration = pulseIn(ECHO,HIGH);//時間∆t
    return duration * 0.0346 / 2;//距離公式
}
```

## Problem 1 設定蜂鳴器和超音波腳位

```arduino=6
void setup() { 
    pinMode(TRIG,__1.1__); //將Trig腳位訂為輸出
    pinMode(ECHO,__1.2__); //將Echo腳位訂為輸入
    pinMode(BUZZER,__1.3__); // 把蜂鳴器設為輸出
    Serial.begin(9600); // 開啟序列埠監視器 
}
```
:::success
Problem １ :
選項 >> 只有一個是對的喔!
:::
```
__1.1__ / __1.2__ / ___1.3___
```

> A )  `INPUT` / `OUTPUT` / `INPUT`
> 
> 
> B )  `OUTPUT` / `INPUT` / `OUTPUT`
> 
> C )  `INPUT` / `OUTPUT` / `OUTPUT`
> 
> D )  `OUTPUT` / `INPUT` / `INPUT` 
> 

## Problem 2 讓蜂鳴器發出特定聲音

```arduino=13
void loop() { 
    double d = distance();
    if (d > 20) { // 大於 20cm，不發出聲音
        noTone(BUZZER); 
    } else if (d > 10) { // 10-20 cm，1 秒 1000Hz，1 秒靜音
        tone(BUZZER, __2.1__); 
        delay(1000); 
        __2.2__(BUZZER); 
        delay(1000); 
    } else { // 0-10 cm，0.5 秒 2000Hz，0.5 秒靜音
        tone(BUZZER, __2.3__); 
        delay(500); 
        noTone(BUZZER); 
        delay(500); 
    }
}
```
:::success
Problem 2 :
選項 >> 只有一個是對的喔!
:::
```
__2.1__ / __2.2__ / __2.3__
```


> A )  `1000` / `tone` / `2000`
> 
> 
> B )  `2000` / `noTone` / `1000`
> 
> C )  `1000` / `noTone` / `2000`
> 
> D )  `2000` / `tone` / `500`
> 

# Exercise 6 搖桿

---



![螢幕擷取畫面 2025-06-15 204411](https://hackmd.io/_uploads/S1c8lH37ex.png)
![Arduino (9)](https://hackmd.io/_uploads/H1o2_3lHlx.jpg)
![Arduino (7)](https://hackmd.io/_uploads/B1vOdherxx.jpg)




## 程式碼

```arduino=
#include <Servo.h>
int x = A0;   // 搖桿 X 軸（控制伺服）
int y = A1;  // 搖桿 Y 軸（控制蜂鳴器）
int SERVO = 9;     // 伺服馬達接腳
int BUZZER = 6;    // 蜂鳴器接腳
Servo servoMotor;

void setup() {
    pinMode(x, INPUT);
    pinMode(y, INPUT);
    pinMode(BUZZER, OUTPUT);    
    servoMotor.attach(SERVO);  // 連接伺服馬達  
    //Serial.begin(9600);
}

void loop() {
    // 讀取搖桿數值（0~1023）
    int xValue = __1.1__;   // 讀取搖桿x方向數值（0~1023）
    int yValue = __1.2__;   // 讀取搖桿y方向數值（0~1023）
  
    /*Debug用
    Serial.print("Xpos : ");
    Serial.println(xValue);
    Serial.print("Ypos : ");
    Serial.println(yValue);*/
  
    // X 軸控制伺服馬達（對應到 0° ~ 180°）
    int servoAngle = __2.1__;
    servoMotor.write(servoAngle);

    // Y 軸控制蜂鳴器頻率（對應到 1000Hz ~ 1500Hz）
    int buzzerFreq = __2.2__;
    tone(BUZZER, buzzerFreq);
}
```

## Problem 1 讀取搖桿數值

```arduino=17
int xValue = __1.1__;   // 讀取搖桿x方向數值（0~1023）
int yValue = __1.2__;   // 讀取搖桿y方向數值（0~1023）
```

:::success
Problem １ :
選項 >> 只有一個是對的喔!
:::
```
__1.1__ / __1.2__
```


> A )  `analogRead(x)` / `analogRead(y)`
> 
> 
> B )  `analogread(x)` / `analogread(y)`
> 
> C )  `digitalRead(x)` / `digitalRead(y)` 
> 
> D )  `digitalread(x)` / `digitalread(y)` 
> 

## Problem 2 搖桿數值轉換

```arduino=20
// X 軸控制伺服馬達（對應到 0° ~ 180°）
int servoAngle = __2.1__;
servoMotor.write(servoAngle);

// Y 軸控制蜂鳴器頻率（對應到 1000Hz ~ 1500Hz）
int buzzerFreq = __2.2__;
tone(BUZZER, buzzerFreq);
```

:::success
Problem 2 :
選項 >> 只有一個是對的喔!
:::
```
__2.1__ / __2.2__
```

> A )  `map(xValue, 0, 180, 0, 1023)` / `map(yValue, 1000, 1500, 0, 1023)`
> 
> 
> B )  `Map(xValue, 0, 180, 0, 1023)` / `Map(yValue, 1000, 1500, 0, 1023)` 
> 
> C )  `map(xValue, 0, 1023, 0, 180)` / `map(yValue, 0, 1023, 1000, 1500)`
> 
> D )  `Map(xValue, 0, 1023, 0, 180)` / `Map(yValue, 0, 1023, 1000, 1500)`
> 

---

# Lab1 平交道

---

![螢幕擷取畫面 2025-07-01 085523](https://hackmd.io/_uploads/BkfpT2EBex.png)




## 程式碼

---

```arduino=
#include <Servo.h>  // 引入伺服馬達函式庫

int trigPin = 9;      // TRIG 腳位：超音波模組
int echoPin = 10;     // ECHO 腳位：超音波模組
int servoPin = 6;     // 伺服馬達腳位
int redLed = 3;       // 紅色 LED
int greenLed = 4;     // 綠色 LED
int buzzer = 5;       // 蜂鳴器腳位
int button = 7;       // 按鈕腳位

Servo servo;  // 宣告 Servo 物件控制馬達

void setup() {
    Serial.__1__(9600);                // 設定序列通訊鮑率為 9600
    pinMode(trigPin, OUTPUT);         // TRIG 設為輸出
    pinMode(echoPin, INPUT);          // ECHO 設為輸入
    pinMode(redLed, OUTPUT);          // 紅色 LED 設為輸出
    pinMode(greenLed, OUTPUT);        // 綠色 LED 設為輸出
    pinMode(buzzer, OUTPUT);          // 蜂鳴器設為輸出
    pinMode(button, __2__);           // 按鈕腳位設為輸入，使用內部上拉電阻
    servo.__3__(servoPin);            // 將伺服馬達接到指定腳位
    servo.write(0);                   // 初始設為 0 度（柵欄打開）
}

void loop() {
    long duration;                    // 儲存超音波回波時間
    float distance;                   // 計算距離（公分）
    int buttonState;
    buttonState = digitalRead(button);  // 讀取按鈕狀態

    /*debug用
    Serial.print("距離為: ");
    Serial.println(distance);
    Serial.print(" 按鈕狀態: ");
    Serial.println(buttonState);
    */
    
    if (__4__) {                      // 如果按鈕被按下
        servo.write(0);              // 馬達轉到開啟角度
        digitalWrite(redLed, HIGH);  // 紅燈亮
        digitalWrite(greenLed, HIGH);// 綠燈亮
        __5.1__(buzzer, 500);        // 蜂鳴器發出聲音（150Hz）
        Serial.println("狀態：緊急按鈕按下，強制停止");
    }
    else {
        digitalWrite(trigPin, __6.1__);  // 送出超音波
        delayMicroseconds(10);          // 等 10 微秒
        digitalWrite(trigPin, __6.2__); // 停止送出超音波

        duration = pulseIn(echoPin, HIGH);   // 偵測回音時間
        distance = __7__ * 0.034 / 2;        // 計算距離（cm）

        Serial.print("測得距離: ");          
        Serial.print(distance);
        Serial.println(" cm");
        __5.2__(buzzer);                // 停止蜂鳴器
        if (distance > 20) {
            delay(500);
            servo.write(0);            // 開啟柵欄
            digitalWrite(redLed, LOW); 
            digitalWrite(greenLed, LOW);
            digitalWrite(buzzer, LOW);
            Serial.println("狀態：安全，柵欄開啟");
        }
        else if (__8__) {              // 如果距離在 10~20cm
            servo.write(90);          // 關閉柵欄
            digitalWrite(__9.1__, HIGH);  // 紅燈亮
            digitalWrite(__9.2__, LOW);   // 綠燈關
            tone(buzzer,100);   // 蜂鳴器響
            Serial.println("狀態：危險靠近，警示燈閃爍");
            delay(500);                    
            digitalWrite(__9.3__, LOW);   // 紅燈關
            digitalWrite(__9.4__, HIGH);  // 綠燈亮
            noTone(buzzer);    // 蜂鳴器停
            delay(500);
        }
        else {
            servo.write(90);          // 非常危險，完全關閉
            digitalWrite(redLed, HIGH);
            digitalWrite(greenLed, LOW);
            tone(buzzer,125);
            Serial.println("狀態：非常危險，快速警示");
            __10__;            // 快速閃爍，每0.1秒閃爍一次
            digitalWrite(redLed, LOW);
            digitalWrite(greenLed, HIGH);
            noTone(buzzer);
            __10__;           // 快速閃爍，每0.1秒閃爍一次
        }
    }
}
```

## Problem 1 設定序列通訊鮑率

```arduino=13
void setup() {
    Serial.__1__(9600);               // 設定序列通訊鮑率為 9600
    pinMode(trigPin, OUTPUT);         // TRIG 設為輸出
    pinMode(echoPin, INPUT);          // ECHO 設為輸入
    pinMode(redLed, OUTPUT);          // 紅色 LED 設為輸出
```

:::success
Problem １ :
選項 >> 只有一個是對的喔!
:::


> A )  `start`
> 
> 
> B )  `begin` 
> 
> C )  `end`  
> 
> D )  `print`  
> 

## Problem 2 設定上拉電阻

```arduino=19
pinMode(buzzer, OUTPUT);          // 蜂鳴器設為輸出
pinMode(button, __2__);           // 按鈕腳位設為輸入，使用內部上拉電阻
```

:::success
Problem 2 :
選項 >> 只有一個是對的喔!
:::
> A )  `INPUT`
> 
> 
> B )  `OUTPUT` 
> 
> C )  `INPUT_PULLUP`
> 
> D )  `OUTPUT_PULLUP`
> 

## Problem 3 連接伺服馬達

```arduino=21
servo.__3__(servoPin);            // 將伺服馬達接到指定腳位
servo.write(0);                   // 初始設為 0 度（柵欄打開）
```

:::success
Problem 3 :
選項 >> 只有一個是對的喔!
:::


> A )  `Write`
> 
> 
> B )  `Attach`
> 
> C )  `write` 
> 
> D )  `attach` 
> 

## Problem 4 緊急按鈕觸發條件

```arduino=31
if(__4__){                      // 如果按鈕被按下
  servo.write(0);               // 馬達轉到開啟角度
  digitalWrite(redLed, HIGH);   // 紅燈亮
  digitalWrite(greenLed, HIGH); // 綠燈亮
```

:::success
Problem 4 :
選項 >> 只有一個是對的喔!
:::
> A )  `buttonSTATE == LOW`
> 
> 
> B )  `buttonState == LOW` 
> 
> C )  `ButtonState == HIGH`
> 
> D )  `buttonState == 1`
> 

## Problem 5 蜂鳴器發聲

```arduino=34
digitalWrite(greenLed, HIGH);// 綠燈亮
__5.1__(buzzer, 500);        // 蜂鳴器發出聲音（500Hz）
Serial.println("狀態：緊急按鈕按下，強制停止");
}
```
```arduino=46
Serial.print("測得距離: ");
Serial.print(distance);
Serial.println(" cm");
__5.2__(buzzer);            // 蜂鳴器關閉
```

:::success
Problem 5 :
選項 >> 只有一個是對的喔!
:::
```
__5.1__ / __5.2__
```

> A )  `tone` / `notone`
> 
> 
> B )  `TONE` / `noTone`
> 
> C )  `tone` / `noTone` 
> 
> D )  `TONE` / `noTone` 
> 

## Problem 6 發出超音波

```arduino=39
digitalWrite(trigPin, __6.1__);  // 送出超音波
delayMicroseconds(10);           // 等 10 微秒
digitalWrite(trigPin, __6.2__);  // 停止送出超音波
```

:::success
Problem 6 :
選項 >> 只有一個是對的喔!
:::
```
__6.1__ / __6.2__
```

> A )  `High` / `Low`
> 
> 
> B )  `Low` / `High` 
> 
> C )  `LOW` / `HIGH`
> 
> D )  `HIGH` / `LOW`
> 

## Problem 7 距離公式

```arduino=43
duration = pulseIn(echoPin, HIGH);    // 偵測回音時間
distance = __7__ * 0.034 / 2;         // 計算距離（cm）
```

:::success
Problem 7 :
選項 >> 只有一個是對的喔!
:::
> A )  `duration`
> 
> 
> B )  `DuRaTiOn`
> 
> C )  `dUrAtIoN` 
> 
> D )  `DURATION` 
> 

## Problem 8 中距離狀態條件

```arduino=53
digitalWrite(greenLed, LOW);
digitalWrite(buzzer, LOW);
Serial.println("狀態：安全，柵欄開啟");
} 
else if (__8__) {              // 如果距離在 10~20cm
  servo.write(90);             // 關閉柵欄
```

:::success
Problem 8 :
選項 >> 只有一個是對的喔!
:::
> A )  `distance <= 10`
> 
> 
> B )  `distance < 10` 
> 
> C )  `distance > 10`
> 
> D )  `distance > 100`
> 

## Problem 9 LED閃爍

```arduino=58
servo.write(90);          // 關閉柵欄
digitalWrite(__9.1__, HIGH);  // 紅燈亮
digitalWrite(__9.2__, LOW);   // 綠燈關
tone(buzzer, 100);      // 蜂鳴器響
Serial.println("狀態：危險靠近，警示燈閃爍");
delay(500);
digitalWrite(__9.3__, LOW);   // 紅燈關
digitalWrite(__9.4__, HIGH);  // 綠燈亮
noTone(buzzer);   // 蜂鳴器停
delay(500);
```

:::success
Problem 9 :
選項 >> 只有一個是對的喔!
:::
```
__9.1__ / __9.2__ / __9.3__ / __9.4__
```

> A )  `redLed` / `redLed` / `greenLed` / `greenLed`
> 
> 
> B )  `redLed` / `greenLed` / `redLed` / `greenLed` 
> 
> C )  `greenLed` / `greenLed`  / `redLed` / `redLed` 
> 
> D )  `redLed` / `greenLed`  / `greenLed`/ `redLed` 
> 


## Problem 10 LED閃爍時間控制

```arduino=70
else {
  servo.write(90);  // 非常危險，完全關閉
  digitalWrite(redLed, HIGH);
  digitalWrite(greenLed, LOW);
  tone(buzzer,125);
  Serial.println("狀態：非常危險，快速警示");
  __10__;           // 快速閃爍，每0.1秒閃爍一次
  digitalWrite(redLed, LOW);
  digitalWrite(greenLed, HIGH);
  noTone(buzzer);
  __10__;           // 快速閃爍，每0.1秒閃爍一次
}
```
---
:::success
Problem 10 :
選項 >> 只有一個是對的喔!
:::


> A )  `delay(100)`
> 
> 
> B )  `delay(0.1)`
> 
> C )  `Delay(100)`
> 
> D )  `Delay(0.1)`
> 

# Lab2 打地鼠

![螢幕擷取畫面 2025-06-29 224044](https://hackmd.io/_uploads/ByjzZA04xl.png)
![Arduino (6)](https://hackmd.io/_uploads/r1-Xb0R4lg.jpg)
![image](https://hackmd.io/_uploads/HkRYFMWHgx.png)



## 程式碼

```arduino=
// 定義四個 LED 的腳位
int UpLed = 2;        // 上方LED腳位
int RightLed = 3;     // 右方LED腳位
int DownLed = 4;      // 下方LED腳位
int LeftLed = 5;      // 左方LED腳位

// 定義搖桿的類比輸入腳位
int joyX = A0;  // 搖桿 X 軸
int joyY = A1;  // 搖桿 Y 軸
int joySw = 7;  // 搖桿按鈕

// 蜂鳴器腳位
int buzzer = 6;  

// LED 腳位陣列
int ledPins[] = {UpLed, RightLed, LeftLed, DownLed};  

int activeLED = -1;  // 記錄當前點亮的 LED
int lastLED = -1;    // 記錄上一顆點亮的 LED
int validCount = 0;  // 記錄正確關閉 LED 次數
int penaltyCount = 0; // 記錄錯誤扣分
int r = 2;  // 得分倍率

bool gameStarted = false;  // 遊戲是否開始
unsigned long startTime = 0;  // 記錄遊戲開始時間
int gameDuration = 15000;  // 遊戲時間 15 秒

unsigned long lastButtonPress = 0;  // 記錄上次按下按鈕的時間
unsigned long debounceDelay = 200;  // Debounce 延遲 200 毫秒

unsigned long lastLedActionTime = 0;  // 記錄上次關閉 LED 的時間
unsigned long ledCooldown = 200;  // LED 冷卻時間 200 毫秒，避免過快連續操作

//函數宣告
void playStartCountdown();
void lightRandomLED(); 
void playEndTone();
void turnOffAllLEDs();
void checkJoystick();

void setup() {
    __1__(9600);  // 設定序列埠，用於輸出訊息
    // 設定 LED 腳位為輸出
    pinMode(UpLed, OUTPUT);
    pinMode(LeftLed, OUTPUT);
    pinMode(RightLed, OUTPUT);
    pinMode(DownLed, OUTPUT);    
    pinMode(joySw, __2__ );  // 設定搖桿按鈕為輸入
    pinMode(buzzer, OUTPUT);  // 設定蜂鳴器腳位為輸出
    Serial.println("按下 Joystick 中間鍵開始遊戲");
}

void loop() {
    if (!gameStarted) {  // 如果遊戲尚未開始
        // 等待玩家按下搖桿按鈕啟動遊戲
        if ( ( __3__ ) && ( __4__ ) ) { //當(按鈕按下時)且(Debounce)
            delay(1000);
            lastButtonPress = millis();  // 記錄按下時間
            gameStarted = true;  // 設定遊戲開始
            validCount = 0;
            penaltyCount = 0;
            startTime = millis();  // 記錄遊戲開始時間
            playStartCountdown();
            Serial.println("遊戲開始！15 秒內關掉最多 LED");
            lightRandomLED();  // 隨機點亮一顆 LED
        }
    } 
    else {
        // 檢查遊戲是否已達時間限制
        if ( __5__ ) {
            Serial.print("遊戲結束！你關掉了 ");
            Serial.print(validCount);
            Serial.print(" 顆 LED，錯誤扣分: ");
            Serial.println(penaltyCount);
            Serial.print("<總得分>：");
            Serial.println(validCount * r + penaltyCount);  // 計算總得分
            playEndTone();
            gameStarted = false;  // 遊戲結束
            turnOffAllLEDs();  // 關閉所有 LED
            Serial.println("按下 Joystick 中間鍵重新開始");
        } 
        else {
            checkJoystick();  // 檢查搖桿輸入
        }
    }
}

void checkJoystick() {
    int xVal = analogRead(joyX);  // 讀取搖桿 X 軸數值
    int yVal = analogRead(joyY);  // 讀取搖桿 Y 軸數值
    
    /*debug用
    Serial.print("Xpos : ");
    Serial.println(xVal);
    Serial.print("Ypos : ");
    Serial.println(yVal);*/
    
    // 確保 LED 點亮，且符合冷卻時間
    if ( __6__ ) {
        bool correctMove = false;  // 是否為正確的移動
        bool moved = false;  // 是否有移動搖桿
        
        // 判斷是否有移動搖桿
        if ( __7.1__ || __7.2__ || __7.3__ ||　__7.4__ ) {
            moved = true;
        }

        // 檢查移動方向是否與 LED 位置匹配
        if( __8__ ) {
        /*
        如果點亮的是 UpLed，則應該向上推
        如果點亮的是 RightLed，則應該向右推
        如果點亮的是 LeftLed，則應該向左推
        如果點亮的是 DownLed，則應該向下推
        */
            correctMove = true;
        }

        if (moved) {  // 如果有移動搖桿
            if (correctMove) {  // 如果移動方向正確
                turnOffAllLEDs();  // 關閉所有 LED
                delay(100);
                validCount++;  // 增加正確關閉計數
                Serial.print("LED 關閉數量: ");
                Serial.println(validCount);             
                lightRandomLED();  // 再次隨機點亮 LED
            } 
            else {  // 如果移動方向錯誤
                penaltyCount -= 5;  // 錯誤扣 5 分
                Serial.print("錯誤操作！目前扣分: ");
                Serial.println(penaltyCount);
                
            }
            lastLedActionTime = millis();  // 記錄這次操作的時間
        }
    }
}

// 隨機點亮一顆 LED
void lightRandomLED() {
    activeLED = random(0, 4);  // 產生 0~3 之間的隨機數，選擇要點亮的 LED
    digitalWrite( __9.1__, __9.2__ );
}

// 關閉所有 LED
void turnOffAllLEDs() {
    for (int i = 0; i < 4; i++) {
         __10__ ;
    }
}

// 🎵 遊戲開始音效
void playStartCountdown() {
    for (int i = 3; i > 0; i--) {
        __11.1__
        __11.2__ // 發出 1000 Hz 音調 300ms
        noTone(buzzer);
        delay(1000);  // 等待 1 秒
    }
    __11.3__
    __11.4__ // 發出 1500 Hz 音調 500ms
    noTone(buzzer); 
    delay(500);
}

// 🎵 遊戲結束音效
void playEndTone() {
    tone(buzzer, 500);
    delay(300); 
    noTone(buzzer); 
    delay(400);
    tone(buzzer, 300);  
    delay(500); 
    noTone(buzzer);
}
```
### Problem 1 設定序列埠，用於輸出訊息

```arduino=34
void setup() {
  __1__(9600); // 設定序列埠，用於輸出訊息
}
```

:::success
Problem 1 :
選項 >> 只有一個是對的喔!
:::


> A )  `Serial.write`
> 
> 
> B )  `Serial.print`
> 
> C )  `Serial.begin`
> 
> D )  `Serial.end`
> 

---
### Problem 2 設定搖桿按鈕為輸入

```arduino=41
pinMode(joySw, __2__ );  // 請根據你拿到的搖桿選擇正確答案。
```

### Hint :
**黑色搖桿需要**給予上拉電阻（否則電位會浮動）。
**紅色搖桿不需**給予上拉電阻，只須設定該腳位為輸入。
:::success
Problem 2 :
請根據你拿到的搖桿選擇正確答案。
:::
**黑色搖桿：**`INPUT_PULLUP` 
**紅色搖桿：**`INPUT`
### Problem 3 當按鈕按下時

```arduino=49
if ( ( __3__ ) && ( __4__ ) ) { //當(按鈕按下時)且(Debounce)
//code
}
```


### Hint :
**黑色搖桿**有被給予上拉電阻，因此當按鈕按下時，使用digitalRead函式會讀取到低電位。
**紅色搖桿**預設連接到GND，因此當按鈕按下時，使用digitalRead函式會讀取到高電位。
:::success
Problem 3 :
選項 >> 請根據你拿到的搖桿選擇正確答案。
:::
**黑色搖桿：**`digitalRead(joySw) == LOW` 
**紅色搖桿：**`digitalRead(joySw) == HIGH`

---
### Problem 4 Debounce

```arduino=49
if ( ( __3__ ) && ( __4__ ) ) { //當(按鈕按下時)且(Debounce)
//code
}
```

:::success
Problem 4 :
選項 >> 只有一個是對的喔!
:::


> A ) `millis() - lastButtonPress < debounceDelay`
> 
> 
> B ) `millis() - lastButtonPress > debounceDelay`
> 
> C ) `lastButtonPress < debounceDelay`
> 
> D ) `lastButtonPress > debounceDelay`
> 

### Problem 5 檢查遊戲是否已達時間限制

```arduino=62
// 檢查遊戲是否已達時間限制
if ( __5__ ) {
//code
}
```

:::success
Problem 5 :
選項 >> 只有一個是對的喔!
:::



> 
> A ) `startTime <= gameDuration`
> 
> B ) `startTime > gameDuration`
> 
> C ) `millis() - startTime < gameDuration`
> 
> D ) `millis() - startTime >= gameDuration`
> 
---

### Problem 6 確保 LED 點亮，且符合冷卻時間

```arduino=91
// 確保 LED 點亮，且符合冷卻時間
if ( __6__ ) {
  //code
}
```
:::success
Problem 6 :
選項 >> 只有一個是對的喔!
:::

> A ) `activeLED == -1 && (millis() - lastLedActionTime) > ledCooldown`
> 
> 
> B ) `activeLED != -1 && (millis() - lastLedActionTime) > ledCooldown`
> 
> C ) `activeLED == -1 && lastLedActionTime > ledCooldown`
> 
> D ) `activeLED != -1 && lastLedActionTime > ledCooldown`
> 

### Problem 7 判斷是否有移動搖桿
```arduino=96
// 判斷是否有移動搖桿
if ( __7.1__ || __7.2__ || __7.3__ || __7.4__ ) {
  moved = true;
}
```
:::success
Problem 7 :
選項 >> 只有一個是對的喔!
:::
```
__7.1__ || __7.2__ || __7.3__ || __7.4__
```


> A ) `yVal < 200 || yVal > 800 || xVal < 200 || xVal > 800`
> 
> 
> B ) `yVal < 200 || yVal < 800 || xVal > 200 || xVal > 800`
> 
> C ) `yVal > 200 || yVal < 800 || xVal > 200 || xVal < 800`
> 
> D ) `yVal > 200 || yVal > 800 || xVal < 200 || xVal < 800`
> 

---
### Problem 8 檢查移動方向是否與 LED 位置匹配
```arduino=101
// 檢查移動方向是否與 LED 位置匹配
if( __8__ ) 
/*
如果點亮的是 UpLed，則應該向上推
如果點亮的是 RightLed，則應該向右推
如果點亮的是 LeftLed，則應該向左推
如果點亮的是 DownLed，則應該向下推
*/
    correctMove = true;
}
```
### Hint :
![image](https://hackmd.io/_uploads/HkRYFMWHgx.png)
**黑色搖桿：**
1. 往上推：`xVal > 800`
2. 往右推：`yVal > 800`
3. 往左推：`yVal < 200`
4. 往下推：`xVal < 200`

**紅色搖桿：**
1. 往上推：`yVal < 200`
2. 往右推：`xVal > 800`
3. 往左推：`xVal < 200`
4. 往下推：`yVal > 800`
:::success
Problem 8 : 
選項 >> 請根據你拿到的搖桿選擇正確答案。
:::
**黑色搖桿：** `( activeLED == 0 && xVal > 800 ) || ( activeLED == 1 && yVal > 800 ) || ( activeLED == 2 && yVal < 200 ) || ( activeLED == 3 && xVal < 200 )`
**紅色搖桿：** `( activeLED == 0 && yVal < 200 ) || ( activeLED == 1 && xVal > 800 ) || ( activeLED == 2 && xVal < 200 ) || ( activeLED == 3 && yVal > 800 )`

### Problem 9 隨機點亮一顆 LED

```arduino=129
// 隨機點亮一顆 LED
void lightRandomLED() {
  activeLED = random(0, 4); // 產生 0~3 的隨機數
  digitalWrite( __9.1__, __9.2__ );
}
```

:::success
Problem 9 :
選項 >> 只有一個是對的喔!
:::
```
__9.1__ / __9.2__
```

> A ) `ledPins[activeLED] / HIGH`
> 
> 
> B ) `ledPins[activeLED] / LOW`
> 
> C ) `ledPins[millis()] / HIGH`
> 
> D ) `ledPins[gameDuration] / LOW`
> 

---

### Problem 10 關閉所有 LED

```arduino=135
// 關閉所有 LED
void turnOffAllLEDs() {
  for (int i = 0; i < 4; i++) {
    __10__;
  }
```

:::success
Problem 10 :
選項 >> 只有一個是對的喔!
:::

> A ) `digitalWrite(ledPins[j], LOW)`
> 
> 
> B ) `digitalWrite(ledPins[j], HIGH)`
> 
> C ) `digitalWrite(ledPins[i], LOW)`
> 
> D ) `digitalWrite(ledPins[i], HIGH)`
> 

### Problem 11 發出 1000 Hz 音調 300ms / 發出 1500 Hz 音調 500ms

```arduino=142
// 🎵 遊戲開始音效
void playStartCountdown() {
    for (int i = 3; i > 0; i--) {
        __11.1__
        __11.2__ // 發出 1000 Hz 音調 300ms
        noTone(buzzer);
        delay(1000);  // 等待 1 秒
    }
    __11.3__
    __11.4__ // 發出 1500 Hz 音調 500ms
    noTone(buzzer); 
    delay(500);
}
```

:::success
Problem 11 :
選項 >> 只有一個是對的喔!
:::
```
__11.1__ / __11.2__ / __11.3__ / __11.4__
```

> A ) `delay(300); / tone(buzzer, 1000); / tone(buzzer, 1500); / delay(500);`
> 
> 
> B ) `delay(300); / tone(buzzer, 1000); / delay(500); / tone(buzzer, 1500);`
> 
> C ) `tone(buzzer, 1000); / delay(300); / tone(buzzer, 1500); / delay(500);`
>
> D ) `tone(buzzer, 1000); / delay(300); / delay(500); / tone(buzzer, 1500);`
>