Arduino:有紅燈倒數計時的紅綠燈控制電路
功能
一開始縱向的紅色 LED 亮,伴隨著從 120 秒開始的倒數計時 ( 倒數秒數為 3 位數時不顯示,倒數至 2 位數即 99 秒時才開始顯示 ),且橫向的綠色 LED 同時跟著亮。當縱向的紅色 LED 倒數至 3 秒時,橫向的綠色 LED 熄滅,且橫向的黃色 LED 亮;當縱向的紅色 LED 倒數至 0 秒時 ( 不顯示 ),縱向的紅色 LED 熄滅,轉而縱向的綠色 LED 亮,且橫向的紅色 LED 亮,伴隨著從 120 秒開始的倒數計時( 一樣倒數秒數為 3 位數時不顯示,倒數至 2 位數即 99 秒時才開始顯示 )。當橫向的紅色 LED 倒數至 3 秒時,縱向的綠色 LED 熄滅,縱向的的黃色 LED 亮;當橫向的紅色 LED 倒數至 0 秒時 ( 不顯示 ),橫向的紅色 LED 熄滅,縱向的綠色 LED 亮,如此周而復始。
電路圖
圖一 有紅燈倒數計時的紅綠燈控制電路圖
程式碼
C/C++
bool RedOnLongitudinal = true; /* 初始狀態為縱向紅燈亮 */
const int scanPin[] = {5, 6, 7, 8}; /* 七段顯示器掃描訊號的輸出接腳為第 5、6、7、8 腳 */
const int dataPin = 10, latchPin = 11, clockPin = 12; /* 串列資料輸出接腳為第 10 腳;栓鎖訊號輸
出接腳為第 11 腳;移位脈波輸出接腳為第
12 腳 */
/* 數字 0 至 9 的共陽極七段顯示碼 */
const int sevenSegCode[ ] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
int dataOut[4] = {0, 0, 0, 0}; /* 縱向兩位數以及橫向兩位數的輸出輸出緩衝區,由左至右順序為
縱向的個位 (dataOut[0])、十位 (dataOut[1]) 、與橫向的個位
(dataOut[2])、十位 (dataOut[3]) */
unsigned long previousTime; /* 暫存系統時間的變數 */
unsigned long nowTime; /* 暫存系統時間的變數 */
int second = 0; /* 紀錄秒數的變數 */
int GreenLight_1 = 2; /* 輸出控制縱向綠色 LED 亮滅的輸出接腳為第 2 腳 */
int YellowLight_1 = 3; /* 輸出控制縱向黃色 LED 亮滅的輸出接腳為第 3 腳 */
int RedLight_1 = 4; /* 輸出控制縱向紅色 LED 亮滅的輸出接腳為第 4 腳 */
int GreenLight_2 = A0; /* 輸出控制橫向綠色 LED 亮滅的輸出接腳為第 A0 腳 */
int YellowLight_2 = A1; /* 輸出控制橫向黃色 LED 亮滅的輸出接腳為第 A1 腳 */
int RedLight_2 = A2; /* 輸出控制橫向紅色 LED 亮滅的輸出接腳為第 A2 腳 */
int RedLightLastingSecond = 120; /* 紅色 LED 亮的持續秒數 */
int GreenLightLastingSecond = 117; /* 綠色 LED 亮的持續秒數 */
int YellowLightLastingSecond = 3; /* 黃色 LED 亮的持續秒數 */
/* 〔注意〕:GreenLightLastingSecond +
YellowLightLastingSecond 必須等於
RedLightLastingSecond */
void display(); /* 宣告自定顯示函數 */
void calCountDigit(int count); /* 宣告找出計數值的十位數與個位數值 */
int scanDigitNum; /* 實際需要掃描的位數,可為 1 或 2 */
int countTenthsDigit; /* 暫存找出的計數值的十位數值 */
int remainder; /* 暫存在找出計數值的十位數與個位數值過程產生的餘數 */
int countUnitsDigit; /* 暫存找出的計數值的個位數值 */
int redLEDRemainTime; /* 紅色 LED 亮的剩餘秒數 */
void setup() {
/* 規劃輸出控制縱向與橫向紅黃綠 LED 的訊號接腳為輸出 */
pinMode(GreenLight_1, OUTPUT);
pinMode(YellowLight_1, OUTPUT);
pinMode(RedLight_1, OUTPUT);
pinMode(GreenLight_2, OUTPUT);
pinMode(YellowLight_2, OUTPUT);
pinMode(RedLight_2, OUTPUT);
for (int i = 0; i < 4; i++){
pinMode(scanPin[i], OUTPUT); /* 規劃第 5、6、7、8 的掃瞄接腳為輸出 */
digitalWrite(scanPin[i], 1); /* 初始狀態:第 5、6、7、8 腳停止掃描,故分別送出邏輯 1 } 訊號*/
pinMode(dataPin, OUTPUT); /* 規劃第 10 腳為輸出 */
pinMode(clockPin, OUTPUT); /* 規劃第 12 腳為輸出 */
pinMode(latchPin, OUTPUT); /* 規劃第 11 腳為輸出 */
digitalWrite(RedLight_1, HIGH); /* 初始狀態縱向紅色 LED 亮 */
digitalWrite(YellowLight_1, LOW); /* 初始狀態縱向黃色 LED 熄 */
digitalWrite(GreenLight_1, LOW); /* 初始狀態縱向綠色 LED 熄 */
digitalWrite(RedLight_2, LOW); /* 初始狀態橫向紅色 LED 熄 */
digitalWrite(YellowLight_2, LOW); /* 初始狀態橫向黃色 LED 熄 */
digitalWrite(GreenLight_2, HIGH); /* 初始狀態橫向綠色 LED 亮 */
previousTime = millis(); /* 取得系統從開始至今歷經的時間 (單位毫秒) */
redLEDRemainTime = RedLightLastingSecond-second; /* 找出紅色 LED 亮的剩餘時間 */
}
void loop() {
nowTime = millis(); /* 取得系統從開始至今歷經的時間 (單位毫秒) */
display(); /* 呼叫顯示函式 */
if ((nowTime - previousTime) >= 1000 ){ /* 如果已過 1 秒的時間 */
previousTime = nowTime;
second++; /* 歷經的秒數遞加一 */
redLEDRemainTime = RedLightLastingSecond-second; /* 找出紅色 LED 亮的剩餘秒數 */
if (second == GreenLightLastingSecond ){ /* 若一次週期中綠燈持續亮的時間到 */
if (RedOnLongitudinal){ /* 若輪到縱向紅色 LED 亮 */
digitalWrite(YellowLight_2, HIGH); /* 令橫向黃色 LED 亮 */
digitalWrite(GreenLight_2, LOW); /* 令橫向綠色 LED 熄 */
}
else{ /* 若輪到橫向紅色 LED 亮 */
digitalWrite(YellowLight_1, HIGH); /* 令縱向黃色 LED 亮 */
digitalWrite(GreenLight_1,LOW); /* 令縱向綠色 LED 熄*/
}
}
else if (second == (GreenLightLastingSecond + YellowLightLastingSecond)){ /* 一次週期中綠燈 +
黃燈持續亮的時間到 */
if (RedOnLongitudinal){
digitalWrite(YellowLight_2, LOW); /* 令橫向黃色 LED 熄 */
digitalWrite(RedLight_2, HIGH); /* 令橫向紅色 LED 亮 */
digitalWrite(GreenLight_1, HIGH); /* 令縱向綠色 LED 亮 */
digitalWrite(RedLight_1, LOW); /* 令縱向紅色 LED 熄 */
}
else{
digitalWrite(YellowLight_1, LOW); /* 令橫向黃色 LED 熄 */
digitalWrite(RedLight_1, HIGH); /* 令橫向紅色 LED 亮 */
digitalWrite(GreenLight_2, HIGH); /* 令縱向綠色 LED 亮 */
digitalWrite(RedLight_2, LOW); /* 令縱向紅色 LED 熄 */
}
second = 0; /* 秒數歸 0,新的週期開始 */
redLEDRemainTime = RedLightLastingSecond-second;
RedOnLongitudinal = !RedOnLongitudinal; /* 切換縱橫向紅燈亮 */
}
}
}
void display(){
if(redLEDRemainTime >=100) /* 若紅燈亮的剩餘秒數大於等於 100 */
return; /* 返回 (不顯示) */
calCountDigit(redLEDRemainTime); /* 找出紅燈亮的剩餘秒數的十位數與個位數 */
for(int x = 0; x < 4; x++)
digitalWrite(scanPin[x], 1); /* 清除掃描信號 */
if (RedOnLongitudinal) { /* 縱向紅燈亮 */
for (int i = 0; i < scanDigitNum ; i++){ /* scanDigitNum 為實際掃描位數 */
digitalWrite(latchPin, 0); /* 栓鎖信號解除 */
/* 序列傳輸縱向紅燈倒數秒數的第 i 位數數字的七段顯示碼 */
shiftOut(dataPin, clockPin, MSBFIRST, sevenSegCode[dataOut[i]]);
digitalWrite(latchPin, 1);
digitalWrite(scanPin[i], 0); /* 送出掃描信號給縱向紅燈倒數秒數的第 i 位數 */
delay(2); /* 延遲 2 毫秒 */
digitalWrite(scanPin[i], 1); /* 清除縱向紅燈倒數秒數的第 i 位數的掃描信號 */
}
}
else{ /* 橫向紅燈亮 */
for (int i = 0; i < scanDigitNum ; i++){ /* scanDigitNum 為實際掃描位數 */
digitalWrite(latchPin, 0); /* 栓鎖信號解除 */
/* 序列傳輸橫向紅燈倒數秒數的第 i 位數數字的七段顯示碼 */
shiftOut(dataPin, clockPin, MSBFIRST, sevenSegCode[dataOut[i+2]]);
digitalWrite(latchPin, 1); /* 送出栓鎖信號 */
digitalWrite(scanPin[i+2], 0); /* 送出掃描信號給橫向紅燈倒數秒數的第 i 位數 */
delay(2); /* 延遲 2 毫秒 */
digitalWrite(scanPin[i+2], 1); /* 清除橫向紅燈倒數秒數的第 i 位數的掃描信號 */
}
}
}
void calCountDigit(int count){
countTenthsDigit = count/10; /* 找出計數值的十位數值存入變數 countTenthsDigit */
remainder = count%10; /* 找出計數值的個位數值存入變數 remainder */
countUnitsDigit = remainder; /* 計數值的個位數值暫存於變數 countUnitsDigit */
if (RedOnLongitudinal) {
dataOut[1] = countTenthsDigit; /* 將縱向紅燈倒數秒數的十位數值存入輸出顯示器緩衝區 */
dataOut[0] = countUnitsDigit; /* 將縱向紅燈倒數秒數的個位數值存入輸出顯示器緩衝區 */
}
else{
dataOut[3] = countTenthsDigit; /* 將橫向紅燈倒數秒數的十位數值存入輸出顯示器緩衝區 */
dataOut[2] = countUnitsDigit; /* 將縱向紅燈倒數秒數的個位數值存入輸出顯示器緩衝區 */
}
if (countTenthsDigit != 0)
scanDigitNum = 2; /* 如果秒數值的十位數值不為 0,則掃描位數為 2 個位數 */
else
scanDigitNum = 1; /* 否則掃描位數為 1 個位數 */
}

留言
張貼留言