微控制器就那點資源,為啥還要用RTOS?
對於搞微控制器的特別用8051系列工程師來說,談到微控制器的RTOS,很多時候會問一句:“為什麼要用RTOS?微控制器就這一點資源,使用RTOS能保證效率嗎?”
對於這個問題,我會反問:“你用微控制器的目的是什麼?是為了用微控制器的C程式設計,微控制器的彙編程式設計甚至於用微控制器的二進位制指令程式設計?”上個世紀80年代,工程師用二進位制指令給Z80程式設計,現在還有誰在用?現在還有人死抱著彙編不放,但越來越多的人工程師使用C程式設計(我起初也是使用匯編的),為什麼?因為我們的目的是在有限的時間甚至是不充足的時間內把專案保質保量的完成!使用什麼工具和方法是次要的(如果你的專案以成本放在第一位,則另當別論,這時,也是要考慮開發時間的)。時間就是金錢啊,一個產品在微控制器上增加些許成本是可以接受的。況且,使用8051系列微控制器時,微控制器資源也常有富餘,CPU一般情況也只是空轉,這就為它使用RTOS創造了條件。
那麼,使用RTOS的好處呢?我舉一個例子吧。假設我們編一個序列通訊程式,通訊協議如下:
資料包長度為NBYTE,起始位元組為STARTBYTE1,STARTBYTE2,最後一個位元組為檢驗和,中間位元組不可能出現連續出現STARTBYTE1,STARTBYTE2。
第一種方法,在中斷中處理協議:
unsignedcharBuf[NBYTE-2];bitGetRight=0;
void comm(void) interrupt 4//"序列口中斷"{
static unsigned char Sum,Flag=0,i;
unsigned char temp;
if(RI==1)
{
RI=0;
temp=SBUF;
switch(Flag)
{
case 0:
if(temp==STARTBYTE1)
{
Flag=1;
}
break;
case 1:
if(temp==STARTBYTE2)
{
Sum=STARTBYTE1+STARTBYTE2;
i=0;
Flag=2;
break;
}
if(temp==STARTBYTE1) break;
Flag=0;
break;
case 2:
if(temp==STARTBYTE1)
{
Flag=3;
break;
}
Sum+=temp;
if((i>=(NBYTE-3))&&Sum==0)
{
GetRight=1;
Flag=0;
break;
}
Buf[i++]=temp;
break;
case 3:
if(temp==STARTBYTE2)
{
Sum=STARTBYTE1+STARTBYTE2;
Flag=2;
i=0;
break;
}
Sum+=STARTBYTE1;
if((i>=(NBYTE-3))&&Sum==0)
{
GetRight=1;
Flag=0;
break;
}
Buf[i++]=STARTBYTE1;
if(temp==STARTBYTE1)
{
break;
}
Sum+=temp;
if((i>=(NBYTE-3))&&Sum==0)
{
GetRight=1;
Flag=0;
break;
}
Buf[i++]=temp;
Flag=2;
break;
}
}}
第二種方法,使用佇列中斷函式:
voidcomm(void)interrupt4//"序列口中斷"{
if(RI==1)
{
RI=0;
SBUF入隊;
}}
主程式不斷呼叫的函式:
unsigned char Buf[NBYTE-2];
unsigned char ReadSerial(unsigned char *cp){
unsigned char i;
unsigned char temp,Sum;
temp=佇列中資料個數;
if(temp<(NBYTE)) return 0;
出隊 temp;
if(temp!=STARTBYTE1) return 0;
temp=佇列首位元組;
if(temp!=STARTBYTE2) return 0;
出隊 temp;
sum=STARTBYTE1+STARTBYTE2;
for(i=0;i
{
temp=佇列首位元組;
if(temp==STARTBYTE1)
{
temp=佇列次首位元組;
if(temp==STARTBYTE2) return 0;
}
出隊 temp;
*cp++=temp;
Sum+=temp;
}
temp=佇列首位元組;
Sum+=temp;
if(Sum!=0) return 0;
出隊 temp;
return 1;}
第三種方法,使用RTOS中斷函式:
void comm(void) interrupt 4//"序列口中斷"{
OS_INT_ENTER();
if(RI==1)
{
RI=0;
OSIntSendSignal(RECIVE_TASK_ID);
}
OSIntExit();}
ID為RECIVE_TASK_ID的任務
void Recuve(void){
unsigned char temp,temp1,Sum,i;
OSWait(K_SIG,0);
temp=SBUF;
while(1)
{
while(1)
{
OSWait(K_SIG,0);
temp1=SBUF;
if((temp==STARTBYTE1)&&(temp1==STARTBYTE2)) break;
temp=temp1;
}
Sum=STARTBYTE1+STARTBYTE2;
OSWait(K_SIG,0);
temp=SBUF;
for(i=0;i
{
OSWait(K_SIG,0);
temp1=SBUF;
if((temp==STARTBYTE1)&&(temp1==STARTBYTE2))
{
OSWait(K_SIG,0);
temp=SBUF;
i=-1;
Sum=STARTBYTE1+STARTBYTE2;
continue;
}
Buf[i]=temp;
Sum+=temp;
temp=temp1;
}
Sum+=temp1;
if(Sum==0) OSSendSignal(命令解釋任務 ID);
}}
以下為這幾種方法的比較:
可讀性和程式設計容易性方面,第三鍾方法最好(如果允許使用goto語句,程式更加簡單易讀),第二種次之(因為要編佇列程式),第一種最差。如果協議更加複雜,這方面更加明顯。程式簡單易讀,自然出錯機會小了。
RAM佔用方面,第三種方法較少,第二種最多(因為佇列佔用大量空間),第一種最少。
中斷執行時間方面,第三種方法最長,第二種最短,第一種較長。
從功能方面,第三種方法最強,它還可以進行超時處理(雖然例子程式沒有),其它方法均不行。
如果資料來的太快,命令處理程式來不及處理,三種方法處理方式不太一樣,第一種和第三種方法類似:丟棄以前資料,第二種則是丟棄後到的資料。而且,第二種方法必須等命令處理程式完成後才處理下一個資料包,而第一種和第三種方只需命令處理程式將資料收取後就可處理下一個資料包。也就是說,第一種和第三種與命令處理程式並行處理,第二種方法為序列處理。
現在,一般情況下,開發的效率第一,執行的效率(包括執行時間和資源佔用)第二。在這種情況下,降低些許效率換取開發的效率的較大提高,何樂而不為?何況,單個模組的執行的效率高不等於整個程式執行效率高。例如,如果程式需要等待一段時間,一般用程式延時或定時器延時。無論何種方法,CPU不再處理其它工作,效率很低。而用RTOS,等待的時候CPU可以處理其它工作,效率得到提高。
走進ARM-ARM開發環境搭建
http://www.makeru.com.cn/live/1758_318.html?s=143793
ARM體系架構
http://www.makeru.com.cn/live/1392_587.html?s=143793
ARM之蜂鳴器播放音樂
http://www.makeru.com.cn/live/1758_325.html?s=143793
ARM之中斷GIC分析
http://www.makeru.com.cn/live/1758_328.html?s=143793