2002年初,筆者著手寫一個IC卡預(yù)付費電表的工作程序,該電表使用Philips公司的8位51擴展型單片機87LPC764,要求實現(xiàn)很多功能,包括熄顯示、負荷計算與控制、指示閃爍以及電表各種參數(shù)的查詢等,總之,要使用時間的單元很多。筆者當時使用ASM51完成了這個程序的編寫,完成后的程序量是2KB多一點。后來,由于種種原因,這個程序并沒有真正使用,只是作了一些改動之后用在一個老化設(shè)備上進行計時與負荷計算。約一年后,筆者又重新改寫了這些代碼。
1系統(tǒng)的改進
可以說,這個用ASM51實現(xiàn)的代碼是沒有什么組織性可言的,要什么功能就加入什么功能,弄得程序的結(jié)構(gòu)非常松散,其實這也是導(dǎo)致筆者最終決定重新改寫這些代碼的原因。大家知道,87LPC764有4KB的FlashROM,而筆者的程序量只有2KB多點,因而第一個想法是改用C語言作為主要的開發(fā)語言,應(yīng)該不至于導(dǎo)致代碼空間不夠用。其次,考慮到需要定時功能的模塊(或稱任務(wù),以下統(tǒng)稱任務(wù))較多,有必要對這些任務(wù)進行有序的管理。筆者考慮使用時間片輪詢方式,即給每個要求時間管理的任務(wù)以一個時間間隔,時間間隔一到,即運行其代碼,達到合理使用系統(tǒng)定時器資源的目的。就51系統(tǒng)而言,一般至少一個定時器可用來進行時間片的輪詢?;谝陨系南敕?,構(gòu)造了下述數(shù)據(jù)類型。
typedef unsigned char uInt8
typedef struct {
void (*proc)( void ); /* 處理程序 */
uInt8 ms_count; /* 時間片大小 */
} _op_;
數(shù)據(jù)結(jié)構(gòu)定義好之后,接著就是實現(xiàn)代碼,包括三部分,即初始化數(shù)據(jù)、時間片的刷新與時間到執(zhí)行。
初始化數(shù)據(jù)。#defineproc_cnt0x08//定義過程或任務(wù)數(shù)量
//任務(wù)棧初始化
code _op_ Op[proc_cnt] = { { ic_check 10 } { disp_loop 100 }
{ calc_power 150 } { set_led 2 } … };
//設(shè)置時間片初始值
datauInt8time_val[proc_cnt]={10,100,150,2,…};
時間片刷新。
void time_int1( void ) interrupt 3
{
uInt8 cnt;
Time_Counter: = Time_Unit;
for ( cnt = 0; cnt < proc_cnt; cnt++ )
{
time_val[cnt]--;
}
}
任務(wù)的執(zhí)行。
void main( void )
{
uInt8 cnt;
init(); /*程序初始化 */
interrupt_on(); /* 打開中斷 */
do
{
for ( cnt = 0; cnt < proc_cnt; cnt++ )
{
if ( !time_val[cnt] )
{
time_val[cnt] = Op[cnt].ms_count;
Op[cnt].proc();
}
}
}
while ( 1 );
}
在上面的結(jié)構(gòu)定義中,proc是不能帶參數(shù)的,各任務(wù)之間的通信可以定義一個參數(shù)內(nèi)存塊,通過一種機制進行數(shù)據(jù)信息交互,如定義一個全局變量。對于小容量單片機系統(tǒng)而言,需要這樣做的任務(wù)并不多,總?cè)蝿?wù)量也不會太多,因而這種協(xié)調(diào)并不太難處理。也許大家都有這樣的認識,即一個實時系統(tǒng)中,差不多所有的具體任務(wù)都是有時間屬性的,即使是不需要定時的過程或任務(wù),也不見得要時時進行查詢與刷新。如IC卡介質(zhì)檢測,保證每秒一次就足夠了。因而,這些任務(wù)也可以列入到這個結(jié)構(gòu)中來。在以上的程序代碼中,考慮到單片機系統(tǒng)的RAM限制,不能像一些實時OS那樣將任務(wù)棧建立在RAM中。筆者將任務(wù)棧建立在代碼空間,因而不能在程序運行時動態(tài)地加入任務(wù),因此要求在程序編譯時,任務(wù)棧已經(jīng)確定。同時,定義一組計數(shù)值旗標time_val,記錄程序運行時的時間量,并在一個定時器中斷中對其進行刷新。改變時間片刷新中斷過程語句Time_Counter:=Time_Unit;中的Time_Unit,可以改變系統(tǒng)時間片的刷新粒度,一般這個值由系統(tǒng)的最小時間度量值確定。同時,由任務(wù)的執(zhí)行流程可知,此種系統(tǒng)構(gòu)造并沒有改變其前/后臺系統(tǒng)的性質(zhì),只是對后臺邏輯操作序列進行了有效管理。同時,如果將任務(wù)執(zhí)行流程進行一些更改,并保證時間片小的任務(wù)前置,如下述程序。
do
{
for ( cnt = 0; cnt < proc_cnt; cnt++ )
{
if ( !time_val[cnt] )
{
time_val[cnt] = Op[cnt].ms_count;
Op[cnt].proc();
break; /* 執(zhí)行完成后,重新進行優(yōu)先調(diào)度 */
}
}
}
while ( 1 );
則系統(tǒng)變?yōu)橐粋€以執(zhí)行頻率為優(yōu)先級的任務(wù)調(diào)度系統(tǒng)。當然,設(shè)置此種方式得非常小心,并要注意時間片的分配,如果時間片過小,則可能導(dǎo)致執(zhí)行頻率較低的任務(wù)難以被執(zhí)行;而如果存在兩個同樣的時間片,則更加危險,可能導(dǎo)致第二個具有相同時間片的任務(wù)不被執(zhí)行,因而,時間片的分配要合理,并保證其唯一性。
2性能分析與任務(wù)拆分
以上兩種任務(wù)管理方式,前一種按任務(wù)棧的順序與時間片的大小依次進行調(diào)度,暫且稱其為流水作業(yè)調(diào)度;而后一種,且稱其為頻率優(yōu)先調(diào)度。兩種方式各有優(yōu)缺點。流水作業(yè)調(diào)度的各任務(wù)具有等同優(yōu)先級,時間片一到即會被按序調(diào)用,時間片大小的次序與唯一性不作要求;缺點是可能導(dǎo)致時間片小的,即要求執(zhí)行得較快的任務(wù)等待過長的時間。頻率優(yōu)先調(diào)度的各任務(wù)按其時間片的大小,即執(zhí)行頻率劃分優(yōu)先級,時間片小的任務(wù),其執(zhí)行頻率高,總是具有較高的優(yōu)先權(quán),但時間片的分配得協(xié)調(diào),否則可能會導(dǎo)致執(zhí)行頻率低的任務(wù)長時間等待。要特別注意的是,兩種方式都有可能導(dǎo)致一些任務(wù)長時間等待,時間片所設(shè)定的時間也因此不能作為精確時間的依據(jù),根據(jù)系統(tǒng)的要求或需要,甚至要在任務(wù)執(zhí)行過程中進行某些保護工作,如中斷屏蔽等,因而在進行任務(wù)規(guī)劃時要注意。如果一個任務(wù)較繁瑣或可能要等待很長時間,則應(yīng)當考慮任務(wù)的拆分,把一個較大的任務(wù)細化為較小的任務(wù),把一個費時長的任務(wù)劃分為多個費時小的任務(wù),協(xié)同完成其功能。如在等待時間長的情況下,可附加一個定時任務(wù),定時任務(wù)到則發(fā)送一個消息旗標,主過程沒有檢測到消息旗標就馬上返回,否則繼續(xù)執(zhí)行。下面是示例代碼,假定該任務(wù)將等待很長時間,現(xiàn)將其拆分為兩個任務(wù)proc1與proc2協(xié)同完成原來的工作,proc1每100個時間單位執(zhí)行一次,而proc2每200個時間單位執(zhí)行一次。
/* 定義兩個任務(wù),并將其加入到任務(wù)棧中。 */
code _op_Op[proc_cnt] = { …{ proc1 100 } { proc2 200 } };
data inttime1_Seg; /* 定義一個全局旗標 */
/* 任務(wù)實現(xiàn) */
void proc1( void )
{
if ( time1_Seg )
exit;
else
time1_Seg = const_Time1; /* 如果時間到了,則恢復(fù)初值并 */
/* 接著執(zhí)行下列代碼。 */
… /* 任務(wù)實際執(zhí)行代碼 */
}
void proc2( void )
{
if ( time1_Seg )
time1_Seg--;
}
由上例可以看出,任務(wù)拆分后,幾乎不占過多的CPU時間,使得任務(wù)的等待時間大減,讓CPU有足夠的時間進行任務(wù)管理與調(diào)度。同時也讓程序的結(jié)構(gòu)性與可讀性大為加強。
-
單片機
+關(guān)注
關(guān)注
6076文章
45501瀏覽量
670814 -
IC
+關(guān)注
關(guān)注
36文章
6415瀏覽量
185748 -
cpu
+關(guān)注
關(guān)注
68文章
11287瀏覽量
225168 -
電表
+關(guān)注
關(guān)注
13文章
873瀏覽量
37576
原文標題:如何用單片機完成多任務(wù)操作
文章出處:【微信號:weixin21ic,微信公眾號:21ic電子網(wǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
實時多任務(wù)操作系統(tǒng)
setjmp構(gòu)建簡單協(xié)作式多任務(wù)系統(tǒng)
實時多任務(wù)操作系統(tǒng)(RTOS)
如何去實現(xiàn)基于stm32的FreeRTOS多任務(wù)程序
多任務(wù)編程多任務(wù)處理是指什么
如何在STM32下完成一個基于FreeRTOS的多任務(wù)程序
VxWorks操作系統(tǒng)及實時多任務(wù)程序設(shè)計
VxWorks下實時多任務(wù)程序的實現(xiàn)
基于消息驅(qū)動的多任務(wù)操作機制
MSP430單片機實時多任務(wù)操作系統(tǒng)c源代碼
DSP實時多任務(wù)操作系統(tǒng)設(shè)計與實現(xiàn)
51單片機多任務(wù)操作系統(tǒng)的原理與實現(xiàn)
基于實時操作系統(tǒng)的單片機多任務(wù)應(yīng)用程序設(shè)計
一種實時嵌入式多任務(wù)微內(nèi)核的分析與改進
STM32 簡單多任務(wù)調(diào)度的方法與程序例程
改進一個可實現(xiàn)多任務(wù)操作電表的代碼程序
評論