高三多元選修科技應用專題

平交道程式設計
 avatar
unknown
c_cpp
16 days ago
5.0 kB
6
Indexable
#include <Servo.h>  // 引入控制伺服馬達的函式庫

// 定義蜂鳴器使用的兩個音調頻率(單位 Hz)
#define NOTE_G5 784
#define NOTE_F5 698

// 設定 LED、蜂鳴器與按鈕的接腳編號
const int yellowLED = 4;
const int redLED = 8;
const int greenLED = 12;
const int buzzer = 2;
const int button = A1;

// 馬達設定
Servo motor;               // 宣告伺服馬達物件
const int MOTOR_PIN = 11;  // 馬達控制腳位

// 設定馬達控制的 PWM 值(數值大約 0~180 之間)
const int MOTOR_CW = 60;     // 順時針轉動時的 PWM 值(較小代表順時針)
const int MOTOR_CCW = 130;   // 逆時針轉動時的 PWM 值(較大代表逆時針)
const int MOTOR_STOP = 90;   // 停止轉動時的 PWM 值

// 控制馬達轉動的時間(以毫秒為單位)
const int rotationTime = 3750;          // 順時針轉動 540 度所需時間
const int rotationTimeReverse = 4100;   // 逆時針轉動 540 度所需時間(略長以補轉速差)
const int motorHoldTime = 5000;         // 停止等待時間 5 秒

// 用於紀錄計時的變數
long motorStartTime, warningStartTime, buzzerStartTime;

// 紅黃燈交替、蜂鳴器交替的切換時間
const int warningDelay = 250;   // 紅黃燈交替頻率(250ms)
const int buzzerDelay = 500;    // 蜂鳴器交替頻率(500ms)

// 狀態控制:w=等待、d=正轉、p=等待、u=逆轉
char state = 'w';

// 控制燈與蜂鳴器的開關狀態
bool redLightOn = false;
bool buzzerToneG5 = true;

void setup() {
    Serial.begin(9600);  // 啟動序列埠,方便除錯輸出

    // 設定腳位模式
    pinMode(buzzer, OUTPUT);
    pinMode(yellowLED, OUTPUT);
    pinMode(redLED, OUTPUT);
    pinMode(greenLED, OUTPUT);
    pinMode(button, INPUT);

    // 馬達初始化為停止
    motor.attach(MOTOR_PIN);
    motor.write(MOTOR_STOP);

    // 初始顯示為綠燈亮
    digitalWrite(greenLED, HIGH);
    digitalWrite(redLED, LOW);
    digitalWrite(yellowLED, LOW);
}

void loop() {
    // 顯示目前狀態於序列監控視窗
    Serial.print("狀態: ");
    Serial.println(state);

    // === 等待啟動狀態(w)===
    if (state == 'w') {
        noTone(buzzer);                   // 停止蜂鳴器
        digitalWrite(greenLED, HIGH);    // 綠燈常亮
        digitalWrite(redLED, LOW);       
        digitalWrite(yellowLED, LOW);
        motor.write(MOTOR_STOP);         // 馬達不轉

        // 按鈕被按下後,切換到正轉(d)狀態
        if (digitalRead(button) == LOW) {
            state = 'd';
            motorStartTime = millis();   // 記錄開始時間
        }
    }

    // === 正轉、等待、逆轉階段中通用的:紅黃燈交替與蜂鳴器 ===
    if (state == 'd' || state == 'p' || state == 'u') {
        // 紅黃燈交替閃爍
        if (millis() - warningStartTime >= warningDelay) {
            redLightOn = !redLightOn;  // 交替狀態切換
            digitalWrite(redLED, redLightOn ? HIGH : LOW);
            digitalWrite(yellowLED, redLightOn ? LOW : HIGH);
            digitalWrite(greenLED, LOW);  // 綠燈熄滅
            warningStartTime = millis();
        }

        // 蜂鳴器交替播放 G5 和 F5
        if (millis() - buzzerStartTime >= buzzerDelay) {
            if (buzzerToneG5) {
                tone(buzzer, NOTE_G5, 400);
            } else {
                tone(buzzer, NOTE_F5, 400);
            }
            buzzerToneG5 = !buzzerToneG5;
            delay(100);        // 小延遲,避免音調黏在一起
            noTone(buzzer);    // 停止音調
            buzzerStartTime = millis();
        }
    }

    // === 正轉狀態(d) ===
    if (state == 'd') {
        Serial.println("馬達: 順時針旋轉");
        motor.write(MOTOR_CW);  // 馬達順時針轉
        if (millis() - motorStartTime >= rotationTime) {
            // 時間到 → 停止,進入等待狀態(p)
            state = 'p';
            motor.write(MOTOR_STOP);
            Serial.println("馬達: 停止");
            motorStartTime = millis();  // 重置時間
        }
    }

    // === 停止狀態(p) ===
    if (state == 'p') {
        motor.write(MOTOR_STOP);  // 保持馬達停止
        if (millis() - motorStartTime >= motorHoldTime) {
            state = 'u';  // 進入逆轉狀態
            motorStartTime = millis();
        }
    }

    // === 逆轉狀態(u) ===
    if (state == 'u') {
        Serial.println("馬達: 逆時針旋轉");
        motor.write(MOTOR_CCW);  // 馬達逆時針轉
        if (millis() - motorStartTime >= rotationTimeReverse) {
            // 逆轉完成 → 回到等待狀態(w)
            state = 'w';
            motor.write(MOTOR_STOP);
            Serial.println("馬達: 停止");
            digitalWrite(greenLED, HIGH);  // 恢復綠燈常亮
        }
    }
}
Editor is loading...
Leave a Comment