|
前段時(shí)間看到了分層思想、時(shí)間片輪轉(zhuǎn)和狀態(tài)機(jī)的相關(guān)文章正好近期手上有一些小項(xiàng)目,于是就進(jìn)行了一些嘗試。相關(guān)的概念就不在細(xì)說了,很多嵌入式的公眾號(hào)文章都有介紹過,下面只敘述下我開發(fā)的經(jīng)歷幫助后來者少走彎路也是我個(gè)人的一個(gè)記錄。
我在看到講述相關(guān)思想的文章后在腦子里想著架構(gòu)出一個(gè)相對(duì)比較完善的系統(tǒng)。
分層思想不用多說根據(jù)相應(yīng)的軟硬件結(jié)構(gòu)進(jìn)行分層即可,其中的好處會(huì)在代碼復(fù)用時(shí)體現(xiàn)出來。
時(shí)間片輪轉(zhuǎn)思想在我個(gè)人實(shí)踐的過程中走了很多彎路,本人使用的硬件為清翔電子的最小系統(tǒng)板,在最開始進(jìn)行開發(fā)時(shí)使用定時(shí)器的方式對(duì)固定延時(shí)變量(REF20MS等)進(jìn)行相應(yīng)的環(huán)形累加(if(REF20MS==0)REF20MS=NUM20MS)(NUM20MS為宏定義的定時(shí)器計(jì)數(shù)記錄到對(duì)應(yīng)時(shí)間所需要的值)。然后當(dāng)相應(yīng)的變量計(jì)數(shù)完成后對(duì)相應(yīng)的標(biāo)志位進(jìn)行計(jì)數(shù)。
在我最初的構(gòu)想中,希望能夠完成一個(gè)多個(gè)需要相同的延時(shí)時(shí)間的任務(wù)對(duì)同一個(gè)標(biāo)記位的檢測即可完成延時(shí)的效果,但是在實(shí)際實(shí)現(xiàn)過程中遇到了很多問題。
1、如何判定任務(wù)1完成了20ms延時(shí)(僅作為舉例),判定相應(yīng)的延時(shí)時(shí)間的話需要對(duì)REF20MS的值進(jìn)行記錄當(dāng)該變量再一次到達(dá)記錄值時(shí)則說明完成20ms延時(shí),這有一個(gè)問題就是定時(shí)器中斷的時(shí)間一定時(shí)比單片機(jī)主函數(shù)中運(yùn)行的時(shí)間要慢的于是當(dāng)該變量進(jìn)行記錄時(shí)定時(shí)器未能及時(shí)對(duì)延時(shí)記錄變量進(jìn)行增減從而導(dǎo)致沒有延時(shí)的現(xiàn)象,當(dāng)然這種問題可以通過再增加一個(gè)記錄次數(shù)的標(biāo)記位來解決但是還有更好的解決方式我下面會(huì)講。
2、如何多個(gè)任務(wù)同時(shí)標(biāo)記并使用同一個(gè)延時(shí)變量,這個(gè)問題使用變量記錄加標(biāo)記位的方式可以去解決但是結(jié)構(gòu)復(fù)雜較為繁瑣。
在遇到上述問題后我改變了想法,使用一個(gè)u32位(u64更好但是51不支持u64)的變量(u32 TimeRef)作為統(tǒng)一的一個(gè)時(shí)間片(定時(shí)器125us中斷一次,足夠使用一周左右),對(duì)每個(gè)任務(wù)定義一個(gè)_DELAY變量(如按鍵:u32 KEY_DELAY) 在每次需要延時(shí)時(shí)KEY_DELAY=TimeRef+NUM_20MS;(NUM20MS為宏定義的定時(shí)器計(jì)數(shù)記錄到對(duì)應(yīng)時(shí)間所需要的值),在使用狀態(tài)機(jī)的思想進(jìn)行狀態(tài)轉(zhuǎn)移即可。能夠較為簡單的時(shí)間一些任務(wù)輪轉(zhuǎn)的功能,整體代碼理解起來也比較簡單。整體單片機(jī)代碼如下:
- #include<reg52.h>
- #include<intrins.h>
- //嘗試分層思想與時(shí)間片輪轉(zhuǎn)
- #define u8 unsigned char
- #define u16 unsigned int
- #define u32 unsigned long int
- //按鍵引腳映射
- sbit KEY1=P3^5;
- sbit KEY2=P3^4;
- sbit KEY3=P3^3;
- sbit KEY4=P3^2;
- sbit LED1=P1^0;
- u8 KEY_DAT=0;//按鍵寄存器按鍵為1存儲(chǔ)當(dāng)前被按下的按鍵鍵值,0為無按鍵
- u8 SEG7[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
- //時(shí)間片為125us
- #define NUM_1MS 8
- #define NUM_2MS 16
- #define NUM_5MS 40
- #define NUM_20MS 160
- #define NUM_100MS 800
- #define NUM_200MS 1600
- #define NUM_500MS 4000
- #define NUM_1000MS 8000
- //時(shí)間片輪轉(zhuǎn)變量
- u32 TimeRef=0;
- //任務(wù)延時(shí)變量
- //按鍵任務(wù)
- u32 KEY_DELAY =0;
- u8 KEY_STATE =0;
- u8 KEY_DATx =0;
- //顯示任務(wù)
- u32 SEG_DELAY =0;
- u8 SEG_STATE =0;//0位標(biāo)記是否第一次進(jìn)入
- u8 SEG_NUM[4] ={0,0,0,0};
- u8 SEG_I =0;
- /////////////////////////函數(shù)聲明/////////////////////////////////
- //讀按鍵鍵值
- u8 ReadKeyDat(void);
- //讀按鍵寄存器
- u8 ReadKeyReg(void);
- //中斷初始化函數(shù)
- void IsrInit(void);
- //數(shù)碼管顯示控制函數(shù)
- void SegDisplay(u16 num);
- void main(void)
- {
- u16 num=0;
- u8 key=0;
- IsrInit();
- while(1)
- {
- SegDisplay(num);
- key = ReadKeyDat();
- if(key==1)
- num++;
- if(key==2)
- num--;
- // if(key==3)
- // LED1=0;
- // if(key==4)
- // LED1=1 ;
- }
-
- }
- //數(shù)碼管顯示控制函數(shù)
- void SegDisplay(u16 num)
- {
- u8 i=0;
- if(SEG_STATE==0)//分割字符狀態(tài)
- {
- SEG_I=0;
- for(i=0;i<4;i++)
- {
- SEG_NUM[SEG_I++]=num%10;
- num=num/10;
- }
- SEG_STATE=1;
-
- }
-
- if(SEG_STATE==1)//顯示狀態(tài)
- {
- P0=SEG7[SEG_NUM[4-SEG_I]];//[];
- P2=~(0x01<<(SEG_I-1));
- SEG_I--;
- SEG_DELAY=TimeRef+NUM_5MS;
- SEG_STATE=2;
- }
- if(SEG_STATE==2)//延時(shí)等待狀態(tài)
- {
- if(TimeRef >= SEG_DELAY)
- {
- //判斷是否為最后一次延時(shí)
- if(SEG_I==0)
- SEG_STATE=0;
- else
- SEG_STATE=1;
- }
- }
-
- }
- //讀按鍵鍵值
- u8 ReadKeyDat(void)
- {
- ReadKeyReg();
- if(KEY_STATE == 0)//第一次讀取狀態(tài)
- {
- if(KEY_DAT!=0)//讀取到按鍵
- {
- KEY_DATx=KEY_DAT;
- KEY_DELAY=TimeRef+NUM_100MS;
- KEY_STATE=1;
- }
- }
-
- if(KEY_STATE == 1)//延時(shí)狀態(tài)
- {
- if(TimeRef >= KEY_DELAY)
- {
- KEY_STATE=2;
- }
- }
- if(KEY_STATE == 2)//第二次讀取狀態(tài)
- {
- if(KEY_DATx == KEY_DAT)//讀取到按鍵
- {
- KEY_STATE=0;
- return KEY_DATx;
- }
- KEY_STATE=0;
- }
- return 0;
- }
- //讀按鍵寄存器
- u8 ReadKeyReg(void)
- {
- if(KEY1==0)
- {
- KEY_DAT=1;
- return 1;
- }
- if(KEY2==0)
- {
- KEY_DAT=2;
- return 1;
- }
- if(KEY3==0)
- {
- KEY_DAT=3;
- return 1;
- }
- if(KEY4==0)
- {
- KEY_DAT=4;
- return 1;
- }
- KEY_DAT=0;
- return 0;
- }
- //中斷初始化函數(shù)
- void IsrInit(void)
- {
- EA=1;
-
- //使能定時(shí)器中斷并開啟定時(shí)器
- // ET0=1;
- // TR0=1;
- //ET1=1;
- //使能兩個(gè)外部中斷并將其設(shè)定為跳沿觸發(fā)
- // EX0=1;
- // IT0=1;
- // EX1=1;
- // IT1=1;
- //定時(shí)器0,方式2,計(jì)數(shù)器
- TMOD|=0x02;
- TH0=0x8d;//125us 中斷一次
- TL0=0x8d;
- ET0=1;
- TR0=1;
- // //使用定時(shí)器1,方式2,計(jì)數(shù)器
- // TMOD|=0x20;
- // TH1=0x8d;//125us 中斷一次
- // TL1=0x8d;
- }
- //定時(shí)器0,提供基礎(chǔ)時(shí)鐘125us中斷1次
- //////////////////////////統(tǒng)一時(shí)間完成標(biāo)志位可能沒有意義//////////////////////////////////////
- int Tim0Isr() interrupt 1 using 1
- {
- TimeRef++;
- // P0=SEG7[TimeRef/100%10];//[];
- // P2=0xfe;
- }
復(fù)制代碼 Keil代碼下載:
1、按鍵檢測控制數(shù)碼管顯示.7z
(16.25 KB, 下載次數(shù): 119)
2021-11-17 18:07 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|
評(píng)分
-
查看全部評(píng)分
|