標(biāo)題:
51單片機(jī)按鍵數(shù)碼管顯示 時(shí)間片輪轉(zhuǎn)+狀態(tài)機(jī) 源程序
[打印本頁]
作者:
wyqf
時(shí)間:
2021-11-17 11:00
標(biāo)題:
51單片機(jī)按鍵數(shù)碼管顯示 時(shí)間片輪轉(zhuǎn)+狀態(tài)機(jī) 源程序
前段時(shí)間看到了分層思想、時(shí)間片輪轉(zhuǎn)和狀態(tài)機(jī)的相關(guān)文章正好近期手上有一些小項(xiàng)目,于是就進(jìn)行了一些嘗試。相關(guān)的概念就不在細(xì)說了,很多嵌入式的公眾號文章都有介紹過,下面只敘述下我開發(fā)的經(jīng)歷幫助后來者少走彎路也是我個(gè)人的一個(gè)記錄。
我在看到講述相關(guān)思想的文章后在腦子里想著架構(gòu)出一個(gè)相對比較完善的系統(tǒng)。
分層思想不用多說根據(jù)相應(yīng)的軟硬件結(jié)構(gòu)進(jìn)行分層即可,其中的好處會在代碼復(fù)用時(shí)體現(xiàn)出來。
時(shí)間片輪轉(zhuǎn)思想在我個(gè)人實(shí)踐的過程中走了很多彎路,本人使用的硬件為清翔電子的最小系統(tǒng)板,在最開始進(jìn)行開發(fā)時(shí)使用定時(shí)器的方式對固定延時(shí)變量(REF20MS等)進(jìn)行相應(yīng)的環(huán)形累加(if(REF20MS==0)REF20MS=NUM20MS)(NUM20MS為宏定義的定時(shí)器計(jì)數(shù)記錄到對應(yīng)時(shí)間所需要的值)。然后當(dāng)相應(yīng)的變量計(jì)數(shù)完成后對相應(yīng)的標(biāo)志位進(jìn)行計(jì)數(shù)。
在我最初的構(gòu)想中,希望能夠完成一個(gè)多個(gè)需要相同的延時(shí)時(shí)間的任務(wù)對同一個(gè)標(biāo)記位的檢測即可完成延時(shí)的效果,但是在實(shí)際實(shí)現(xiàn)過程中遇到了很多問題。
1、如何判定任務(wù)1完成了20ms延時(shí)(僅作為舉例),判定相應(yīng)的延時(shí)時(shí)間的話需要對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í)對延時(shí)記錄變量進(jìn)行增減從而導(dǎo)致沒有延時(shí)的現(xiàn)象,當(dāng)然這種問題可以通過再增加一個(gè)記錄次數(shù)的標(biāo)記位來解決但是還有更好的解決方式我下面會講。
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中斷一次,足夠使用一周左右),對每個(gè)任務(wù)定義一個(gè)_DELAY變量(如按鍵:u32 KEY_DELAY) 在每次需要延時(shí)時(shí)KEY_DELAY=TimeRef+NUM_20MS;(NUM20MS為宏定義的定時(shí)器計(jì)數(shù)記錄到對應(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存儲當(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
作者:
heicad
時(shí)間:
2021-11-18 06:01
好資料,51黑有你更精彩!!!
作者:
liht1634
時(shí)間:
2021-11-23 11:06
結(jié)構(gòu)清晰!贊!
作者:
luhonglang
時(shí)間:
2022-4-9 16:58
學(xué)習(xí)受教了,很有用
作者:
yinds5092
時(shí)間:
2022-8-3 15:19
51黑有你更精彩,學(xué)習(xí)使人進(jìn)步
作者:
youlinys
時(shí)間:
2022-9-8 12:12
正對這方面感興趣。
作者:
vikey_zhu
時(shí)間:
2022-10-13 10:42
學(xué)習(xí)使人進(jìn)步
作者:
dyx811
時(shí)間:
2022-10-16 15:18
動態(tài)掃描,最近在學(xué)習(xí)595驅(qū)動。謝謝分享
作者:
lhtlhtl
時(shí)間:
2022-10-17 06:40
時(shí)間片輪轉(zhuǎn)+狀態(tài)機(jī),精彩
作者:
zenghl
時(shí)間:
2022-10-18 13:11
時(shí)間片輪轉(zhuǎn)+狀態(tài)機(jī),精彩
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1