嵌入式系统的核心:RTOS

来源:互联网 发布:自考好还是网络教育好 编辑:程序博客网 时间:2024/06/03 11:49

大概在2000年左右,嵌入式行业迎来了黄金发展期,盖因为电子行业的兴起。电子嵌入式设备与我们的生活紧密的联系在一起。小到我们日常用品 ,比如:手机,冰箱,洗衣机,导航。大到国家层面:火箭,飞船,卫星等。诚然,任何一个行业都有成熟期,到衰落期。嵌入式行业不能说是衰落,只是没有之前那么火热。但是依然和我们的生活息息相关。在这里和大家一起探讨下嵌入式的核心:操作系统,结合原创代码,以便对其有深入的理解。

其实,我们一般说嵌入式操作系统,首先想到的是RTOS;那就需要保证两点:实时性或者准实时,稳定性。开车的朋友都知道,汽车里的音响设备是一个典型的嵌入式系统

我们打个比方如果把车载音响里的收音机,CD,USB,蓝牙等称作人体功能骨骼的话,那RTOS就相当于我们的神经大脑。来统一支配,协调工作。

简单来说,RTOS可以看做是一个无限循环的系统,在这个系统中,一直在检测是否有事件被触发,一旦有事件触发,就解析该事件所附带的信息,把事件发送给对应的APP去处理。如果有多个APP,有大量的事件。那么事件以及APP就需要分优先级,因为高优先级的事件可以打断正在执行的低优先级事件;那么就涉及到队列等。

一:消息队列的设计



        如上图,32个消息,P代表指向前一个消息,N代表指向下一个消息,Event代表消息的结构体,蓝色和黑色箭头分别代表出队和入队,一个简单的消息框架就成型了

我们看下定义消息的结构体代码:

typedef  struct{

int  EvtCode;  //事件内容

int EvtPri; //优先级(值越小优先级越高)

int  Opt1;

int  Opt2;

}


typedef  struct{intPrev;//指向前一单元的indexintNext;//指向后一单元的indexSysEvent_stEvent;//保存Event信息}SysEventItem_ts;typedef  struct{SysEventItem_ts*EventItem;//指向EventQueue的指针intIn;//进队位置的indexintOut;//出队位置的indexintQueFullFlg;//队列是否为Full}SysEventQueue_ts;typedef  struct{

考虑到事件带有优先级,所以定义了成员:EvtPri,另外为了方便扩展,又定义了4个opt。


二:事件入队和出队

 为了方便事件管理,在入队时,我们是把优先级高的尽量向队列的头部插入,出队时就按照正常的顺序,这样队列的优先级就可以很好的保证。








       对应源码就比较简单了,分为以下几个主要模块:
      1,队列初始化
     void event_init(void)
{

for(aubCount = 0; aubCount < aubSize; aubCount++){
/* Event Item Init */
tsEventItem[aubCount].Prev = (aubCount + aubMask) & aubMask;
tsEventItem[aubCount].Next = (aubCount + 1)  & aubMask;
/* Event Init */
tsEventItem[aubCount].Event.EvtCode= CLEAR;
tsEventItem[aubCount].Event.EvtPri= INVALID;
tsEventItem[aubCount].Event.Opt1= CLEAR;
tsEventItem[aubCount].Event.Opt2= CLEAR;
tsEventItem[aubCount].Event.Opt3= CLEAR;
tsEventItem[aubCount].Event.Opt4= CLEAR;
}
}

2.发送事件
int event_send(AppEvent_st *pEvt)
{

if(NULL != pEvt)
{
uhwEvtPri = (Type_uHWord)(pEvt->EvtCode >> 0x10);


if(uhwEvtPri != 0x00)
{
if(uhwEvtPri > 0x08)
{
uhwEvtPri = NORMAL_EVT_PRI;
}
aubEvent.EvtCode= pEvt->EvtCode;
aubEvent.Opt1 = pEvt->Opt1;
aubEvent.Opt2 = pEvt->Opt2;
aubEvent.Opt3 = pEvt->Opt3;
aubEvent.Opt4 = pEvt->Opt4;
aubEvent.EvtPri= uhwEvtPri;


ubRet = evt_mgr_set(&nstAppTaskEventQue,&aubEvent);
}
}

return ubRet;
}
3.事件入队,这个比较复杂,要考虑优先级问题
void event_set(SysEventQueue_ts *pEventQueue,SysEvent_st *pEvt)
{
if(NULL != pEventQueue && NULL != pEventQueue->EventItem)
{
q_in = pEventQueue->In;
q_insert = pEventQueue->Out;
pEvtItem = pEventQueue->EventItem;


if(pEventQueue->QueFullFlg == FALSE)
{
if(pEvtItem[q_in].Next == q_insert)
{
pEventQueue->QueFullFlg = TRUE;
}
if(pEvtItem[pEventQueue->Out].Event.EvtPri > pEvt->EvtPri)//move out position
{
pEventQueue->Out = pEvtItem[pEventQueue->Out].Prev;
pCurt = &(pEvtItem[pEventQueue->Out].Event);
BACKUP_EVENT_INFO(pCurt,pEvt);
}
else
{
while(q_in != q_insert)
{
q_insert = pEvtItem[q_insert].Next;
if (q_in == q_insert)
{
break;
}
else if (pEvtItem[q_insert].Event.EvtPri > pEvt->EvtPri || bChanged == TRUE)//insert to queue
{
pTemp = &TempEvt;
pCurt = &(pEvtItem[q_insert].Event);

BACKUP_EVENT_INFO(pTemp,pCurt);
BACKUP_EVENT_INFO(pCurt,pEvt);
BACKUP_EVENT_INFO(pEvt,pTemp);
bChanged = TRUE;
}
}
if(q_in == q_insert)//add to queue rear
{
pCurt = &(pEvtItem[q_insert].Event);

BACKUP_EVENT_INFO(pCurt,pEvt);
q_in = pEvtItem[q_insert].Next;//set next event add position
pEventQueue->In = q_in;
}
}
}
else
{
aubRet = QUE_OVER;
}
}

return aubRet;
}

三:任务状态机的设计



如上图,我们可以把任务状态简单的分为:sleep;active;wait;finished;error五种状态。最后一个是异常态。
对于任意一个任务,我们可以这样设计一个矩阵:任务当前态,触发事件,后续处理,改变后的状态。我们可以据此设计一个任务变更的结构体:
typedef void (*systemCtrlFunc) (void);
typedef struct
{
int CurtState;  //当前状态
int AcceptEvent; //触发事件
int NextState;//改变后的状态
systemCtrlFunc  Proc;//处理函数

} Proc_st;

四:系统主函数
系统主函数就比较简单了,一个无限循环,不断触发端口
while(1)
{
INIT_EVT(evt);
_wait_evt(&evt);


if(IS_VALID_EVT(evt))
{
//SYS_RUNTIME_OUTPUT("[Main] Receive Event: 0x%u \n",evt.EvtCode,0,0);
_evt_proc(&evt);
}


cycle_checkup();

FEED_WATCH_DOG;
}
0 0