---
# System prepended metadata

title: 數位式時鐘設計

---

# 數位式時鐘設計

## 實驗材料：
電阻,開關,pmos,七段顯示器,Arduino uno

## 實驗方法：
#### 3-3
1. P11A-7~P11A-1連接到13腳
2. P11B-4~P11B-1連接到5~2腳
3. P5-1(指撥開關)連接A0
4. P11B-5連接A1
5. P6-5~P6-8連到A2~A5，而P6接地


## 程式碼 3-7
```c=
const int SEG[7] = {6,7,8,9,10,11,12}; // 宣告顯示信號接腳
 const int scan[4] = {2,3,4,5}; // 宣告掃描信號接腳(scan)
 const int SEG_code[10] = { // 宣告七段顯示碼陣列
 0xc0,0xf9,0xa4,0xb0,0x99, // 0~4
 0x92,0x82,0xf8,0x80,0x90 } ; // 5~9
 const int PB[4]={A2,A3,A4,A5}; // 按鍵, 小時(兩位數)與分鐘(兩位數)
 const int DD=A1; // 閃秒LED
 const int DIPSW=A0; // 指撥開關
 const int BZ=13; // 蜂鳴器
 int disp[4]={0,0,0,0}; // 宣告顯示緩衝區陣列
 int DISP; // 宣告顯示變數
 unsigned long x0,x1,x2; // 宣告時間變數
 // 宣告狀態旗標：phase0 = false計時模式(ON),
 // phase0 = true調整模式(OFF)
 boolean phase0;
 int seconds=0,sec=0; // 宣告秒變數
 // 函式原型
 void beep(int pin, int counts); // 宣告嗶聲函數
 void scanner(int x); // 宣告掃描函數
 // 初始設定
 void setup() {
     for(int i=0;i<7;i++)
     pinMode(SEG[i], OUTPUT); // 設定顯示信號接腳為輸出接腳
     for(int i=0;i<4;i++) {
     pinMode(scan[i], OUTPUT); // 設定顯示掃描接腳為輸出接腳
     pinMode(PB[i], INPUT); // 設定PB(行接腳)為輸入接腳
     }
     pinMode(DD, OUTPUT); // 設定閃秒LED接腳為輸出接腳
     pinMode(BZ, OUTPUT); // 設定蜂鳴器接腳為輸出接腳
     pinMode(DIPSW, INPUT); // 設定指撥開關接腳為輸入接腳
 }
// 主程式
 void loop() {
     if (digitalRead(DIPSW)) phase0=true; //狀態設定，讀取指撥開關=1：調整模式
     else phase0=false; //狀態設定，讀取指撥開關=0：計時模式

 //調整模式狀態
     while(phase0) {
         seconds=0; //秒數歸零
         //小時遞增調整，按鍵(4x4鍵盤) 為低態動作
         if (!digitalRead(PB[0])) { //若PB[0]被按下(小時遞增)
             if (disp[3]==2 && disp[2]==2) { //若已達到22時
                 disp[3]=1; //小時之十位數歸零
                 disp[2]=2; //小時之個位數歸零
             }
             else if (disp[2]==9) { //若小時之個位數等於9
                 disp[2]=0; //小時之個位數歸零
                 disp[3]++; //小時之十位數遞增(進位)
             }
             else disp[2]++; //否則小時之個位數遞增
         }
  //小時遞減調整(按鍵為低態動作)
         if (!digitalRead(PB[1])) { //若PB[1]被按下(小時遞減)
             if (disp[3]==0 && disp[2]==0) { //若已00時
                 disp[3]=2; //小時之十位數調整為2
                 disp[2]=3; //小時之個位數調整為3
             }
             else if (disp[2]==0) { //若小時之個位數等於0
                 disp[2]=9; //小時之個位調整為9
                 disp[3]--; //小時之十位數遞減(借位)
             }
             else disp[2]--; //否則小時之個位數遞減
         }
        //分鐘遞增調整(按鍵為低態動作)
         if (!digitalRead(PB[2])) { //若PB[2]被按下(分鐘遞增)
             if (disp[1]==5 && disp[0]==9) { //若已59分
                 disp[1]=0; //分鐘之十位數歸零
                 disp[0]=0; //分鐘之個位數歸零
             }
             else if (disp[0]==9) { //若分鐘之個位數等於9
                 disp[0]=0; //分鐘之個位數歸零
                 disp[1]++; //分鐘之十位數遞增(進位)
             }
             else disp[0]++; //否則分鐘之個位數遞增
         }
  //分鐘遞減調整(按鍵為低態動作)
         if (!digitalRead(PB[3])) { //若PB[3]被按下(分鐘遞減)
             if (disp[1]==0 && disp[0]==0) { //若已00分
                 disp[1]=5; //分鐘之十位數調整為5
                 disp[0]=9; //分鐘之個位數調整為9
             }
             else if (disp[0]==0) { //若分鐘之個位數等於0
                 disp[0]=9; //分鐘之個位調整為9
                 disp[1]--; //分鐘之十位數遞減(借位)
             }
             else disp[0]--; //否則分鐘之個位數遞減
             }
             scanner(25); //連續掃描25週(100ms，每秒約10次)
             if (digitalRead(DIPSW)) phase0=true; //讀取指撥開關=1：調整模式
             else phase0=false; //讀取指撥開關=0：計時模式
         }
//計時模式
 while(!phase0) {
     scanner(2); //連續掃描2週(8ms)
     x1=millis(); //查詢時間
     x2=x1-x0; //計算時間差
     if (x2>=500) { //0.5秒時間差
     x0=x1; //記錄時間
     sec=!sec; //切換閃秒一直閃爍跳動
     digitalWrite(DD,sec); //處理時間
     //處理時間
     if (sec) { //處理秒數
         if (++seconds==60) { //秒數加1
             seconds=0; //若秒數滿60則歸零
             if (disp[0]==9) { //若分鐘之個位數滿9
                 disp[0]=0; //則分鐘之個位數歸零
                 if (disp[1]==5) { //若分鐘之十位數滿5
                     disp[1]=0;
                  if (disp[2]==3 && disp[3]==2) { //若為23時
                     disp[2]=0; //則小時之個位數歸零
                     disp[3]=0; //則小時之十位數歸零
                  }
                  else if (disp[2]==9) { //若小時之個位數滿9
                  disp[2]=0; //則小時之個位數歸零
                  disp[3]++; //小時之十位數加1
                  }
                  else disp[2]++; //否則小時之個位數加1
                 }
                 else disp[1]++; //否則分鐘之十位數加1
             }
             else disp[0]++; //否則分鐘之個位數加1
         }
        }
     }
     if (digitalRead(DIPSW)) phase0=true; //讀取指撥開關=1：調整模式
     else phase0=false; //讀取指撥開關=0：計時模式
    }
}
 //七段顯示器掃描函式
 void scanner(int x) { // G~A(不含小數點)每週期4ms
     for(int i=0;i<x;i++) { //重複掃描x次
         for(int j=0;j<4;j++) { //掃描四位數
     //關閉掃描信號(防殘影)
             for(int k=0;k<4;k++) digitalWrite(scan[k],1); //掃描信號為1111
     //輸出七節顯示器顯示信號
             DISP=SEG_code[disp[j]]; // 讀取顯示信號
                 for(int k=0;k<8;k++) { // 並列資料串列輸出
                     if(bitRead(DISP,k)) digitalWrite(SEG[k],1);
                     else digitalWrite(SEG[k],0);
                 }
     //輸出掃描信號
             digitalWrite(scan[j],0);
         delay(1); //延遲1ms
         }    
     }
 }
// 嗶聲函數
 void beep(int pin, int counts) {
     for(int i=0;i<counts;i++) { //執行counts次
         tone(pin,1000,100); //發聲(1kHz,0.1秒)
         delay(100); //靜音(0.1秒)
     }
 }
```
## 實驗結果
![](https://i.imgur.com/bvG4ofn.png)
disp[3]==2 && disp[2]==2) { //若已達到22時
 disp[3]=1; //小時之十位數歸零
disp[2]=2; //小時之個位數歸零

## 實驗心得
電路非常的複雜,但是做出來的時候很有成就感~~
也對微處理機有更進一步的認識了