專做外貿(mào)衣服鞋網(wǎng)站有哪些網(wǎng)址搜索引擎入口
基于定時(shí)器的倒計(jì)時(shí)程序
題目如下所示:
實(shí)現(xiàn)過(guò)程中遇到的一些問(wèn)題
01 如何改變Seg_Buf數(shù)組的值數(shù)碼管總是一致地顯示0 1 2 3 4 5
首先這個(gè)問(wèn)題不是在main.c中關(guān)于數(shù)碼管顯示部分的邏輯錯(cuò)誤,就是發(fā)生在數(shù)碼管的底層錯(cuò)誤。
檢查了邏輯部分,沒(méi)有發(fā)現(xiàn)問(wèn)題
轉(zhuǎn)而查找底層上面的錯(cuò)誤。
底層的Seg.c是這樣寫的:
#include <Seg.h>unsigned char code Seg_Dula[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f ,0x00};
unsigned char code Seg_Wela[] = {0xfe ,0xfd ,0xfb,0xf7,0xef,0xdf};void Seg_Disp(unsigned char wela,dala)
{//消影P0 = 0x00;P2_6 = 1;P2_6 = 0;P0 = Seg_Wela[wela];P2_7 = 1;P2_7 = 0;P0 = Seg_Dula[wela];//問(wèn)題出現(xiàn)在這里!P2_6 = 1;P2_6 = 0;
}
果然被我發(fā)現(xiàn)了,段選數(shù)組的索引寫錯(cuò)了,寫成了wela,這樣無(wú)論如何,數(shù)碼管的每一位都會(huì)按照傳入的wela來(lái)顯示(wela在main函數(shù)中即Seg_Pos,這個(gè)變量在0-5范圍內(nèi)循環(huán))
if(++Seg_Pos == 6) Seg_Pos = 0;Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);
02 按下設(shè)置按鍵KEY4設(shè)置好倒計(jì)時(shí)參數(shù)后,該參數(shù)應(yīng)該在什么時(shí)機(jī)傳輸給Time_Count倒計(jì)時(shí)變量用于倒計(jì)時(shí)呢?
(1)設(shè)置完就對(duì)Time_Count賦值
//按鍵處理函數(shù)Key_Proc()
void Key_Proc()
{if(Key_Slow_Down)return;Key_Slow_Down = 1;//按鍵減速程序//這三行要背下來(lái)Key_Val = Key_Read();//讀取按下的鍵碼值Key_Down = Key_Val &(Key_Val ^ Key_Old);//捕獲下降沿Key_Old = Key_Val;//輔助掃描switch(Key_Down){//框架先搭好,內(nèi)容先不寫case 1:if(Seg_Mode == 0) System_Flag = 1;break;case 3:Seg_Mode ^= 1;break;case 4:if(Seg_Mode == 1){if(++Set_Dat_Index == 3) Set_Dat_Index = 0;Time_Count = Set_Dat[Set_Dat_Index];//設(shè)置完就對(duì)Time_Count賦值!!!!!!}break;case 2:if(Seg_Mode == 0) Time_Count = Set_Dat[Set_Dat_Index];break;}
}
如果這樣的話,會(huì)導(dǎo)致切換回顯示模式后已經(jīng)倒計(jì)時(shí)了一段時(shí)間了,不是從設(shè)置的值開(kāi)始倒計(jì)時(shí)的。想要切換回顯示模式從設(shè)置的值開(kāi)始倒計(jì)時(shí),需要在切換回顯示模式后,再對(duì)Time_Count賦值。
(2)在切換成顯示模式后對(duì)Time_Count賦值
//按鍵處理函數(shù)Key_Proc()
void Key_Proc()
{if(Key_Slow_Down)return;Key_Slow_Down = 1;//按鍵減速程序//這三行要背下來(lái)Key_Val = Key_Read();//讀取按下的鍵碼值Key_Down = Key_Val &(Key_Val ^ Key_Old);//捕獲下降沿Key_Old = Key_Val;//輔助掃描switch(Key_Down){//框架先搭好,內(nèi)容先不寫case 1:if(Seg_Mode == 0) System_Flag = 1;break;case 3:Seg_Mode ^= 1;if(Seg_Mode == 0)Time_Count = Set_Dat[Set_Dat_Index] ;//切換到顯示界面再對(duì)Time_Count賦值!!!!!!break;case 4:if(Seg_Mode == 1){if(++Set_Dat_Index == 3) Set_Dat_Index = 0;//Time_Count = Set_Dat[Set_Dat_Index];}break;case 2:if(Seg_Mode == 0) Time_Count = Set_Dat[Set_Dat_Index];break;}
}
03 倒計(jì)時(shí)到0之后為什么數(shù)碼管又變成55再倒計(jì)時(shí)呢?
這是因?yàn)門ime_Count–,沒(méi)有對(duì)其作任何限制的情況下,Time_Count減為0之后會(huì)再?gòu)?55開(kāi)始減遞減(Time_Count是一個(gè)unsigned char類型的變量,該變量8bit,變量可以表示的范圍為0-255
)。而我們只讓數(shù)碼管顯示到十位數(shù),因此我們看到的就是數(shù)碼管從55開(kāi)始倒計(jì)時(shí)。
對(duì)中斷服務(wù)函數(shù)代碼作如下修改:
void Timer0Server() interrupt 1
{//定時(shí)器的初值一定要記得從上面復(fù)制過(guò)來(lái)TL0 = 0x18; //設(shè)置定時(shí)初值TH0 = 0xFC; //設(shè)置定時(shí)初值if(++Key_Slow_Down == 10) Key_Slow_Down = 0;if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;if(++Seg_Pos == 6) Seg_Pos = 0;Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);//模板以外的東西if(System_Flag == 1)//倒計(jì)時(shí)開(kāi)始{if(++Timer_1000ms == 1000){Timer_1000ms = 0;Time_Count--;//相當(dāng)于1s中減少一次(倒計(jì)時(shí)一次)if(Time_Count==255) Time_Count=0;//修改代碼!!!!!!!!!!!!!!!!!!}}
}
修改代碼之后數(shù)碼管會(huì)停在00的位置。
至此,所有代碼如下所示(不包含設(shè)置參數(shù)以1s為周期閃爍):
//頭文件聲明
#include <REGX52.H>
#include <Key.h>
#include <Seg.h>//動(dòng)態(tài)數(shù)碼管會(huì)用到數(shù)碼管的底層?//變量聲明
unsigned char Key_Slow_Down;//按鍵減速專用變量 10ms
unsigned char Key_Val,Key_Down,Key_Old;//按鍵掃描專用變量unsigned int Seg_Slow_Down;//數(shù)碼管減速專用變量 500mschar:0-255.char不夠用//動(dòng)態(tài)數(shù)碼管
unsigned char Seg_Pos;//數(shù)碼管掃描變量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//數(shù)碼管顯示數(shù)據(jù)存放數(shù)組unsigned char Seg_Mode;//數(shù)碼管顯示頁(yè)面 0-顯示 1-設(shè)置,默認(rèn)為0
unsigned int Timer_1000ms;//1000ms標(biāo)志位
unsigned char Time_Count = 30;//倒計(jì)時(shí)變量//按鍵
bit System_Flag;//0-暫停 1-開(kāi)始倒計(jì)時(shí)unsigned char Set_Dat[3] = {15,30,60};//設(shè)置參數(shù)儲(chǔ)存數(shù)組
unsigned char Set_Dat_Index = 1;//LED點(diǎn)亮標(biāo)志位
bit Timer0Flag;//0-倒計(jì)時(shí)沒(méi)有到0;1-倒計(jì)時(shí)到0//按鍵處理函數(shù)Key_Proc()
void Key_Proc()
{if(Key_Slow_Down)return;Key_Slow_Down = 1;//按鍵減速程序//這三行要背下來(lái)Key_Val = Key_Read();//讀取按下的鍵碼值Key_Down = Key_Val &(Key_Val ^ Key_Old);//捕獲下降沿Key_Old = Key_Val;//輔助掃描switch(Key_Down){//框架先搭好,內(nèi)容先不寫case 1:if(Seg_Mode == 0) System_Flag = 1;break;case 3:Seg_Mode ^= 1;//if(Seg_Mode == 0)//Time_Count = Set_Dat[Set_Dat_Index];break;case 4:if(Seg_Mode == 1){if(++Set_Dat_Index == 3) Set_Dat_Index = 0;Time_Count = Set_Dat[Set_Dat_Index];}break;case 2:if(Seg_Mode == 0) Time_Count = Set_Dat[Set_Dat_Index];break;}
}//信息顯示函數(shù)Seg_Proc()
void Seg_Proc()
{if(Seg_Slow_Down)return;Seg_Slow_Down = 1;//數(shù)碼管減速程序//現(xiàn)在沒(méi)有要顯示的信息,這里先空著。(模板以外的東西)Seg_Buf[0] = Seg_Mode + 1;if(Seg_Mode == 0)//顯示模式{Seg_Buf[4] = Time_Count/10%10;//可以寫成Time_Count/10嘛Seg_Buf[5] = Time_Count%10;}else//處于設(shè)置模式{Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;}}/* 其他顯示函數(shù) */
//Led_Proc()
void Led_Proc()
{if(Time_Count == 0){P1 = 0x00;//LED全亮P2_3 = 0;//蜂鳴器使能}else{P1 = 0xff;//LED全滅P2_3 = 1;//蜂鳴器關(guān)閉}
}//Timer0Init()定時(shí)器0的中斷初始化函數(shù)
void Timer0Init(void) //1毫秒@12.000MHz
{//AUXR &= 0x7F; //定時(shí)器時(shí)鐘12T模式TMOD &= 0xF0; //設(shè)置定時(shí)器模式TMOD |= 0x01; //設(shè)置定時(shí)器模式TL0 = 0x18; //設(shè)置定時(shí)初值TH0 = 0xFC; //設(shè)置定時(shí)初值TF0 = 0; //清除TF0標(biāo)志TR0 = 1; //定時(shí)器0開(kāi)始計(jì)時(shí)//復(fù)制過(guò)來(lái)之后不要忘記加上兩句話ET0 = 1;EA = 1;
}//Server定時(shí)器0的中斷服務(wù)函數(shù)
//a++是先進(jìn)行取值,后進(jìn)行自增。++a是先進(jìn)行自增,后進(jìn)行取值
void Timer0Server() interrupt 1
{//定時(shí)器的初值一定要記得從上面復(fù)制過(guò)來(lái)TL0 = 0x18; //設(shè)置定時(shí)初值TH0 = 0xFC; //設(shè)置定時(shí)初值if(++Key_Slow_Down == 10) Key_Slow_Down = 0;if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;if(++Seg_Pos == 6) Seg_Pos = 0;Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);//模板以外的東西if(System_Flag == 1)//倒計(jì)時(shí)開(kāi)始{if(++Timer_1000ms == 1000){Timer_1000ms = 0;Time_Count--;//相當(dāng)于1s中減少一次(倒計(jì)時(shí)一次)if(Time_Count==255) Time_Count=0;}}
}
//主函數(shù)
void main()
{Timer0Init();//上電時(shí)立即調(diào)用定時(shí)器初始化函數(shù)while(1){//三大處理單元:按鍵、數(shù)碼管、LEDKey_Proc();Seg_Proc();Led_Proc();}
}
04 如何實(shí)現(xiàn)設(shè)置參數(shù)以1s為周期閃爍?
(1)在變量聲明區(qū)新增兩個(gè)變量:
注:以1s為周期閃爍,即500ms亮,500ms滅。
unsigned int Timer_500ms;//500ms標(biāo)志位
bit Seg_Flag;//數(shù)碼管標(biāo)志位,即控制數(shù)碼管的亮滅
(2)在中斷服務(wù)函數(shù)中
if(++Timer_500ms == 500){Timer_500ms = 0;Seg_Flag ^= 1;//因?yàn)槟J(rèn)值為0,只需要對(duì)其取反即可,不需要賦值,可以用^=1來(lái)對(duì)一個(gè)變量取反}
(3)在數(shù)碼管顯示函數(shù)中
//信息顯示函數(shù)Seg_Proc()
void Seg_Proc()
{if(Seg_Slow_Down)return;Seg_Slow_Down = 1;//數(shù)碼管減速程序//現(xiàn)在沒(méi)有要顯示的信息,這里先空著。(模板以外的東西)Seg_Buf[0] = Seg_Mode + 1;if(Seg_Mode == 0)//顯示模式{Seg_Buf[4] = Time_Count/10%10;//可以寫成Time_Count/10嘛Seg_Buf[5] = Time_Count%10;}else//處于設(shè)置模式{
// Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;
// Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;
//修改如下:if(Seg_Flag == 1){Seg_Buf[4] = 10;Seg_Buf[5] = 10;}else{Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;}}
}
05 最終版代碼
//頭文件聲明
#include <REGX52.H>
#include <Key.h>
#include <Seg.h>//動(dòng)態(tài)數(shù)碼管會(huì)用到數(shù)碼管的底層?//變量聲明
unsigned char Key_Slow_Down;//按鍵減速專用變量 10ms
unsigned char Key_Val,Key_Down,Key_Old;//按鍵掃描專用變量unsigned int Seg_Slow_Down;//數(shù)碼管減速專用變量 500mschar:0-255.char不夠用//動(dòng)態(tài)數(shù)碼管
unsigned char Seg_Pos;//數(shù)碼管掃描變量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//數(shù)碼管顯示數(shù)據(jù)存放數(shù)組unsigned char Seg_Mode;//數(shù)碼管顯示頁(yè)面 0-顯示 1-設(shè)置,默認(rèn)為0
unsigned int Timer_1000ms;//1000ms標(biāo)志位
unsigned char Time_Count = 30;//倒計(jì)時(shí)變量//按鍵
bit System_Flag;//0-暫停 1-開(kāi)始倒計(jì)時(shí)unsigned char Set_Dat[3] = {15,30,60};//設(shè)置參數(shù)儲(chǔ)存數(shù)組
unsigned char Set_Dat_Index = 1;//設(shè)置參數(shù)閃爍
unsigned int Timer_500ms;//500ms標(biāo)志位
bit Seg_Flag;//數(shù)碼管標(biāo)志位//LED點(diǎn)亮標(biāo)志位
bit Timer0Flag;//0-倒計(jì)時(shí)沒(méi)有到0;1-倒計(jì)時(shí)到0//按鍵處理函數(shù)Key_Proc()
void Key_Proc()
{if(Key_Slow_Down)return;Key_Slow_Down = 1;//按鍵減速程序//這三行要背下來(lái)Key_Val = Key_Read();//讀取按下的鍵碼值Key_Down = Key_Val &(Key_Val ^ Key_Old);//捕獲下降沿Key_Old = Key_Val;//輔助掃描switch(Key_Down){//框架先搭好,內(nèi)容先不寫case 1:if(Seg_Mode == 0) System_Flag = 1;break;case 3:Seg_Mode ^= 1;//if(Seg_Mode == 0)//Time_Count = Set_Dat[Set_Dat_Index];break;case 4:if(Seg_Mode == 1){if(++Set_Dat_Index == 3) Set_Dat_Index = 0;Time_Count = Set_Dat[Set_Dat_Index];}break;case 2:if(Seg_Mode == 0) Time_Count = Set_Dat[Set_Dat_Index];break;}
}//信息顯示函數(shù)Seg_Proc()
void Seg_Proc()
{if(Seg_Slow_Down)return;Seg_Slow_Down = 1;//數(shù)碼管減速程序//現(xiàn)在沒(méi)有要顯示的信息,這里先空著。(模板以外的東西)Seg_Buf[0] = Seg_Mode + 1;if(Seg_Mode == 0)//顯示模式{Seg_Buf[4] = Time_Count/10%10;//可以寫成Time_Count/10嘛Seg_Buf[5] = Time_Count%10;}else//處于設(shè)置模式{
// Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;
// Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;if(Seg_Flag == 1){Seg_Buf[4] = 10;Seg_Buf[5] = 10;}else{Seg_Buf[4] = Set_Dat[Set_Dat_Index]/10%10;Seg_Buf[5] = Set_Dat[Set_Dat_Index]%10;}}
}/* 其他顯示函數(shù) */
//Led_Proc()
void Led_Proc()
{if(Time_Count == 0){P1 = 0x00;//LED全亮P2_3 = 0;//蜂鳴器使能}else{P1 = 0xff;//LED全滅P2_3 = 1;//蜂鳴器關(guān)閉}
}//Timer0Init()定時(shí)器0的中斷初始化函數(shù)
void Timer0Init(void) //1毫秒@12.000MHz
{//AUXR &= 0x7F; //定時(shí)器時(shí)鐘12T模式TMOD &= 0xF0; //設(shè)置定時(shí)器模式TMOD |= 0x01; //設(shè)置定時(shí)器模式TL0 = 0x18; //設(shè)置定時(shí)初值TH0 = 0xFC; //設(shè)置定時(shí)初值TF0 = 0; //清除TF0標(biāo)志TR0 = 1; //定時(shí)器0開(kāi)始計(jì)時(shí)//復(fù)制過(guò)來(lái)之后不要忘記加上兩句話ET0 = 1;EA = 1;
}//Server定時(shí)器0的中斷服務(wù)函數(shù)
//a++是先進(jìn)行取值,后進(jìn)行自增。++a是先進(jìn)行自增,后進(jìn)行取值
void Timer0Server() interrupt 1
{//定時(shí)器的初值一定要記得從上面復(fù)制過(guò)來(lái)TL0 = 0x18; //設(shè)置定時(shí)初值TH0 = 0xFC; //設(shè)置定時(shí)初值if(++Key_Slow_Down == 10) Key_Slow_Down = 0;if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;if(++Seg_Pos == 6) Seg_Pos = 0;Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos]);//模板以外的東西if(System_Flag == 1)//倒計(jì)時(shí)開(kāi)始{if(++Timer_1000ms == 1000){Timer_1000ms = 0;Time_Count--;//相當(dāng)于1s中減少一次(倒計(jì)時(shí)一次)if(Time_Count==255) Time_Count=0;}}if(++Timer_500ms == 500){Timer_500ms = 0;Seg_Flag ^= 1;//因?yàn)槟J(rèn)值為0,只需要對(duì)其取反即可,不需要賦值,可以用^=1來(lái)對(duì)一個(gè)變量取反}
}
//主函數(shù)
void main()
{Timer0Init();//上電時(shí)立即調(diào)用定時(shí)器初始化函數(shù)while(1){//三大處理單元:按鍵、數(shù)碼管、LEDKey_Proc();Seg_Proc();Led_Proc();}
}
參考視頻:https://www.bilibili.com/video/BV1TR4y1k7iz?p=6&vd_source=5af7b905774c79f1754cd4ab83975115