Arduino:具有倒數計時自動回復功能的行人穿越道號誌控制系統

 Pedestrian Crossing Safety Circuit with Self-resetting Functions Using Arduino

先前文章具有倒數計時自動回復功能的行人穿越道號誌控制電路是以純硬體電路的方式來完成,本文則是用微控器寫控制程式的方式來達成相同功能。

功能

路口在無行人穿越道路時會有黃燈閃爍;但是當有行人要安全地穿越道路時,行人按下「通行」按鈕後,路口的黃燈會熄滅同時紅燈亮且倒數 30 秒計時開始並顯示。此時,駕駛人看到紅燈亮,車輛會停下來等待行人通過。當倒數計時完畢,路口恢復閃黃燈且紅燈熄滅,車輛恢復通行。


電路圖

如圖一所示。

圖一    Arduino:具有倒數計時自動回復功能的行人穿越道號誌控制系統




程式碼


  C/C++
const int yellowLED = A5;        /* A5 腳輸出訊號控制黃色 LED 的亮滅 */
const int redLED = 2;               /* 第 2 腳輸出訊號控制紅色 LED 的亮滅*/
const int crossingBtn = 3;         /* 第 3 腳偵測通行按鈕按下與否 */
const int scanPin[2] = {5, 6};    /* 七段顯示器掃描訊號輸出接腳為第 5 腳與第 6 腳 */

/* 串列資料輸出接腳為第 10 腳;栓鎖訊號輸出接腳為第 11 腳;移位脈波輸出接腳為第 12 腳 */
const int dataPin = 10, latchPin = 11, clockPin = 12;  

/* 數字 0 至 9 的共陽極七段顯示碼  */
const int sevenSegCode[ ] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
int dataOut[2] = {0, 0};             /* 兩位數輸出輸出緩衝區,順序為個位、十位 */
unsigned long clock;                 /* 存放系統時間的變數 */

bool crossingBtn_pressed = false;  /* 通行按鈕狀態旗標 (false 表示未按下 ) */
void yellowLEDFlash();                 /* 輸出黃燈閃爍需要的脈波函數 */
void display();                                 /* 顯示函數 */
void buttonStates();                         /* 偵測按鈕狀態函數 */
int count = 31;                                 /* 計數初值 */
void calCountDigit(int count);        /* 找出計數值的十位數與個位數值 */
int countTenthsDigit;                       /* 暫存找出的計數值的十位數值 */
int remainder;                                  /* 暫存在找出計數值的十位數與個位數值過程產生的餘數 */
int countUnitsDigit;                         /* 暫存找出的計數值的個位數值 */
int scanDigitNum;                           /* 實際需要掃描的位數,可為 1 或 2 */

void setup() {
  pinMode(crossingBtn, INPUT);       /* 規劃第 3 腳為輸入 */
  pinMode(yellowLED, OUTPUT);   /* 規劃第 A5 腳為輸出 */
  pinMode(redLED, OUTPUT);         /* 規劃第 2 腳為輸出 */
  for (int i = 0; i < 2; i++){
      pinMode(scanPin[i], OUTPUT);    /* 規劃第 5、6 腳為輸出 */
      digitalWrite(scanPin[i], 1);             /* 第 5、6 腳停止送出掃描訊號邏輯 "0" */
  }
  pinMode(dataPin, OUTPUT);             /* 規劃第 10 腳為輸出 */
  pinMode(clockPin, OUTPUT);            /* 規劃第 12 腳為輸出 */
  pinMode(latchPin, OUTPUT);             /* 規劃第 11 腳為輸出 */
  clock = millis();                                    /* 取得系統從開始至今的時間 (單位毫秒) */ 
}

void loop() { 
   buttonStates();                             /* 偵測通行按鈕的狀態 */ 
   if (!crossingBtn_pressed){          /* 若通行按鈕未按下 */
      digitalWrite(redLED, 1);          /* 令紅色 LED 熄滅 */ 
      yellowLEDFlash();                   /* 令脈波送出去驅動黃色 LED  */ 
   }
   else if (crossingBtn_pressed){    /* 若通行按鈕按下 */ 
      display();                                  /* 顯示計時值 */
      digitalWrite(redLED, 0);         /* 紅色 LED 亮 */ 
      digitalWrite(yellowLED, 1);   /* 黃色 LED 熄 */ 
      if (millis() - clock >= 1000){   /* 如果兩次取得的系統時間間隔超過 1000 毫秒 */ 
            display();                            /* 顯示計時值 */
            count--;                               /* 計時值遞減一 */
            calCountDigit(count);         /* 將計時值的十位數與個位數找出 */
            clock = millis();                  /* 取得系統從開始至今的時間 (單位毫秒) */ 
      }
     
   }
   if (count == -1){                           /* 如果計時值為 -1 */ 
      crossingBtn_pressed = false;     /* 通行按鈕狀態為未按下 */ 
      digitalWrite(redLED, 0);           /* 紅色 LED 亮 */ 
      digitalWrite(yellowLED, 1);     /* 黃色 LED 熄 */ 
      count = 31;                                /* 計時值回復為 31 */
   }  
}

void buttonStates(){
   if (!digitalRead(crossingBtn)){  /* 若通行按鈕按下 */
      crossingBtn_pressed = true;   /* 通行按鈕狀態標註為已按下 */
   }  
}

void yellowLEDFlash(){
      digitalWrite(yellowLED, 0);   /* 黃色 LED 亮 */ 
      delay(500);                              /* 延遲 0.5 秒 */ 
      digitalWrite(yellowLED, 1);   /* 黃色 LED 熄 */ 
      delay(500);
}

void display(){
      for(int x=0;x<2;x++) 
            digitalWrite(scanPin[x], 1);               /* 清除掃描信號 */ 
      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 位數的掃描信號 */ 
      }         
}

void calCountDigit(int count){  
    countTenthsDigit = count/10;              /* 找出計數值的十位數值變數 countTenthsDigit */
    remainder =  count%10;                       /* 找出計數值的位數值 */
    countUnitsDigit = remainder;              /* 計數值的個位數值暫存於變數 countUnitsDigit */
    dataOut[1] = countTenthsDigit;       /* 將計數值的十位數值存入輸出顯示器十位數緩衝區 */
    dataOut[0] = countUnitsDigit;         /* 將計數值的個位數值存入輸出顯示器個位數緩衝區 */
    if (countTenthsDigit != 0)
        scanDigitNum = 2;   /* 如果計數值的十位數值不為 0,則掃描位數為 2 個位數 */
    else
        scanDigitNum = 1;                 /*  否則掃描位數為 1 個位數 */
}



眞趣盎然集相關文章



留言

這個網誌中的熱門文章

三段式電子開關電路

陣列 (C++)

首數、尾數與位數

分壓偏壓 BJT 放大電路的直流分析及其近似解的條件

MOSFET 共汲極放大電路 (源極隨耦器) 小訊號分析

為什麼理想的 OPA 電壓放大器有虛短路與虛斷路現象

具有倒數計時自動回復功能的行人穿越道號誌控制電路