# 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亮度 --- ![螢幕擷取畫面 2026-01-08 154921](https://hackmd.io/_uploads/BJ5uVx8aWe.png) # Exercise 2 上數計數器 --- ![螢幕擷取畫面 2026-01-14 194002](https://hackmd.io/_uploads/Sky04gLp-x.png) ## 程式碼 ```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 超音波感測器 ![image](https://hackmd.io/_uploads/rk0x9DmJlg.png) --- ### 超音波感測器請兩個圈圈朝外方便感測(腳位順序如示意圖)。 ![image](https://hackmd.io/_uploads/rysTGb86Ze.png) ## 程式碼 ```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 伺服馬達 --- ![image](https://hackmd.io/_uploads/SkxLubU6-x.png) ## 程式碼 ```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 無源蜂鳴器 --- ![螢幕擷取畫面 2026-04-26 015742](https://hackmd.io/_uploads/HJ-MgFq6-e.png) --- :::warning 注意超音波感測器方向,要面向外側 ::: ![螢幕擷取畫面 2026-04-23 144733](https://hackmd.io/_uploads/rJ1kHHPTWe.png =45%x)![螢幕擷取畫面 2026-04-23 150608](https://hackmd.io/_uploads/rkmeSBvpZl.png =55%x) ## 程式碼 ```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 搖桿 --- ![螢幕擷取畫面 2026-04-23 060831](https://hackmd.io/_uploads/SJStFtD6Wx.png) ![螢幕擷取畫面 2026-04-23 200315](https://hackmd.io/_uploads/Bky0KFvpbe.png) ![螢幕擷取畫面 2026-04-23 144544](https://hackmd.io/_uploads/B1RCtYwTbe.png =70%x) ## 程式碼 ```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: 智慧自動門 ### 範例接線圖 ![螢幕擷取畫面 2026-04-22 175941](https://hackmd.io/_uploads/rJl42fUTbe.png) ### 📝 任務說明 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 憤怒鳥彈射模擬器 ![image](https://hackmd.io/_uploads/ByfxnWU6Zx.png) ### 注意:四顆LED(豬豬)的位置 ![image](https://hackmd.io/_uploads/rk5Uh-8pbg.png) ## 程式碼 ```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 : ![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);` >