<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                【116.1 按鍵控制數碼管的倒計時。】 ![](https://img.kancloud.cn/d1/98/d19803e327fa494dce4ab72902e02129_285x371.png) 上圖116.1.1 數碼管 ![](https://img.kancloud.cn/a2/3d/a23df87ac21f61d2182864f67461b009_359x103.png) 上圖116.1.2 獨立按鍵 ![](https://img.kancloud.cn/89/70/8970513a066fe0726b2997dcb0329ce0_194x190.png) 上圖116.1.3 有源蜂鳴器 上一節講“累加式”的秒表,這一節講“遞減式”的倒計時。通過此小項目,加深理解在顯示框架中常用的更新變量(整屏更新和局部更新),以及應用程序與按鍵是如何關聯的框架。同時,在拆分“個十百千萬...”的時候,有一處地方必須注意,“先整除后求余”必須用一行代碼一氣呵成,不能拆分成兩行代碼“先整除;后求余”,否則會有隱患會有bug。除非,把四個臨時變都改成unsigned long類型。比如: 以下這樣是對的: static unsigned char Su8Temp\_1; Su8Temp\_1=vGu32CountdownTimerCnt/10%10; //一氣呵成,沒毛病。 以下這樣是有隱患有bug的(除非把Su8Temp\_1改成unsigned long類型): static unsigned char Su8Temp\_1; Su8Temp\_1=vGu32CountdownTimerCnt/10; Su8Temp\_1=Su8Temp\_1%10; //拆分成兩行代碼后,有隱患有bug。數據溢出的原因引起。 本節倒計時程序的功能:K1按鍵是復位按鍵,每按一次,倒計時停止并且重新恢復初始值10.00秒。K2按鍵是啟動按鍵,當秒表處于復位后停止的狀態時按一次則開始啟動倒計時,當倒計時變為0.00秒的時候,蜂鳴器發出一次“滴”的提示聲。此時,如果想啟動新一輪的倒計時,只需按一次K1復位鍵,然后再按K2啟動按鍵,就可以啟動新一輪10.00秒的倒計時。代碼如下: \#include "REG52.H" \#define KEY\_FILTER\_TIME 25 \#define SCAN\_TIME 1 \#define VOICE\_TIME 50 //蜂鳴器一次“滴”的聲音長度 50ms void T0\_time(); void SystemInitial(void) ; void Delay(unsigned long u32DelayTime) ; void PeripheralInitial(void) ; void KeyScan(void); void KeyTask(void); void VoiceScan(void); //蜂鳴器的驅動函數 void DisplayScan(void); //底層顯示的驅動函數 void DisplayTask(void); //上層顯示的任務函數 void RunTask(void); //倒計時的應用程序 void BeepOpen(void); void BeepClose(void); sbit KEY\_INPUT1=P2^2; sbit KEY\_INPUT2=P2^1; sbit P1\_0=P1^0; sbit P1\_1=P1^1; sbit P1\_2=P1^2; sbit P1\_3=P1^3; sbit P3\_4=P3^4; //數碼管轉換表 code unsigned char Cu8DigTable\[\]= { 0x3f, //0 序號0 0x06, //1 序號1 0x5b, //2 序號2 0x4f, //3 序號3 0x66, //4 序號4 0x6d, //5 序號5 0x7d, //6 序號6 0x07, //7 序號7 0x7f, //8 序號8 0x6f, //9 序號9 0x00, //不顯示 序號10 }; //數碼管底層驅動掃描的軟件定時器 volatile unsigned char vGu8ScanTimerFlag=0; volatile unsigned int vGu16ScanTimerCnt=0; //倒計時的軟件定時器,注意,這里是unsigned long類型,范圍是0到4294967295毫秒 volatile unsigned char vGu8CountdownTimerFlag=0; volatile unsigned long vGu32CountdownTimerCnt=10000; //開機默認顯示初始值10.000秒 //數碼管上層每10ms就定時刷新一次顯示的軟件定時器。用于及時更新顯示秒表當前的實時數值 volatile unsigned char vGu8UpdateTimerFlag=0; volatile unsigned int vGu16UpdateTimerCnt=0; //蜂鳴器的軟件定時器 volatile unsigned char vGu8BeepTimerFlag=0; volatile unsigned int vGu16BeepTimerCnt=0; unsigned char Gu8RunStart=0; //應用程序的總啟動 unsigned char Gu8RunStep=0; //應用程序的總運行步驟。建議跟vGu8RunStart成雙成對出現 unsigned char Gu8RunStatus=0; //當前倒計時的狀態。0代表停止,1代表正在工作中 unsigned char Gu8WdUpdate=1; //開機默認整屏更新一次顯示。此變量在顯示框架中是非常重要的變量 volatile unsigned char vGu8Display\_Righ\_4=1; //顯示“1”,跟vGu32CountdownTimerCnt高位一致 volatile unsigned char vGu8Display\_Righ\_3=0; volatile unsigned char vGu8Display\_Righ\_2=0; volatile unsigned char vGu8Display\_Righ\_1=0; volatile unsigned char vGu8Display\_Righ\_Dot\_4=0; volatile unsigned char vGu8Display\_Righ\_Dot\_3=1; //開機默認保留顯示2個小數點 volatile unsigned char vGu8Display\_Righ\_Dot\_2=0; volatile unsigned char vGu8Display\_Righ\_Dot\_1=0; volatile unsigned char vGu8KeySec=0; void main() { SystemInitial(); Delay(10000); PeripheralInitial(); while(1) { KeyTask(); //按鍵的任務函數 DisplayTask(); //數碼管顯示的上層任務函數 RunTask(); //倒計時的應用程序 } } void KeyTask(void) //按鍵的任務函數 { if(0==vGu8KeySec) { return; } switch(vGu8KeySec) { case 1: //復位按鍵 Gu8RunStatus=0; //倒計時返回停止的狀態 Gu8RunStart=0; //倒計時的運行步驟的停止 Gu8RunStep=0; //總運行步驟歸零。建議跟vGu8RunStart成雙成對出現 vGu8CountdownTimerFlag=0; //禁止倒計時開始(而Gu8RunStart是啟動開關,不矛盾) vGu32CountdownTimerCnt=10000; //倒計時的軟件定時器恢復初始值10.000秒 Gu8WdUpdate=1; //整屏更新一次顯示 vGu8KeySec=0; break; case 2: //啟動的按鍵 if(0==Gu8RunStatus) //在停止狀態下 { vGu8CountdownTimerFlag=0; vGu32CountdownTimerCnt=10000; //初始值是10.000秒 vGu8CountdownTimerFlag=1; //允許倒計時的軟件定時器的啟動 Gu8RunStatus=1; //倒計時處于工作狀態(并且,這一瞬間才正式啟動倒計時) Gu8RunStart=1; //倒計時的運行步驟的總開關開啟 Gu8RunStep=0; //總運行步驟歸零。建議跟vGu8RunStart成雙成對出現 Gu8WdUpdate=1; //整屏更新一次顯示,確保在啟動的時候能顯示到最新的數據 } vGu8KeySec=0; break; } } void DisplayTask(void) //數碼管顯示的上層任務函數 { //需要借用的中間變量,用來拆分數據位。 static unsigned char Su8Temp\_4,Su8Temp\_3,Su8Temp\_2,Su8Temp\_1; //需要借用的中間變量 if(1==Gu8WdUpdate) //如果需要整屏更新 { Gu8WdUpdate=0; //及時清零,只更新一次顯示即可,避免一直進來更新顯示 //先分解數據,注意,這里分解的時候,“先整除后求余”必須用一行代碼一氣呵成,不能拆 //分成兩行代碼,否則會有隱患會有bug。除非,把四個臨時變都改成unsigned long類型。 //Su8Temp\_4提取“十秒”位。 Su8Temp\_4=vGu32CountdownTimerCnt/10000%10; //實際精度是0.001秒,但顯示精度是0.01秒 //Su8Temp\_3提取“個秒”位。 Su8Temp\_3=vGu32CountdownTimerCnt/1000%10; //實際精度是0.001秒,但顯示精度是0.01秒 //Su8Temp\_2提取“百毫秒”位。 Su8Temp\_2=vGu32CountdownTimerCnt/100%10; //實際精度是0.001秒,但顯示精度是0.01秒 //Su8Temp\_1提取“十毫秒”位。 Su8Temp\_1=vGu32CountdownTimerCnt/10%10; //實際精度是0.001秒,但顯示精度是0.01秒 //判斷數據范圍,來決定最高位數碼管是否需要顯示。 if(vGu32CountdownTimerCnt<10000) //10.000秒。實際4位數碼管最大只能顯示99.99秒 { Su8Temp\_4=10; //在數碼管轉換表里,10代表一個“不顯示”的數據 } //上面先分解數據之后,再過渡需要顯示的數據到底層驅動變量里,讓過渡的時間越短越好 vGu8Display\_Righ\_4=Su8Temp\_4; //過渡需要顯示的數據到底層驅動變量 vGu8Display\_Righ\_3=Su8Temp\_3; vGu8Display\_Righ\_2=Su8Temp\_2; vGu8Display\_Righ\_1=Su8Temp\_1; vGu8Display\_Righ\_Dot\_4=0; vGu8Display\_Righ\_Dot\_3=1; //保留顯示2位小數點 vGu8Display\_Righ\_Dot\_2=0; vGu8Display\_Righ\_Dot\_1=0; } } void RunTask(void) //倒計時的應用程序 { if(0==Gu8RunStart) { return; // 如果總開關處于停止狀態,則直接退出當前函數,不執行該函數以下的其它代碼 } switch(Gu8RunStep) { case 0: //在這個步驟里,主要用來初始化一些參數 vGu8UpdateTimerFlag=0; vGu16UpdateTimerCnt=10; //每10ms更新顯示一次當前倒計時的時間 vGu8UpdateTimerFlag=1; Gu8RunStep=1; //跳轉到每10ms更新顯示一次的步驟里 break; case 1: //每10ms更新一次顯示,確保實時顯示當前倒計時的時間 if(0==vGu16UpdateTimerCnt) //每10ms更新顯示一次當前倒計時的時間 { vGu8UpdateTimerFlag=0; vGu16UpdateTimerCnt=10; //重置定時器,為下一個10ms更新做準備 vGu8UpdateTimerFlag=1; Gu8WdUpdate=1; //整屏更新一次顯示當前倒計時的時間 if(0==vGu32CountdownTimerCnt) //如果倒計時的時間到,則跳轉到結束的步驟 { Gu8RunStep=2; //跳轉到倒計時結束的步驟 } } break; case 2: //倒計時結束的步驟 //Gu8RunStatus=0; //這行代碼注釋掉,讓每次新啟動之前都必須按一次K1復位按鍵才有效 Gu8RunStart=0; //倒計時的運行步驟的停止 Gu8RunStep=0; //總運行步驟歸零。建議跟vGu8RunStart成雙成對出現 vGu8BeepTimerFlag=0; vGu16BeepTimerCnt=VOICE\_TIME; //蜂鳴器發出“滴”一聲 vGu8BeepTimerFlag=1; Gu8WdUpdate=1; //整屏更新一次顯示當前倒計時的時間 break; } } void KeyScan(void) //按鍵底層的驅動掃描函數,放在定時中斷函數里 { static unsigned char Su8KeyLock1; static unsigned int Su16KeyCnt1; static unsigned char Su8KeyLock2; static unsigned int Su16KeyCnt2; if(0!=KEY\_INPUT1) { Su8KeyLock1=0; Su16KeyCnt1=0; } else if(0==Su8KeyLock1) { Su16KeyCnt1++; if(Su16KeyCnt1>=KEY\_FILTER\_TIME) { Su8KeyLock1=1; vGu8KeySec=1; } } if(0!=KEY\_INPUT2) { Su8KeyLock2=0; Su16KeyCnt2=0; } else if(0==Su8KeyLock2) { Su16KeyCnt2++; if(Su16KeyCnt2>=KEY\_FILTER\_TIME) { Su8KeyLock2=1; vGu8KeySec=2; } } } void DisplayScan(void) //數碼管底層的驅動掃描函數,放在定時中斷函數里 { static unsigned char Su8GetCode; static unsigned char Su8ScanStep=1; if(0==vGu16ScanTimerCnt) { P0=0x00; P1\_0=1; P1\_1=1; P1\_2=1; P1\_3=1; switch(Su8ScanStep) { case 1: Su8GetCode=Cu8DigTable\[vGu8Display\_Righ\_1\]; if(1==vGu8Display\_Righ\_Dot\_1) { Su8GetCode=Su8GetCode|0x80; } P0=Su8GetCode; P1\_0=0; P1\_1=1; P1\_2=1; P1\_3=1; break; case 2: Su8GetCode=Cu8DigTable\[vGu8Display\_Righ\_2\]; if(1==vGu8Display\_Righ\_Dot\_2) { Su8GetCode=Su8GetCode|0x80; } P0=Su8GetCode; P1\_0=1; P1\_1=0; P1\_2=1; P1\_3=1; break; case 3: Su8GetCode=Cu8DigTable\[vGu8Display\_Righ\_3\]; if(1==vGu8Display\_Righ\_Dot\_3) { Su8GetCode=Su8GetCode|0x80; } P0=Su8GetCode; P1\_0=1; P1\_1=1; P1\_2=0; P1\_3=1; break; case 4: Su8GetCode=Cu8DigTable\[vGu8Display\_Righ\_4\]; if(1==vGu8Display\_Righ\_Dot\_4) { Su8GetCode=Su8GetCode|0x80; } P0=Su8GetCode; P1\_0=1; P1\_1=1; P1\_2=1; P1\_3=0; break; } Su8ScanStep++; if(Su8ScanStep>4) { Su8ScanStep=1; } vGu8ScanTimerFlag=0; vGu16ScanTimerCnt=SCAN\_TIME; vGu8ScanTimerFlag=1; } } void VoiceScan(void) //蜂鳴器的驅動函數 { static unsigned char Su8Lock=0; if(1==vGu8BeepTimerFlag&&vGu16BeepTimerCnt>0) { if(0==Su8Lock) { Su8Lock=1; BeepOpen(); } else { vGu16BeepTimerCnt--; if(0==vGu16BeepTimerCnt) { Su8Lock=0; BeepClose(); } } } } void BeepOpen(void) { P3\_4=0; } void BeepClose(void) { P3\_4=1; } void T0\_time() interrupt 1 { VoiceScan(); //蜂鳴器的驅動函數 KeyScan(); //按鍵底層的驅動掃描函數 DisplayScan(); //數碼管底層的驅動掃描函數 if(1==vGu8ScanTimerFlag&&vGu16ScanTimerCnt>0) { vGu16ScanTimerCnt--; //遞減式的軟件定時器 } //每10ms就定時更新一次顯示的軟件定時器 if(1==vGu8UpdateTimerFlag&&vGu16UpdateTimerCnt>0) { vGu16UpdateTimerCnt--; //遞減式的軟件定時器 } //倒計時實際走的時間的軟件定時器,注意,這里還附加了啟動狀態的條件“&&1==Gu8RunStatus” if(1==vGu8CountdownTimerFlag&&vGu32CountdownTimerCnt>0&&1==Gu8RunStatus) { vGu32CountdownTimerCnt--; //遞減式的軟件定時器 } TH0=0xfc; TL0=0x66; } void SystemInitial(void) { P0=0x00; P1\_0=1; P1\_1=1; P1\_2=1; P1\_3=1; TMOD=0x01; TH0=0xfc; TL0=0x66; EA=1; ET0=1; TR0=1; } void Delay(unsigned long u32DelayTime) { for(;u32DelayTime>0;u32DelayTime--); } void PeripheralInitial(void) { }
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看