# 2026 陽明交大電機營 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亮度
---

# Exercise 2 上數計數器
---

## 程式碼
```arduino=
int pushbutton = 7; //設定按鈕的接腳
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___ //讓程式暫停100毫秒後再繼續讀取
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___ //讓程式暫停100毫秒後再繼續讀取
times++; //計次數加1
___3___ //在視窗列印出計次數並換行
}
```
<aside>
:::success
Problem 2 :
選項 >> 只有一個是對的喔!
</aside>
> A ) `delay(100);`
>
>
> B ) `Delay(100);`
>
> C ) `Debounce(times);`
>
> D ) `Debounce(buttonState);`
>
## Problem 3 在序列埠監控視窗列印出計次數並換行
```arduino=11
if(buttonState == 0 && beforeState == 1){ //當按鈕被按下時執行
___2___ //讓程式暫停100毫秒後再繼續讀取
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 超音波感測器

---
### 超音波感測器請兩個圈圈朝外方便感測(腳位順序如示意圖)。

## 程式碼
```arduino=
int trig_pin=13;//觸發接口接13腳位
int echo_pin=12;//回聲接口接12腳位
void setup()
{
Serial.begin(9600);//初始化鮑率
__1.1__
__1.2__
}
void loop()
{
digitalWrite(trig_pin,__2.1__);//輸入10微秒的啟動脈衝
delayMicroseconds(10);
digitalWrite(trig_pin,__2.2__);
long duration=pulseIn(echo_pin,HIGH);//引用函式計算時間
long distant=__3__;//利用速度、時間計算距離
Serial.print("Distant : ");//輸出結果
Serial.print(distant);
Serial.println(" cm");
delay(2000);//延遲2000毫秒
}
```
## Problem 1 設定腳位的模式
```arduino=4
void setup()
{
Serial.begin(9600);//初始化鮑率
__1.1__
__1.2__
}
```
<aside>
:::success
Problem 1 :
選項 >> 只有一個是對的喔!
</aside>
```
__1.1__ / __1.2__
```
> A ) `pinMode(trig_pin,OUTPUT);` / `pinMode(echo_pin,OUTPUT);`
>
> B ) `pinMode(trig_pin,INPUT);` / `pinMode(echo_pin,INPUT);`
>
> C ) `pinMode(trig_pin,OUTPUT);` / `pinMode(echo_pin,INPUT);`
>
> D ) `pinMode(trig_pin,INPUT);` / `pinMode(echo_pin,OUTPUT);`
>
## Problem 2 設定10微秒啟動脈衝波
```arduino=13
digitalWrite(trig_pin,__2.1__);//調成高電位
delayMicroseconds(10); //延遲10微秒
digitalWrite(trig_pin,__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=17
long duration=pulseIn(echo_pin,HIGH);//引用函式計算時間
long distant=__3__;//利用速度、時間計算距離
```
<aside>
:::success
Problem 3 :
選項 >> 只有一個是對的喔!
</aside>
> A ) `0.0346*duration/2`
>
>
> B ) `0.0346*duration`
>
> C ) `346*duration/2`
>
> D ) `duration * 346`
>
# Exercise 4 伺服馬達
---

## 程式碼
```arduino=
#include <Servo.h>
Servo my_servo;//宣告物件
int spin=10;//一次轉多少角度(請不要自己調整參數)
int angle=0;//初始角度
void setup()
{
__1__//signal接9腳位
}
void loop()
{
my_servo.write(angle);
angle=angle + spin;
if(__2__)//如果超過轉動範圍就換方向
{
spin=spin*(-1);//換方向
}
delay(500);//請不要自己調整參數
}
```
## Problem 1 設定伺服馬達的腳位
```arduino=6
void setup()
{
__1__//signal接9腳位
}
```
<aside>
:::success
Problem 1 :
選項 >> 只有一個是對的喔!
</aside>
> A ) `attach(9);`
>
>
> B ) `my_servo.write(9);`
>
> C ) `my_servo.attach(9);`
>
> D ) `pinMode(9,INPUT);`
>
## Problem 2 判斷旋轉角度是否到邊界
```arduino=16
if(__2__)//如果超過轉動範圍就換方向
{
spin=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 無源蜂鳴器
---

---
:::warning
注意超音波感測器方向,要面向外側
:::

## 程式碼
```arduino=
//宣告腳位
int TRIG = 12; // 超音波模組的Trig腳位
int ECHO = 11; // 超音波模組的Echo腳位
int BUZZER = 9; // 無源蜂鳴器腳位
double distance();
void setup() {
pinMode(TRIG, __1.1__);
pinMode(ECHO, __1.2__);
pinMode(BUZZER, __1.3__);
Serial.begin(9600); // 開啟序列埠監視器(檢查程式用)
}
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);
__2.2__(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__ / __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);
__2.2__(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 搖桿
---



## 程式碼
```arduino=
#include <Servo.h>
// 定義腳位
int Xpin = A1;
int Ypin = A2; // 目前沒用到,但保留
int swPin = A3; // 搖桿按鈕
int buzzer = 11;
int servoPin = 3;
int servoPos = 0;
int Xvalue;
Servo myServo;
void setup() {
Serial.begin(9600);
myServo.attach(servoPin);
pinMode(Xpin, INPUT);
pinMode(Ypin, INPUT);
pinMode(swPin, INPUT_PULLUP); // 使用內建上拉電阻
pinMode(buzzer, OUTPUT);
}
void loop() {
// 1. 讀取搖桿x方向數值(0~1023)
Xvalue = __1.1__;
// 2. 使用 map 函式將 X 軸 (0-1023) 轉換為馬達角度 (0-180)
servoPos = __2.1__;
// 3. 控制馬達轉動
myServo.write(servoPos);
// 4. 判斷邊界值發出高頻聲音 (大於 1000 或 小於 20)
if (Xvalue > 1000 || Xvalue < 20) {
tone(buzzer, 2000); // 發出 2000Hz 的高音
} else {
noTone(buzzer); // 正常範圍內停止發聲
}
/*5. 序列埠輸出(方便除錯)
Serial.print("X-axis: ");
Serial.print(Xvalue);
Serial.print(" | Servo Angle: ");
Serial.println(servoPos);*/
delay(15); // 給予馬達反應時間
}
```
## Problem 1 讀取搖桿數值
```arduino=27
// 1. 讀取搖桿x方向數值(0~1023)
Xvalue = __1.1__;
```
:::success
Problem 1 :
選項 >> 只有一個是對的喔!
:::
```
__1.1__
```
> A ) `analogRead(swPin)`
>
> B ) `analogRead(Xvalue)`
>
> C ) `analogRead(Ypin)`
>
> D ) `analogRead(Xpin)`
>
## Problem 2 搖桿數值轉換
```arduino=29
// 2. 使用 map 函式將 X 軸 (0-1023) 轉換為馬達角度 (0-180)
servoPos = __2.1__;
```
:::success
Problem 2 :
選項 >> 只有一個是對的喔!
:::
```
__2.1__
```
> A ) `map(XValue, 0, 180, 0, 1023)`
>
>
> B ) `Map(XValue, 0, 180, 0, 1023)`
>
> C ) `map(XValue, 0, 1023, 0, 180)`
>
> D ) `Map(XValue, 0, 1023, 0, 180)`
>
---
# Lab1 自動門
---
底下 Lab 的程式碼都會被挖空,請根據題目要求與註解提示,將正確的程式碼填入 `___` 中完成任務!
## Lab: 智慧自動門
### 範例接線圖

### 📝 任務說明
1. 利用超音波感測器讀取距離。
2. 距離小於 15 公分時,伺服馬達轉動至 90 度開門。
3. 開門狀態下,**紅燈閃爍**且**蜂鳴器發出警報**,同時系統不能卡住(需使用 millis)。
4. 人離開後,馬達歸零關門,綠燈恆亮。
### 💻 程式碼填空
```cpp=
#include <Servo.h>
// 硬體腳位定義
const int trigPin = 12;
const int echoPin = 11;
const int buzzerPin = 8;
const int redPin = 7;
const int greenPin = 6;
const int servoPin = 3;
// 變數與物件
/* 填空 1: 宣告一個伺服馬達的物件,命名為 myGate */
__1__ myGate;
float pingTime;
float distance;
int servoPos = 0;
bool isGateOpen = false;
// Millis 計時變數
unsigned long currentMillis = 0;
unsigned long previousBlinkTime = 0;
unsigned long previousBeepTime = 0;
int ledState = LOW;
int buzzerState = LOW;
void setup() {
Serial.begin(9600);
/* 填空 2: 設定 trigPin 為輸出模式 */
pinMode(trigPin, __2__);
pinMode(echoPin, INPUT);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
/* 填空 3: 將馬達物件連接到我們定義的 servoPin 腳位 */
myGate.__3__(servoPin);
myGate.write(0); // 初始狀態:門關閉
}
void loop() {
/* 填空 4: 取得 Arduino 開機運作到現在的毫秒數 */
currentMillis = __4__();
// 1. 觸發超音波發射
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// 接收回音並計算距離 (公分)
/* 填空 5: 讀取 echoPin 高電位持續的時間 */
pingTime = __5__(echoPin, HIGH);
distance = (pingTime * 0.0343) / 2;
// 2. 邏輯判斷
if (distance < 15 && distance > 0) {
// 【有人靠近:開門模式】
/* 填空 6: 判斷「如果門還沒有開」 (利用 ! 符號做反相) */
if (__6__) {
/* 填空 7: 命令伺服馬達轉動到 90 度的位置 */
myGate.__7__(90);
isGateOpen = true;
digitalWrite(greenPin, LOW); // 綠燈滅
}
// 非阻塞 LED 閃爍 (間隔 200ms)
/* 填空 8: 判斷目前時間與上次閃爍時間的差,是否達到 200 毫秒 */
if (currentMillis - previousBlinkTime >= __8__) {
previousBlinkTime = currentMillis;
if (ledState == LOW) ledState = HIGH; else ledState = LOW;
digitalWrite(redPin, ledState);
}
//設定聲音變化頻率
int alarmPitch = map(distance, 1, 15, 2000, 500);
// 使用 constrain 確保頻率不會因為稍微超出距離而亂叫
alarmPitch = constrain(alarmPitch, 500, 2000);
// 非阻塞 蜂鳴器警示 (間隔 100ms)
if (currentMillis - previousBeepTime >= 100) {
previousBeepTime = currentMillis;
if (buzzerState == LOW) {
buzzerState = HIGH;
/* 填空 9: 讓蜂鳴器發出 1000Hz 的聲音 */
__9__(buzzerPin, alarmPitch);
} else {
buzzerState = LOW;
/* 填空 10: 停止蜂鳴器的聲音 */
__10__(buzzerPin);
}
}
} else {
// 【無人:待機模式】
if (isGateOpen) {
myGate.write(0); // 關門
isGateOpen = false;
// 重置警示狀態
digitalWrite(redPin, LOW);
noTone(buzzerPin);
digitalWrite(greenPin, HIGH); // 綠燈恆亮
}
}
delay(50);
}
```
## Problem 1 宣告物件
```arduino=13
__1__ myGate;
float pingTime;
float distance;
int servoPos = 0;
bool isGateOpen = false;
```
:::success
Problem 1 :
在宣告伺服馬達物件時,應該使用哪一個關鍵字?(注意大小寫)
:::
> ( A ) `motor`
>
> ( B ) `Servo`
>
> ( C ) `servo`
>
> ( D ) `Motor`
## Problem 2 腳位模式設定
```arduino=30
pinMode(trigPin, __2__);
pinMode(echoPin, INPUT);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(buzzerPin, OUTPUT);
```
:::success
Problem 2 :
超音波感測器的 `trigPin` 負責發射超音波,請問在 `setup()` 中應將其腳位模式設為什麼?
:::
> ( A ) `INPUT`
>
> ( B ) `OUTPUT`
>
> ( C ) `INPUT_PULLUP`
>
> ( D ) `HIGH`
## Problem 3 連接伺服馬達
```arduino=37
myGate.__3__(servoPin);
myGate.write(0); //
```
:::success
Problem 3 :
要將伺服馬達物件綁定到特定的 Arduino 腳位上(例如 `servoPin`),應該呼叫哪一個函式?
:::
> ( A ) `pinMode()`
>
> ( B ) `bind()`
>
> ( C ) `connect()`
>
> ( D ) `attach()`
## Problem 4 緊急按鈕觸發條件
```arduino=43
currentMillis = __4__();
```
:::success
Problem 4 :
為了解決 `delay()` 會讓程式卡住的問題(非阻塞多工),我們使用哪一個函式來取得 Arduino 開機後經過的毫秒數?
:::
> ( A ) `time()`
>
> ( B ) `delay()`
>
> ( C ) `millis()`
>
> ( D ) `micros()`
## Problem 5 超音波測距
```arduino=54
pingTime = __5__(echoPin, HIGH);
distance = (pingTime * 0.0343) / 2;
```
:::success
Problem 5 :
在計算超音波回音時間時,我們使用哪一個函式來測量 `echoPin` 維持高電位(HIGH)的時間長度?
:::
> ( A ) `digitalRead()`
>
> ( B ) `analogRead()`
>
> ( C ) `pulseIn()`
>
> ( D ) `delayMicroseconds()`
## Problem 6 偵測開門
```arduino=62
if (__6__) {
myGate.__7__(90);
isGateOpen = true;
digitalWrite(greenPin, LOW); // 綠燈滅
}
```
:::success
Problem 6 :
程式中要判斷「如果門還沒有開」,下列哪一種條件判斷式的寫法是正確的?(已知 `isGateOpen` 為記錄門狀態的布林值變數)
:::
> ( A ) `if (!isGateOpen)`
>
> ( B ) `if (isGateOpen == true)`
>
> ( C ) `if (isGateOpen != false)`
>
> ( D ) `if (~isGateOpen)`
## Problem 7 馬達轉動
```arduino=62
if (__6__) {
myGate.__7__(90);
isGateOpen = true;
digitalWrite(greenPin, LOW); // 綠燈滅
}
```
:::success
Problem 7 :
當條件滿足要開啟閘門時,要命令伺服馬達轉動到 90 度的位置,應該呼叫伺服馬達的哪一個函式?
:::
> ( A ) `turn(90)`
>
> ( B ) `rotate(90)`
>
> ( C ) `angle(90)`
>
> ( D ) `write(90)`
## Problem 8 判斷時間差
```arduino=78
if (currentMillis - previousBlinkTime >= __8__) {
previousBlinkTime = currentMillis;
if (ledState == LOW) ledState = HIGH; else ledState = LOW;
digitalWrite(redPin, ledState);
}
```
:::success
Problem 8 :
根據任務要求,紅燈需要以 200 毫秒的間隔閃爍。在判斷時間差的條件式 `if (currentMillis - previousBlinkTime >= __8__)` 中應填入什麼數值?
:::
> ( A ) `100`
>
> ( B ) `200`
>
> ( C ) `1000`
>
> ( D ) `50`
## Problem 9 蜂鳴器警報
```arduino=84
if (buzzerState == LOW) {
buzzerState = HIGH;
__9__(buzzerPin, alarmPitch);
```
:::success
Problem 9 :
要讓蜂鳴器發出特定頻率(例如 alarmPitch 變數儲存的頻率)的警報聲,應該使用哪一個 Arduino 內建函式?
:::
> ( A ) `play()`
>
> ( B ) `sound()`
>
> ( C ) `beep()`
>
> ( D ) `tone()`
## Problem 10 警報結束
```arduino=91
__10__(buzzerPin);
```
---
:::success
Problem 10 :
當警示結束,或者在閃爍間隔內要讓蜂鳴器停止發聲(靜音),應該使用哪一個函式?
:::
> ( A ) `noTone()`
>
> ( B ) `stopTone()`
>
> ( C ) `mute()`
>
> ( D ) `noSound()`
# Lab2 憤怒鳥彈射模擬器

### 注意:四顆LED(豬豬)的位置

## 程式碼
```arduino=
#include <Servo.h> // 引入伺服馬達函式庫
Servo catapult; // 建立投石機馬達物件
const int joyX = A0; // 搖桿 X 軸
const int joyY = A1; // 搖桿 Y 軸
const int extButton = 7; // 外接按鈕接腳 (補彈/重置)
const int ledPig1 = 3; // 第 1 隻豬的 LED
const int ledPig2 = 4; // 第 2 隻豬的 LED
const int ledPig3 = 5; // 第 3 隻豬的 LED
const int ledPig4 = 6; // 第 4 隻豬的 LED
const int buzzer = 8; // 蜂鳴器
const int servoPin = 9; // 伺服馬達接腳
int ammo = 5; // 初始子彈數量
const int HIT_RADIUS = 100; // 炸彈命中判定範圍
const unsigned long TIME_LIMIT = 120000; // 遊戲限時 120 秒
// --- 使用「平行陣列」來記錄 4 隻豬的資訊 ---
float pigX[4] = { 150.0, 210.0, 210.0, 270.0 }; // X 座標
float pigY[4] = { 0.0, 200.0,-200.0, 0.0 }; // Y 座標
bool pigAlive[4] = { true, true, true, true }; // 存活狀態
int pigLedPin[4] = { ledPig1, ledPig2, ledPig3, ledPig4 }; // 對應 LED
bool isAiming = false; // 是否正在拉搖桿瞄準
int pullSide = 0; // 搖桿左右拉力
int pullForce = 0; // 搖桿前後拉力
unsigned long gameStartTime = 0; // 遊戲開始時間
bool gameOver = false; // 遊戲是否結束
int currentScore = 0; // 本局分數
int highScore = 0; // 歷史最高分
void setup() {
Serial.begin(9600); // 開啟序列埠看文字訊息
catapult.attach(servoPin); // 設定馬達
catapult.write(90); // 馬達歸位 (置中)
pinMode(extButton, INPUT_PULLUP); // 外接按鈕啟用內建上拉電阻
pinMode(ledPig1, OUTPUT); // 設定 4 顆 LED 為輸出
pinMode(ledPig2, OUTPUT);
pinMode(ledPig3, OUTPUT);
pinMode(ledPig4, OUTPUT);
pinMode(buzzer, OUTPUT); // 設定蜂鳴器為輸出
resetGame(); // 呼叫重置函式,準備開局
}
void loop() {
if (digitalRead(extButton) == LOW) { // 按鈕被按下
if (gameOver) {
resetGame(); // 遊戲結束就重新開始
} else {
ammo = 5; // 遊戲中則補充子彈
tone(buzzer, 1500, 100); delay(150); tone(buzzer, 2000, 150);
Serial.println(">>> 彈藥已補充!");
}
delay(400); // 防彈跳
}
if (gameOver) return; // 遊戲結束就暫停下方動作
unsigned long elapsedTime = millis() - gameStartTime;
if (elapsedTime >= TIME_LIMIT || checkAllPigsDead()) { // 時間到或豬全滅
endGame(elapsedTime);
return;
}
int currentSide = analogRead(joyX) - 512; // 讀取搖桿左右並置中
int currentForce = analogRead(joyY) - 512; // 讀取搖桿前後並置中
if (currentForce > 100 && ammo > 0) { // 往後拉且有子彈 (瞄準中)
isAiming = true;
pullSide = currentSide;
pullForce = currentForce;
float angleRad = atan2((float)pullForce, (float)pullSide); // 計算角度
int angleDeg = angleRad * 180.0 / PI;
catapult.write(constrain(180 - angleDeg, 0, 180)); // 馬達轉向
delay(50);
}
else if (isAiming && currentForce <= 50) { // 放開搖桿 (發射)
isAiming = false;
fireProjectile(pullForce, pullSide); // 執行發射
}
}
void fireProjectile(int pf, int ps) {
ammo--; // 扣子彈
catapult.write(90); // 馬達歸位
tone(buzzer, 1800, 150); // 發射音效
float landX = (pf * 0.75); // 計算落點 X
float landY = (ps * 0.75); // 計算落點 Y
bool hitThisTurn = false;
for (int i = 0; i < 4; i++) { // 巡視 4 隻豬
if (pigAlive[i]) { // 如果豬還活著
// 計算落點與豬的距離
float dist = sqrt(sq(landX - pigX[i]) + sq(landY - pigY[i]));
if (dist <= HIT_RADIUS) { // 如果在爆炸範圍內
pigAlive[i] = false; // 豬死掉
digitalWrite(pigLedPin[i], LOW); // 關燈
currentScore += 25; // 加分
}
}
}
}
bool checkAllPigsDead() {
for (int i = 0; i < 4; i++) if (pigAlive[i]) return false; // 還有活著的
return true; // 全滅
}
void endGame(unsigned long elapsed) {
gameOver = true;
int finalScore = currentScore;
if (checkAllPigsDead()) { // 全滅獲勝
int timeBonus = (120 - (elapsed / 1000)) * 10; // 計算時間獎勵
finalScore += timeBonus;
tone(buzzer, 2000); // 勝利音效
delay(500);
noTone(buzzer);
} else { // 時間到失敗
tone(buzzer, 300, 1000); // 失敗音效
}
if (finalScore > highScore) highScore = finalScore; // 更新最高分
}
void resetGame() {
ammo = 5;
currentScore = 0;
gameOver = false;
isAiming = false;
for (int i = 0; i < 4; i++) { // 把 4 隻豬復活
pigAlive[i] = true;
digitalWrite(pigLedPin[i], HIGH); // 重新開燈
}
gameStartTime = millis(); // 重新計時
}
```
### 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 :

**黑色搖桿:**
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);`
>