|
程序的多任務(wù)和資源復(fù)用舉例
有一臺(tái)機(jī)電設(shè)備 , 有兩個(gè)按鍵,控制設(shè)備的兩個(gè)不同部分。 現(xiàn)要求: 每個(gè)按鍵按下,相應(yīng)控制程序運(yùn)行。但兩個(gè)按鍵可以同時(shí)按下,就是說兩個(gè)控制程序可能 需要同時(shí)運(yùn)行。使用一個(gè)89C52,如何編寫程序?
注:此程序不使用RTOS等操作系統(tǒng)。
/*程序說明: 一)產(chǎn)生波形可以使用中斷中計(jì)數(shù)來產(chǎn)生精確的波形。 本答案中為更能體現(xiàn)程序的多任務(wù)和資源復(fù)用問題,采用主程序循環(huán)產(chǎn)生。 二)請(qǐng)?zhí)貏e注意,題意是兩個(gè)程序在并發(fā)運(yùn)行,實(shí)際按本答案可以擴(kuò)展到N個(gè)不同任務(wù)同時(shí)運(yùn)行,在此就不討論。 (對(duì)大程序結(jié)構(gòu)增加了很多其它的概念) 三)因?yàn)樵谡搲现苯淤N出,所以程序放在一個(gè)文件中。 應(yīng)該按Timer.c, Key.c, Const.h(存放常量定義),Task1, Task2, Answer.c存放 */ #include <REG52.h>
/*Timer*/ bit fTimer0_2ms; /*T0中斷產(chǎn)生的標(biāo)志,準(zhǔn)備傳遞給主循環(huán)*/ bit fSYS_2ms; /*系統(tǒng)T0中斷產(chǎn)生的標(biāo)志,12M,主循環(huán)使用*/ bit fSYS_20ms; /*每20MS產(chǎn)生一次的消息*/
#define INT2MSCOUNT 10 /*產(chǎn)生2MS所需要的時(shí)間次數(shù)*/ unsigned char data mTimer_2msReg=INT2MSCOUNT; /*產(chǎn)生2MS所需要的寄存器*/ #define INT20MSCOUNT 10 /*產(chǎn)生20MS所需要的時(shí)間次數(shù),在20MS基礎(chǔ)上*/ unsigned char data mTimer_20msReg=INT20MSCOUNT; /*產(chǎn)生20MS所需要的寄存器,在20MS基礎(chǔ)上*/
/*KEY*/ unsigned char data mKey1SwapTask; /***按鍵任務(wù)寄存器***/ unsigned char data mKey2SwapTask; /***按鍵任務(wù)寄存器***/ sbit iKey1=P1^0; /*按鍵的輸入口*/ sbit iKey2=P1^1;
bit fKey1; /*為簡單化,沒使用隊(duì)列保存鍵值,使用標(biāo)志*/ bit fKey2; /*為簡單化,沒使用隊(duì)列保存鍵值,使用標(biāo)志*/
/*Task1*/ unsigned char data mTask1Id; /*任務(wù)一的任務(wù)號(hào)*/ unsigned char data mTask1_1HzReg; /*1hz時(shí)間寄存器*/ unsigned int data mTask1_2SReg; /*2S時(shí)間寄存器*/ sbit oTask1=P1^2; /*輸出方波口*/
/*Task2*/ unsigned char data mTask2Id; /*任務(wù)二的任務(wù)號(hào)*/ unsigned char data mTask2_1p2HzReg; /*1.2hz時(shí)間寄存器*/ sbit oTask2=P1^3; /*輸出方波口*/
/*---------------------------------------------------------------------------*/ /*產(chǎn)生以1MS為基礎(chǔ)的系統(tǒng)定時(shí)信號(hào),T0作為基準(zhǔn)定時(shí)器*/
/************************************************* 定時(shí)器T0初始化0.2MS,12M *************************************************/ void Timer0_Init() { TMOD|=0x2; /*8位定時(shí)器*/
TL0=TH0=~(200)+1; /*12M*/
TR0=1; ET0=1; }
/************************************************* 定時(shí)器0的中斷服務(wù),產(chǎn)生fTimer0_2ms *************************************************/ void timer0(void) interrupt 1 /*T0中斷*/ { mTimer_2msReg--; if(mTimer_2msReg==0){ mTimer_2msReg=INT2MSCOUNT; /*產(chǎn)生1MS所需要的寄存器*/ fTimer0_2ms=1; } }
/************************************************* 控制消息fSYS_2ms *************************************************/ void Timer0_MainLoop() { fSYS_2ms=0; fSYS_20ms=0;
if(fTimer0_2ms){ fTimer0_2ms=0; /*接收中斷過來的時(shí)間標(biāo)志,轉(zhuǎn)換為消息*/ fSYS_2ms=1; /*此消息在一周內(nèi)有效,被外部程序復(fù)用*/ /*產(chǎn)生20MS的消息*/ mTimer_20msReg--; if(mTimer_20msReg==0){ mTimer_20msReg=INT20MSCOUNT; /*產(chǎn)生20MS所需要的寄存器,在20MS基礎(chǔ)上*/ fSYS_20ms=1; } } }
/*---------------------------------------------------------------------------*/ /*按鍵掃描,包含兩個(gè)掃描任務(wù)*/ /********************************************** 每次系統(tǒng)時(shí)間進(jìn)入一次,20ms.這里把20MS判斷放進(jìn)來,好看點(diǎn) 按鍵掃描循環(huán) 為簡單化,沒使用隊(duì)列保存鍵值,使用標(biāo)志 那些重復(fù)發(fā)出N鍵,在這個(gè)結(jié)構(gòu)中非常容易加上 **********************************************/ void Key_MainLoop() { if(fSYS_20ms==0)return;
switch(mKey1SwapTask){ case 0:/***有按鍵按下嗎?***/ if(iKey1==0){ mKey1SwapTask=1; } break; case 1: /***鍵按下去抖延時(shí)***/ mKey1SwapTask=2; /***延時(shí)一個(gè)系統(tǒng)時(shí)間***/ break; case 2: /***鍵值判斷***/ if(iKey1==0){ fKey1=1; /*按鍵有效*/ mKey1SwapTask=3; /*去按鍵去抖*/ } else mKey1SwapTask=0; /*抖動(dòng)*/ break; case 3: /***有松開嗎?***/ if(iKey1==1){ mKey1SwapTask=4; } break; case 4: /***鍵松開去抖延時(shí)***/ mKey1SwapTask=5; /***延時(shí)一個(gè)系統(tǒng)時(shí)間***/ break; case 5: /***鍵值判斷***/ if(iKey1==1){ mKey1SwapTask=0; /*去按鍵檢測開始*/ } else mKey1SwapTask=3; /*抖動(dòng)*/ break; }
switch(mKey2SwapTask){ case 0:/***有按鍵按下嗎?***/ if(iKey2==0){ mKey2SwapTask=1; } break; case 1: /***鍵按下去抖延時(shí)***/ mKey2SwapTask=2; /***延時(shí)一個(gè)系統(tǒng)時(shí)間***/ break; case 2: /***鍵值判斷***/ if(iKey2==0){ fKey2=1; /*按鍵有效*/ mKey2SwapTask=3; /*去按鍵去抖*/ } else mKey2SwapTask=0; /*抖動(dòng)*/ break; case 3: /***有松開嗎?***/ if(iKey2==1){ mKey2SwapTask=4; } break; case 4: /***鍵松開去抖延時(shí)***/ mKey2SwapTask=5; /***延時(shí)一個(gè)系統(tǒng)時(shí)間***/ break; case 5: /***鍵值判斷***/ if(iKey2==1){ mKey2SwapTask=0; /*去按鍵檢測開始*/ } else mKey2SwapTask=3; /*抖動(dòng)*/ break; } }
/*---------------------------------------------------------------------------*/ /*任務(wù)一*/ /********************************************** 一個(gè)部分輸出1HZ的方波,2S后停止。 **********************************************/ void Task1_MainLoop() { switch(mTask1Id){ case 0: if(fKey1){ fKey1=0; /*接收該鍵值*/ mTask1_1HzReg=500/2; /*1hz時(shí)間寄存器,500ms,以2MS為單位*/ mTask1_2SReg=2000/2; /*2S時(shí)間寄存器,500ms,以2MS為單位*/ oTask1=0; mTask1Id=1; } break; case 1: if(fSYS_2ms){ mTask1_1HzReg--; if(mTask1_1HzReg==0){ oTask1=~oTask1; mTask1_1HzReg=500/2; /*1hz時(shí)間寄存器,500ms,以2MS為單位*/ }
mTask1_2SReg--; if(mTask1_2SReg==0){ oTask1=1; /*2S時(shí)間到*/ mTask1Id=0; } } break; } }
/*---------------------------------------------------------------------------*/ /*任務(wù)二*/ /********************************************** 一個(gè)一直輸出1.2hz的方波,直到按鍵再次按 **********************************************/ void Task2_MainLoop() { switch(mTask2Id){ case 0: if(fKey2){ fKey2=0; /*接收該鍵值*/ mTask2_1p2HzReg=416/2; /*1hz時(shí)間寄存器,832/2ms,以2MS為單位*/ oTask2=0; mTask2Id=1; } break; case 1: if(fKey2){ fKey2=0; oTask2=1; mTask2Id=0; } else { if(fSYS_2ms){ mTask2_1p2HzReg--; if(mTask2_1p2HzReg==0){ oTask2=~oTask1; mTask2_1p2HzReg=416/2; /*1hz時(shí)間寄存器,832/2ms,以2MS為單位*/ } } } break; } }
/*---------------------------------------------------------------------------*/ /*主程序*/ void main(){ Timer0_Init(); EA=1;
while(1){ Timer0_MainLoop(); Key_MainLoop(); Task1_MainLoop(); Task2_MainLoop(); } } |