单片机就那点资源,为啥还要用RTOS?

Posted jinwenyi

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单片机就那点资源,为啥还要用RTOS?相关的知识,希望对你有一定的参考价值。

对于搞单片机的特别用8051系列工程师来说,谈到单片机的RTOS,很多时候会问一句:“为什么要用RTOS?单片机就这一点资源,使用RTOS能保证效率吗?”

 

对于这个问题,我会反问:“你用单片机的目的是什么?是为了用单片机的C编程,单片机的汇编编程甚至于用单片机的二进制指令编程?”上个世纪80年代,工程师用二进制指令给Z80编程,现在还有谁在用?现在还有人死抱着汇编不放,但越来越多的人工程师使用C编程(我起初也是使用汇编的),为什么?因为我们的目的是在有限的时间甚至是不充足的时间内把项目保质保量的完成!使用什么工具和方法是次要的(如果你的项目以成本放在第一位,则另当别论,这时,也是要考虑开发时间的)。时间就是金钱啊,一个产品在单片机上增加些许成本是可以接受的。况且,使用8051系列单片机时,单片机资源也常有富余,CPU一般情况也只是空转,这就为它使用RTOS创造了条件。

 

那么,使用RTOS的好处呢?我举一个例子吧。假设我们编一个串行通讯程序,通讯协议如下:

 

数据包长度为NBYTE,起始字节为STARTBYTE1,STARTBYTE2,最后一个字节为检验和,中间字节不可能出现连续出现STARTBYTE1,STARTBYTE2。

 

第一种方法,在中断中处理协议:

 

unsigned char Buf[NBYTE-2];bit GetRight=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;}}}

 

第二种方法,使用队列中断函数:

 

void comm(void) interrupt 4//"串行口中断"{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

以上是关于单片机就那点资源,为啥还要用RTOS?的主要内容,如果未能解决你的问题,请参考以下文章

iOS应用支持IPV6,就那点事儿

详述单片机固件模块化架构设计

详论单片机固件模块化架构设计(精华)

玩转Flume+Kafka原来也就那点事儿

iOS应用支持IPV6,就那点事儿

在51单片机上跑RTOS有没有意义?