移植嵌入式操作系统心得Word文档下载推荐.docx
《移植嵌入式操作系统心得Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《移植嵌入式操作系统心得Word文档下载推荐.docx(15页珍藏版)》请在冰豆网上搜索。
(3)任务级任务调度
指在非中断返回时进行任务调度,一般发生在当前任务因时间延迟或等待某事件而阻塞或被挂起,或有更高优先级的任务处于就绪状态。
任务的基本信息:
CPU的PC寄存器:
任务当前执行的位置;
CPU的通用寄存器:
任务当前执行涉及的临时数据;
CPU的状态寄存器:
存储当前CPU的状态。
任务级任务切换:
从一个任务直接切换至另一个任务,不涉及CPU状态的切换,OS_TASK_SW()既保存当前任务上下文,又恢复新任务上下文。
过程:
OS_Sched()->
OS_SchedNew()->
OS_TASK_SW()
(4)中断级任务调度
中断级任务切换:
在中断处理完成后,通过OSIntExit()判断是否有更高优先级就绪任务。
如果有,调用OSIntCtxSW()恢复新任务上下文。
注意:
在中断处理中,已经保存了被中断任务的上下文,所以这里仅仅恢复。
OSIntExt()–>
OSIntEnter()->
ISR–>
OSIntExit()->
OSIntCtxSW()
(5)调度器上锁与解锁
uC/OS-II提供调度器锁定功能,在锁定期间不能进行任务调度。
uC/OS-II使用全局变量OSLockNesting标识是否锁定了任务调度器。
OS_EXTINT8UOSLockNesting;
voidOSSchedLock(void);
voidOSSchedUnlock(void);
(6)中断管理函数
在中断处理中,不允许进行任务管理、事件管理及任务调度等操作。
uC/OS-II通过全局变量OSIntNesting标识当前是否处于中断状态。
在所有任务及事件管理的程序中,都有对OSIntNesting进行判断的语句。
voidOSIntEnter(void);
voidOSIntExit(void);
(7)中断相关问题
OS_ENTER_CRITICAL()
OS_EXIT_CRITICAL()
关中断使得uC/OS-II能够同时避免有其他任务或中断服务进入临界代码段。
调用uC/OS-II功能函数时,中断总应当是开着的。
uC/OS-II如何禁止调度?
在中断中允许调度吗?
为什么?
uC/OS-II如何屏蔽中断?
2.uC/OS-II系统启动
uC/OS-II首先调用OSInit()进行初始化,然后创建任务(此时还未启动系统,仅仅为其分配资源),然后调用OSStart()启动系统,将CPU控制权交给uC/OS-II,OS根据任务优先级选择由哪个任务开始执行,或创建新的任务。
(1)初始化函数OSInit()
OSInit()主要完成初始化操作,包括初始化全局变量(在OS_InitMisc()中)、任务就绪表、TCB、ECB、FCB、内存单元、消息队列,并创建空闲任务。
如果有必要,创建统计任务。
OS_InitMisc();
//初始化部分全局变量
OS_InitRdyList();
//初始化任务就绪表
OS_InitTCBList();
//初始化空闲TCB链表
OS_InitEventList();
//初始化ECB链表
OS_FlagInit();
//初始化事件组标志结构
OS_MemInit();
//初始化内存管理
OS_QInit();
//初始化消息队列
OS_InitTaskIdle();
//创建空闲任务
OS_InitTaskStat();
//创建统计任务
uC/OS-II初始化了5个空的数据结构缓冲区,每个缓冲区都是单向链表,允许uC/OS-II从缓冲区中迅速取得或释放一个缓冲区中的元素。
uC/OS-II调用OSInit()后的变量与数据结构如下图所示:
(2)启动函数OSStart()
OSStart()在一切准备就绪且需要首先创建的任务都被创建后,启动uC/OS-II。
它从就绪表中查找最高优先级就绪任务,并恢复其上下文开始执行。
OSStart()->
OSStartHighRdy()
问题:
任务第一次被调用时,哪来的上下文供其恢复呢?
创建任务时,调用了OSTaskStkInit()初始化任务堆栈,可此函数中没有涉及任务的上下文呀?
uC/OS-II调用OSStart()后的变量和数据结构如下图所示:
(3)统计任务OSTaskStat
OSTaskStat用于计算CPU利用率。
设置OS_CFG.H中的OS_TASK_STAT_EN为1,创建统计任务,在系统启动后一直处于就绪状
态。
刚开始时,空闲任务运行1S,为计算CPU利用率提供一个基准值,并保存在统计任务的堆栈中,这个值不会改变除非重新启动CPU。
此后空闲任每次被其
它任务抢去CPU时,它里面的计数器就会直接记录下CPU空闲的时间。
3.uC/OS-II系统时钟
任何实时系统的时钟硬件设备每隔一段时间(一个系统tick)产生一个硬件中断,OS接收到该中断后,更新时间计数器,更新所有对时钟依赖的程序代码,从而维持系统有序稳定的运行。
主要包含在C源文件OS_TIME.C中。
#defineOS_TICKS_PER_SEC100//系统时钟中断间隔
OS_EXTvolatileINT32UOSTime;
//系统运行的时间值
voidOSTimeTick(void);
//时钟中断服务程序
voidOSTimeDly(INT16Uticks);
//延迟指定时钟节拍
INT8UOSTimeDlyHMSM(…);
//延迟指定时间长度
INT8UOSTimeDlyResume(prio);
//恢复等待(时延/阻塞)任务
INT32UOSTimeGet(void);
//读取当前时间
voidOSTimeSet(INT32Uticks);
//设置当前时间
4.uC/OS-II事件管理
(1)事件控制块
INT8UOSEventType;
//事件类型
void*OSEventPtr;
//指向MBox或Queue
INT16UOSEventCnt;
//信号量计数器(注:
Mutex)
INT8UOSEventGrp;
//事件等待组标志
INT8UOSEventTbl[];
//时间任务等待表
INT8UOSEventName[];
//时间名称
(2)ECB管理机制
OS_EXTOS_EVENT*OSEventFreeList;
//空闲ECB链表指针
OS_EXTOS_EVENTOSEventTbl[];
//ECB结构体数组
(3)ECB管理函数
OS_InitEventList():
初始化ECB;
OS_EventWaitListInit():
在创建事件时调用,初始化ECB任务等待表;
OS_EventTaskRdy():
在事件发生时调用,修改此事件中最高优先级任务的TCB成员变量,在任务就绪表中添加此任务,将相应信息传递给该任务TCB,并将此任务从事件的任务等代表中删除;
OS_EventTaskWait():
在申请资源失败而暂停当前任务时被调用,将任务从任务就绪表中删除,并添加到事件的任务等代表中;
OS_EventTO():
在事件等待超时时调用,将此任务从事件的任务等代表中删除,并修改该任务的TCB成员变量;
【专题】uC/OS-II内核架构解析(4)---uC/OS-II任务管理
1.C可执行代码结构
(1)代码段.text:
存放CPU执行的机器指令,通常.text是可共享且只读的。
(2)数据段.data:
.rodata(常量数据)、.rwdata(已初始化全局变量、静态变量)。
(3)未初始化数据段.bss:
未初始化的全局变量、静态变量。
(4)栈.stack:
存放函数参数、局部变量及任务切换时的上下文。
(5)堆.heap:
用于动态内存分配。
2.任务结构
在uC/OS-II中,任务是事件运行和管理的基本单元。
一个uC/OS-II任务至少包含程序代码、栈和TCB,还可选择性使用相当于堆的动态内存空间。
程序运行时,uC/OS-II中的任务相当于可执行代码(可单独运行的单元)。
uC/OS-II任务的各部分如何管理?
?
3.任务栈
任务栈数据类型:
typedefunsignedshortOS_STK
任务栈增长方向:
#defineOS_STK_GROWTH0/1
任务栈基本功能:
4.任务控制块
(1)TCB描述
主要用来存储任务的当前属性。
(问:
任务第一次被调度时,该如何运行?
)
(2)TCB主要成员
任务栈空间位置:
OSTCBStkPtr、OSTCBStkBottom、OSTCBStkSize;
任务通信与同步:
OSTCBEventPtr、OSTCBMsg;
任务事件组标志:
OSTCBFlagNode、OSTCBFlagsRdy;
任务等待/阻塞:
OSTCBDly、OSTCBPendTO;
任务当前状态:
OSTCBStat;
任务优先级:
OSTCBPrio;
(3)TCB全局变量
OS_EXTOS_TCBOSTCBTbl[OS_MAX_TASKS+OS_N_SYS_TASKS];
OS_EXTOS_TCBOSTCBPrioTbl[OS_LOWEST_PRIO+1];
OS_EXTOS_TCB*OSTCBFreeList;
OS_EXTOS_TCB*OSTCBList;
OS_EXTOS_TCB*OSTCBHighRdy;
OS_EXTOS_TCB*OSTCBCur;
5.任务状态切换
6.任务管理函数
OS_TASK.C:
11个函数
OSTaskCreate();
OSTaskCreateExt();
OSTaskDel();
OSTaskDelReq();
OSTaskChangePrio();
OSTaskSuspend();
OSTaskResume();
OSTaskNameGet();
OSTaskNameSet();
OSTaskStkChk();
OS_TaskStkClr();
OSTaskQuery();
【专题】uC/OS-II内核架构解析(5)---uC/OS-II通信与同步
1.消息邮箱Mbox
Mbox用于多任务间单一消息的传递,uC/OS-II使用ECB管理Mbox的基本信息,OSEventPtr指向创建Mbox时指定的内存空间。
事件的创建由具体的事件管理程序实现。
主要包含在C源文件OS_MBOX.C中。
OS_EVENT*OSMboxCreate(void*msg);
void*OSMboxPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err);
void*OSMboxAccept(OS_EVENT*pevent);
INT8UOSMboxPost(OS_EVENT*pevent,void*msg);
INT8UOSMboxPostOpt(OS_EVENT*pevent,void*msg,INT8Uopt);
OS_EVENT*OSMboxDel(OS_EVENT*pevent,INT8Uopt,INT8U*err);
INT8UOSMboxQuery(OS_EVENT*pevent,OS_MBOX_DATA*);
2.消息队列msgQ
(1)msgQ基本内容
msgQ是uC/OS-II任务间通信的机制,可实现多条消息传递,即可以同时存储多条消息。
uC/OS-II使用循环队列管理机制。
主要包含在C源文件OS_Q.C中。
msgQ管理:
使用指针数组存储所有消息的位置;
使用QCB标识指针数组中消息的基本信息;
使用ECB管理整个msgQ。
QCB在编译时分配空间,即当前系统中可用的msgQ个数是预先设置的,系统运行时不能修改。
(2)msgQ全局变量
OS_EXTOS_Q*OSQTbl[OS_MAX_QS];
//QCB结构体数组
OS_EXTOS_Q*OSQFreeList;
//空闲QCB头指针
typedefstructos_q{//消息队列控制块
structos_q*OSQPtr;
//用于构建空闲QCB链表
void**OSQStart;
//指向msgQ指针数组的起始位置
void**OSQEnd;
//指向msgQ指针数组的结束位置
void**OSQIn;
//指向msgQ指针数组下一个可以插入消息的位置
void**OSQOut;
//指向msgQ指针数组下一个可以读出消息的位置
INT16UOSQSize;
//msgQ指针数组的大小
INT16UOSQEntries;
//msgQ指针数组当前可以读取的消息个数
}OS_Q;
(3)msgQ管理函数
OS_EVENT*OSQCreate(void**start,INT16Usize);
INT8UOSQPost(OS_EVENT*pevent,void*msg);
//发送消息到队尾
INT8UOSQPostFront(OS_EVENT*pevent,void*msg);
//msg至队首
INT8UOSQPostOpt(OS_EVENT*pevent,void*msg,INT8Uopt);
void*OSQPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err);
void*OSQAccept(OS_EVENT*pevent,INT8U*err);
OS_EVENT*OSQDel(OS_EVENT*pevent,INT8Uopt,INT8U*err);
INT8UOSQQuery(OS_EVENT*pevent,OS_Q_DATA*);
INT8UOSQFlush(OS_EVENT*pevent);
(4)msgQ几个问题
uC/OS-II中,什么是事件?
事件是uC/OS-II管理任务间同步与通信的机制。
事件是处理事件的对象感兴趣的,能够感知或捕获到一种事件状态的改变。
3.信号量Sem
Sem主要用来实现任务间同步及标识某类资源的可用个数,即某个特定资源可供多少任务同时使用。
主要包含在C源文件OS_SEM.C中。
OS_EVENT*OSSemCreate(INT16Ucnt);
voidOSSemPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err);
INT16UOSSemAccept(OS_EVENT*pevent);
INT8UOSSemPost(OS_EVENT*pevent);
OS_EVENT*OSSemDel(OS_EVENT*pevent,INT8Uopt,INT8U*err);
INT8UOSSemQuery(OS_EVENT*pevent,OS_SEM_DATA*);
voidOSSemSet(OS_EVENT*pevent,INT16Ucnt,INT8U*err);
4.互斥锁Mutex
(1)Mutex基本原理
Mutex用来实现对资源的排他性访问,可能引起优先级反转。
任何任务在占有某个互斥锁事件时,都不能阻塞等待其它任何事件,否则会造成死锁。
主要包含在C源文件OS_MUTEX.C中。
优先级反转是指,低优先级任务占有高优先级任务运行所需的资源,而使高优先级不得不等低优先级任务把资源释放才能执行。
uC/OS-II使用ECB管理Mutex,其成员变量OSEventCnt:
高8位存储Mutex被使用时提供给任务的prio;
低8位在没有任务占有Mutex时为0xFF,否则为占有任务的prio。
优先级反转及优先级反转避免分别如下图所示:
(2)提升/恢复优先级
a)提升Mutex拥有者任务的优先级的相关操作:
如果该任务原来处于就绪状态,则从就绪表中将其删除;
如果该任务正在等待某个事件,则从该事件的任务等待表中将其删除;
修改拥有Mutex的TCB,将其OSTCBPrio修改为欲提升的优先级;
如果该任务处于就绪状态,则将提升的优先级加载到任务就绪表中;
如果该任务未就绪且正在等待某个事件,则将提升的优先级添加到该事件的任务等待表中,并修改TCB中OSTCBEventPtr;
修改TCB中与优先级相关的成员变量。
b)恢复Mutex拥有任务的优先级的相关操作:
从任务就绪表中删除提升过的优先级值,修改当前TCB中与优先级相关的所有成员变量;
再次保留提升的优先级值控制块入口,避免将其分配给其它任务。
(3)Mutex管理函数
#defineOS_MUTEX_KEEP_LOWER_80x00FF
#defineOS_MUTEX_KEEP_UPPER_80xFF00
#defineOS_MUTEX_AVAILABLE0x00FF
OS_EVENT*OSMutexCreate(INT8Uprio,INT8U*err);
voidOSMutexPend(OS_EVENT*pevent,INT16Utimeout,INT8U*err);
INT8UOSMutexAccept(OS_EVENT*pevent,INT8U*err);
INT8UOSMutexPost(OS_EVENT*pevent);
OS_EVENT*OSMutexDel(OS_EVENT*,INT8Uopt,INT8U*err);
INT8UOSMutexQuery(OS_EVENT*,OS_MUTEX_DATA*);
5.事件组标志Flag
(1)Flag基本原理
uC/OS-II提供事件组标志实现多事件管理。
Flag只是使用0/1来表示某个事件是否发生过,而不能直接被用来传递数据和消息。
可以选择性地设置一个Flag最多可以管理的任务同步状态。
主要包含在C源文件OS_FLAG.C中。
(2)Flag数据结构
#defineOS_FLAGS_NBITS8/16/32//定义OS_FLAGS的位数
FCB结构体:
typedefstructos_flag_grp{
INT8UOSFlagType;
//事件类型
void*OSFlagWaitList;
//指向等待的任务链表
OS_FLAGSOSFlagFlags;
//信号列表
INT8UOSFlagName[OS_FLAG_NAME_SIZE];
}OS_FLAG_GRP;
事件标志等待链表结点
typedefstructos_flag_node{
void*OSFlagNodeNext;
void*OSFlagNodePrev;
void*OSFlagNodeTCB;
void*OSFlagNodeFlagGrp;
//指向此任务所等待的事件组标志
OS_FLAGSOSFlagNodeFlags;
//等待的事件
INT8UOSFlagNodeWaitType;
//等待方式
}OS_FLAG_NODE;
OS_EXTOS_FLAG_GRPOSFlagTbl[OS_MAX_FLAGS];
OS_EXTOS_FLAG_GRP*OSFlagFreeList;
OS_FLAG_GRP*OSFlagCreate(OS_FLAGSflags,INT8U*err);
OS_FLAGSOSFlagPend(OS_FLAG_GRP*pgrp,OS_FLAGSflags,
(3)Flag管理函数
INT8Uwait_type,INT16Utimeout,INT8U*err);