孔憲青
(威海職業(yè)學(xué)院,山東 威海 264200)
基于單片機(jī)運(yùn)行的多線程任務(wù)狀態(tài)機(jī)
孔憲青
(威海職業(yè)學(xué)院,山東 威海 264200)
本文目的是改進(jìn)單片機(jī)的編程方式。VHDL中常用的狀態(tài)機(jī)編程方法,被引入到單片機(jī)的編程結(jié)構(gòu)中,并對(duì)兩種結(jié)構(gòu)做出對(duì)比和闡述。本文闡述的程序結(jié)構(gòu)可以提供一種低成本的實(shí)時(shí)系統(tǒng)解決方式,而其編程思路是比事件觸發(fā)狀態(tài)機(jī)更為復(fù)雜和有效的單片機(jī)編程方法。
定時(shí)器;狀態(tài)機(jī);PLD;并行線程
單片機(jī)通過C語言實(shí)現(xiàn)程序的運(yùn)行,盡管通過操作系統(tǒng)可以實(shí)現(xiàn)多任務(wù)運(yùn)行,但本質(zhì)上還是通過程序分時(shí)復(fù)用實(shí)現(xiàn)的多任務(wù)處理。并且大多數(shù)的操作系統(tǒng)使用一個(gè)定時(shí)器實(shí)現(xiàn)操作系統(tǒng)的分時(shí)調(diào)用。本文通過對(duì)定時(shí)器的進(jìn)一步挖掘,實(shí)現(xiàn)在低RAM下并行進(jìn)程的程序運(yùn)行。
定時(shí)器作為操作系統(tǒng)的時(shí)鐘節(jié)拍,起到定時(shí)切換任務(wù)等作用,但需要消耗RAM空間,任務(wù)越多內(nèi)容越復(fù)雜,對(duì)于RAM空間的消耗也越多。對(duì)于大RAM的單片機(jī)系統(tǒng),直接上操作系統(tǒng)即可,而對(duì)于小RAM的單片機(jī),若希望具有較好的實(shí)時(shí)性,則需要進(jìn)一步挖掘單片機(jī)中冗余的定時(shí)器,耗盡硬件資源。下面就是通過定時(shí)器切換任務(wù)的代碼(以最簡的51單片機(jī)的T 2定時(shí)器下的C程序?yàn)槔?:
void _T2(void) interrupt 5{
static unsigned char m=0,i=j=0; //m為同屬性任務(wù)分散標(biāo)志,i,j為異屬性任務(wù)分散標(biāo)志
if(m==101) m=0; else m++;
if(m%50==0) aaa(); //同屬性任務(wù)aaa
if((m+25)%50==0) bbb(); //任務(wù)bbb和aaa需要等間隔分離
i++;j++; //異屬性任務(wù)標(biāo)志i和j
if(i==20){i==0; ccc();} //i對(duì)應(yīng)任務(wù)ccc具有獨(dú)立性
if(j==30){j==0;ddd();} } //ccc和ddd是不相關(guān)任務(wù),各自有自己的運(yùn)行時(shí)間
以上的四個(gè)任務(wù)盡可能地執(zhí)行后即實(shí)現(xiàn),以節(jié)約RAM空間。靜態(tài)標(biāo)量m、i、j用于區(qū)別任務(wù)類型以平均時(shí)間軸分配任務(wù)。
一個(gè)定時(shí)器可以出現(xiàn)一個(gè)時(shí)間軸,在這個(gè)時(shí)間軸上來平攤?cè)蝿?wù)。
狀態(tài)機(jī)的使用在單片機(jī)中不多,因?yàn)閱纹瑱C(jī)大多以時(shí)間軸來編寫程序,方便快捷,最普通while(1){}類型。狀態(tài)機(jī)的使用一般在硬件描述語言中,例如VHDL來描述PLD。時(shí)序并行邏輯都是時(shí)間脈沖的形式描述各種并行的時(shí)序邏輯電路。例如下面這四個(gè)進(jìn)程:
process(clk,clk1,clk2); //對(duì)振蕩器進(jìn)行分頻,得到時(shí)基脈沖clk1和clk2
process(clk1,aaa,bbb); //時(shí)基clk1處理aaa和bbb的輸出宏單位
process(clk1,ccc.ddd); //時(shí)基clk1并行處理的ccc和ddd的輸出宏單位
process(clk2,eee); //不同時(shí)基的并行eee輸出宏單位
采用VHDL中常用的硬件編程方法狀態(tài)機(jī),可采用標(biāo)準(zhǔn)的三段式狀態(tài)機(jī)如下:
process(reset,clk1,state); //時(shí)序邏輯轉(zhuǎn)移
process(state,其他條件); //組合邏輯轉(zhuǎn)移表
pocess(state); //組合邏輯輸出
以上是PLD器件的基本而且有效的編程方式,以狀態(tài)量連接程序段的各部分,它的優(yōu)點(diǎn)是以事件(或者是條件)為核心驅(qū)動(dòng)各個(gè)部分。狀態(tài)機(jī)編程方式必須有個(gè)時(shí)基觸發(fā)脈沖,沒有這個(gè)時(shí)基,狀態(tài)機(jī)就運(yùn)行不下去。
單片機(jī)定時(shí)器可以固定時(shí)間提供中斷,這個(gè)中斷可以把時(shí)間軸劃分成一段一段,類似脈沖的形式。這非常類似于PLD器件中的分頻器的作用。通過中斷的這個(gè)時(shí)基實(shí)現(xiàn)時(shí)序邏輯轉(zhuǎn)移,而單片機(jī)中的各個(gè)任務(wù)就可以寫成狀態(tài)機(jī)的模式。例如中斷按鍵程序?qū)懗蔂顟B(tài)機(jī)模式:
static void StateMachine_key(void){
static enum StateKey sKey=sInit; //采用C中的枚舉類型,設(shè)置枚舉變量的初值
static unsigned char key_now=1;
unsigned char key_past;
key_past=key_now; //三段式按鍵狀態(tài)機(jī),需要時(shí)鐘脈沖
if(KEY!=0xff) key_now=0; //這里標(biāo)準(zhǔn)是時(shí)序邏輯轉(zhuǎn)移
else key_now=1; //按鍵對(duì)比前次和這次的值,檢測(cè)是否有按下
switch(sKey) { //組合邏輯轉(zhuǎn)移
case sInit:if((key_past==1)&&(key_now==0)) sKey=sPush; break;
case sPush:if((key_past==0)&&(key_now==1)) sKey=sPop; break;
case sPop: sKey=sInit; break;
default: sKey=sInit;}
switch(sKey){ //sInit、sPush、sPop是枚舉量sKey的枚舉值
case sInit: break;
case sPush: switch(KEY){
case 0xfe: aaa(); break; //按下S1,執(zhí)行任務(wù)aaa
case 0xfd: bbb(); break; //按下s2,執(zhí)行任務(wù)bbb
……
default: xxx();}
break;
case sPop: break;
default: ;}}
以上這個(gè)狀態(tài)機(jī)可以放在中斷中,因?yàn)橹袛啾旧砭褪菚r(shí)基,也就是時(shí)鐘脈沖驅(qū)動(dòng)了狀態(tài)機(jī),程序運(yùn)行實(shí)時(shí)性強(qiáng),形成事件觸發(fā)狀態(tài)機(jī)模式,但缺點(diǎn)是狀態(tài)機(jī)不能太長,不然會(huì)影響其他狀態(tài)機(jī)的實(shí)時(shí)性;其他方式是定時(shí)中斷提供時(shí)基標(biāo)志,按鍵狀態(tài)機(jī)可以放到while(1)中,只要能檢測(cè)到時(shí)基標(biāo)志即可,這樣形成的就是前后臺(tái)的程序。
定時(shí)中斷使連續(xù)運(yùn)行的時(shí)間軸變成了脈沖形式,即離散化了單片機(jī)程序。通過狀態(tài)機(jī)判斷運(yùn)行這些離散化的程序段。這樣通過定時(shí)器把單片機(jī)變成了PLD器件實(shí)現(xiàn)了并行邏輯。當(dāng)然這種并行邏輯是偽的,因?yàn)槌绦驁?zhí)行還是順序的,CPU也只有一個(gè)。單片機(jī)形成的時(shí)基可以有多個(gè),例如之前的m、i、j形成的時(shí)基就是不同的。T2定時(shí)中斷可以變成如下形式:
if(m==11){m=0;StateMachine_Key();}
else m++; //10次基礎(chǔ)中斷產(chǎn)生的時(shí)基觸發(fā)驅(qū)動(dòng)按鍵狀態(tài)機(jī)
if(i==25){i==0; 狀態(tài)機(jī)模塊} //i和m是不同屬性的時(shí)基,觸發(fā)不同的狀態(tài)機(jī)任務(wù)
else i++; //異屬性時(shí)基i
可以看出,定時(shí)器就是PLD中的振蕩器,由計(jì)數(shù)單位m和i實(shí)現(xiàn)了VHDL中的分頻器。狀態(tài)機(jī)模塊放到定時(shí)中斷中實(shí)現(xiàn)三段式狀態(tài)機(jī)的時(shí)序邏輯轉(zhuǎn)移,其模塊內(nèi)部實(shí)現(xiàn)狀態(tài)轉(zhuǎn)移表和狀態(tài)輸出。定時(shí)器中可以放多個(gè)事件狀態(tài)機(jī),數(shù)量需要由時(shí)間軸的消耗計(jì)算。因此定時(shí)器內(nèi)部可以存在若干個(gè)事件狀態(tài)機(jī)。
單片機(jī)內(nèi)部一般有多個(gè)定時(shí)器,完成任務(wù)后還有冗余,則可以把這些冗余的定時(shí)器利用起來。一個(gè)單片機(jī)定時(shí)器就會(huì)形成一個(gè)時(shí)間軸,離散化后就是一個(gè)線程。因此定時(shí)器使用一個(gè)就是一個(gè)時(shí)間軸,它們互不關(guān)聯(lián),形成的就是真正的并行邏輯。也就是說多定時(shí)器的中斷時(shí)基就是PLD的并行線程。挖掘冗余的定時(shí)器就可以耗盡單片機(jī)的硬件資源,讓簡單的單片機(jī)完成更復(fù)雜更實(shí)時(shí)性強(qiáng)的任務(wù)。具體框架如下:
void _xxx(void) interrupt ?{
//定時(shí)器xxx離散時(shí)間軸
static unsigned char m=0,i=0;
if(m==11){m=0; 狀態(tài)機(jī)模塊a;}
else m++;
if(i==25){i==0; 狀態(tài)機(jī)模塊b;}
else i++; }
void _yyy(void) interrupt ?{
//定時(shí)器yyy離散時(shí)間軸
{…………}
以上兩個(gè)定時(shí)器形成不同的時(shí)間軸,即兩個(gè)并行線程。
定時(shí)器作為中斷時(shí)基使用最簡單的即可,這樣對(duì)于一些定時(shí)器多的單片機(jī)尤其有效。注意所有的任務(wù)中使用的RAM單元,防止事件狀態(tài)機(jī)的數(shù)據(jù)覆蓋。并行的線程之間如果需要數(shù)據(jù)溝通和相互作用,使用標(biāo)志位和標(biāo)志序列進(jìn)行溝通。一些實(shí)時(shí)性不強(qiáng)的狀態(tài)機(jī)完全可以放在while(1)中,使用標(biāo)志位激活。
Multi Thread Task State Machine Based on Single Chip Microcomputer
Kong Xianqing
(WeihaiVocationalCollege,WeihaiShandong264200,China)
The purpose of this paper is to improve the programming method of MCU. The commonly used programming mode of state machine inVHDL is introduced into the microcontroller programming structure, and two kinds of structure are made comparison and elaboration. The program structure described in this paper can provide a real-time system with low cost solutions, and the programming is more complex microcontroller programming method and effective than the event triggered state machine.
timer; state machine; PLD; parallel thread
2016-10-13
孔憲青(1976- ),男,山東威海人,講師,碩士研究生,專業(yè):控制理論與工程,研究方向:單片機(jī)應(yīng)用。
1674- 4578(2016)06- 0064- 02
TP368.1;TP311.11
A