当前位置:首页 >> 信息与通信 >>

嵌入式实时操作系统_uCOSII_图文

uC/OS-II
北京邮电大学计算机学院 邝 坚 2011年10月

教材及参考文献
《嵌入式实时操作系统 uC/OS-II(第2 版)》,Jean J.Labrosse, 邵贝贝, 北航出版 社, 2003年1月

uC/OS-II的主要特点
实时性可确定:绝大多数系统服务的执行时间具有可确定 性,不依赖于用户应用程序Task数目的多少。 多任务、独立栈:最多64个Task,基于优先级抢占调度方 式。每个Task有自身独立的堆栈。 可裁减性:系统最小可裁减到几K到十几K,这种裁减还可 以做到基于函数级。 可移植性:与CPU体系结构相关部分用汇编编写,其他功 能组件CPU无关。 可靠、稳定性:由整个系统设计来保证,市场验证。美国 联邦航空管理局(FAA)认证。 开源代码:内核约5500行C代码。 可固化:面向嵌入式应用。

系统功能
实时内核 任务管理 时间管理 信号量、互斥信号量管理 事件标志组管理 消息邮箱管理 消息队列管理 内存管理 …

Targets x86 68k PPC CPU32 i960 SPARC ARM MIPS XScale …

Typical development configuration
Ethernet

RS-232

Development Host

Target

Typical scenario:
1. Boot target. 4. Download object module. 2. Attach target server. 5. Test & Debug. 3. Edit & compile. 6. Return to 3 or 1 as necessary

Multi-Tasking

Task是代码运行的一个映像,从系统的角 度看,Task是竞争系统资源的最小运行单 元。Task可以使用或者等待CPU、I/O设备 及内存空间等系统资源,并独立于其它的 Task,与它们一起并发运行。

Task Operation
Priority-base preemptive scheduling(基 于优先级的抢占式调度)

Task调度器上锁和开锁
给调度器上锁函数OSSchedlock() 用于临 时禁止任务调度,直到任务完成后调用给 调度器开锁函数OSSchedUnlock()为止。
须成对执行 时间尽量短 不会关闭中断 什么时候用:希望期间不被打扰 但…

空闲任务(Idle Task)
μC/OS-Ⅱ总是建立一个空闲任务,这个 任务在没有其它任务进入就绪态时投入运 行。 这个空闲任务[OSTaskIdle()]永远设为最低 优先级,即OS_LOWEST_PRI0 OSTaskIdle()什么也不做,只是在不停地 给一个32位的名叫OSIdleCtr的计数器加 1,统计任务使用这个计数器以确定现行应 用软件实际消耗的CPU时间。

统计任务
μC/OS-Ⅱ有一个提供运行时间统计的任 务。这个任务叫做OSTaskStat(),如果用户 将系统定义常数OS_TASK_STAT_EN设为 1,这个任务就会建立。 一旦得到了允许,OSTaskStat()每秒钟运 行一次,计算当前的CPU利用率。换句话 说,OSTaskStat()告诉用户应用程序使用 了多少CPU时间,用百分比表示,这个值 放在一个有符号8位整数OSCPUsage中, 精读度是1个百分点。

States of Task

状态 运行 就绪 等待 中断 睡眠

解 任务占用CPU,运行状态



任务已经得到了除CPU之外的所有资源,仅仅在等待 CPU资源 任务正在等待某些当前不可用的资源 任务运行中被中断服务程序打断,中断服务程序(ISR)运 行 任务尚未被创建或被删除,处于不可被执行状态。

States of Task

OS_TCB – 任务控制块
TCB是一个数据结构,驻留在RAM中,任务建立时TCB被初始化。当 任务的CPU使用权被剥夺时,TCB保存该任务的状态。当任务重新得 到CPU使用权时,TCB能确保任务从当时被中断的那一点丝毫不差地 继续执行。TCB全部。
OSTCBStkPtr:任务栈顶指针 OSTCBExtPtr:TCB扩展。用户可以扩展TCB而不必修改μC/OS-Ⅱ的源代码 OSTCBStkBottom:任务栈底的指针 OSTCBStkSize:栈中可容纳的指针元数目而不是用字节表示的栈容量总数 OSTCBNext、OSTCBPrev:用于任务控制块OS_TCBs的双重链接指针 OSTCBEventPtr:指向事件控制块的指针 OSTCBMsg:指向传给任务的消息的指针 OSTCBDly:当需要把任务延时若干时钟节拍时要用到这个变量 OSTCBStat:任务的状态字(uCOS_II.h) OSTCBPrio:任务优先级 OSTCBX、OSTCBY、 OSTCBBitX、OSTCBBitY:用于加速任务进入就绪态的过 程或进入等待事件发生状态的过程(避免在运行中去计算这些值) OSTCBDelReq:是一个布尔量,用于表示该任务是否需要删除

Task 相关
Task Task Task Task Task Task 创建(及扩展) 堆栈 删除(及请求删除) 优先级改变 挂起及恢复 信息获取

Task形态
任务可以是一个无限的循环,也可以是在 一次执行完毕后被删除掉(其代码并不是 被真正删除,而只是OS不再理会该任务代 码)。 任务看起来与任何C函数一样,具有一个 返回类型和一个参数,只是它从不返回。 任务的函数类型必须被定义成void型

Task形态(demo1)
void YourTask (void *pdata) { for (;;) { /* 用户代码 */ OSMboxPend(); OSTimeDly(); /* 用户代码 */ } }

Task形态(demo2)
void YourTask (void *pdata) { /* 用户代码 */ OSTaskDel(OS_PRIO_SELF); }

Task创建
INT8U OSTaskCreate ( void (*task)(void *pd), void *p_arg, OS_STK *ptos, INT8U prio, )

/* 任务函数的入口的地址 */ /* 任务的入口参数指针 */ /* 任务堆栈栈顶指针 */ /* 任务的优先级 */

每个优先级只允许1个Task存在 优先级取值范围0-63(4-59)/0 -255 值越小,优先级越高 当前Task优先级:OS_PRIO_SELF

Task创建(扩展)
INT8U OSTaskCreateExt ( void (*task)(void *pd), /* 任务函数的入口的地址 */ void *p_arg, /* 任务的入口参数指针 */ OS_STK *ptos, /* 任务堆栈栈顶指针 */ INT8U prio, /* 任务的优先级 */ INT16U id, /* 任务的ID(保留) */ OS_STK *pbos, /* 任务栈底指针 */ INT32U stk_size, /* 任务堆栈大小(指针元数目) */ void *pext, /* 附加的数据域指针 */ INT16U opt /* 选项(堆栈检查、堆栈清零等) */ )

Task堆栈
每个任务都有自己的堆栈空间。堆栈必须声明为 OS_STK类型,并且由连续的内存空间组成。 静态:
static OS_STK MyTaskStack[stack_size]; 或 OS_STK MyTaskStack[stack_size];

动态:
OS_STK *pstk; pstk = (OS_STK *)malloc(stack_size); if (pstk != (OS_STK *)0) { /* 确认malloc()能得到足 够地内存空间 */ Create the task; }

Task删除
被删除的任务将返回并处于休眠状态 INT8U OSTaskDel ( INT8U prio /* Task的优先级 */ ) 不允许中断服务程序(ISR)删除Task 不能删除系统Idle Task(OS_IDLE_PRIO) Task可以删除自己

请求删除Task
有时候,如果任务A拥有内存缓冲区或信 号量之类的资源,而任务B想删除A,这些 资源就可能由于没被释放而丢失。在这种 情况下,用户可以想办法让拥有这些资源 的任务在使用完资源后,先释放资源,再 删除自己。用户可以通过OSTaskDelReq() 函数来完成该功能。

改变Task优先级
在程序运行期间,用户可以动态改变任务 的优先级。 INT8U OSTaskChangePrio ( INT8U oldprio, /* 原优先级 */ INT8U newprio /* 新优先级 */ ) 不能改变idle task的优先级 可以改变自己或其他Task优先级

Task挂起和恢复
挂起任务可通过调用OSTaskSuspend()函 数来完成。被挂起的任务只能通过调用 OSTaskResume()函数来恢复
INT8U OSTaskSuspend (INT8U prio) INT8U OSTaskResume (INT8U prio)

Task信息获取
通过调用OSTaskQuery()来获得自身或其它应用任务的信 息。实际上,OSTaskQuery()获得的是对应任务OS_TCB 中内容的拷贝
OS_TCB MyTaskData; void MyTask (void *pdata){ pdata = pdata; for (;;) { /* 用户代码 */ err = OSTaskQuery(10, &MyTaskData); /* Examine error code .. */ /* 用户代码 */ } }

时间管理
μC/OS-Ⅱ(其它内核也一样)要求系统提供 定时中断来实现延时与超时控制等功能。 这个定时中断叫做时钟节拍(Tick),它 应该每秒发生10至100次。时钟节拍的实 际频率是由用户的应用程序决定的。时钟 节拍的频率越高,系统的负荷就越重。 实质:
定时器中断ISR -> OSTimeTick()

时间管理相关
Task延时: OSTimeDly() 按时、分、秒延时:OSTimeDlyHMSM() 恢复被延时Task:OSTimeDlyResume() 系统时间管理: OSTimeGet() OSTimeSet()

Task延时
申请该服务的任务可以延时一段时间,这 段时间的长短是用时钟节拍(Tick)的数 目来确定的。 void OSTimeDly (INT16U ticks)
Tick = n (n>0), delay n个Tick, 之后Task状 态?有没有误差? Tick = 0, 函数立即返回

按时、分、秒延时
INT8U OSTimeDlyHMSM ( INT8U hours, INT8U minutes, INT8U seconds, INT16U milli ) 有最长延时限制:65535个Tick

恢复被延时的Task
INT8U OSTimeDlyResume (INT8U prio) 谁能发起这个唤醒动作? 不建议使用?
被唤醒的Task同样认为是超时被唤醒

系统时间管理
INT32U OSTimeGet (void)
返回系统当前的Tick计数值(32位: 04,294,967,295)

void OSTimeSet (INT32U ticks)
设置系统的Tick计数值

Intertask Communication
Task间通信的主要目的:
保护共享的数据、信息. 通知Task数据已经准备好,可以读写 Task之间同步,防止相互干扰

Communication Methods
信号量( Semaphores )- 用于最基本的互斥、同步操 作 互斥信号量(Mutual Exclusion Semaphores ) – 专 门用于互斥 消息邮箱(Message Box) - 单消息 消息队列( Message Queues )- 用于消息通信 事件标志组(Event Flag)- 一组标志 Others –
Shared Memory(共享内存)- 用于数据的简单共享 Pipes(管道)- 用于支持标准I/O操作的消息通信 Signals(信号)- 用于处理异常 Network(Sockets), …

信号量相关
信号量创建:OSSemCreate() 信号量删除:OSSemDel() 信号量等待:OSSemPend() 信号量发出:OSSemPost() 信号量请求(无等待): OSSemAccept() 信号量状态查询: OSSemQuery()

信号量创建
μC/OS-II中的信号量由两部分组成:一个是信 号量的计数值,它是一个16位的无符号整数(0 到65,535之间);另一个是由等待该信号量的任 务组成的等待任务表。 OS_EVENT *OSSemCreate (INT16U cnt)
返回信号量指针(句柄、ID) 对信号量的初始计数值赋值。该初始值为0到65,535 之间的一个数。如果信号量是用来表示一个或者多个 事件的发生,那么该信号量的初始值应设为0。如果 信号量是用于对共享资源的访问,那么该信号量的初 始值应设为1(例如,把它当作二值信号量使用)。 最后,如果该信号量是用来表示允许任务访问n个相 同的资源,那么该初始值显然应该是n,并把该信号 量作为一个可计数的信号量使用。

信号量删除
OS_EVENT *OSSemDel( OS_EVENT *prevent, /* 信号量指针(句柄,ID) */ INT8U opt, /* 选项 */ INT8U *err /* 错误码缓冲指针 */ ) 删除成功返回空指针(NULL); ISR不能调用 opt :OS_DEL_NO_PEND ->若有Task在等, 返回err=OS_ERR_TASK_WAITING; OS_DEL_ALWAYS -> 强制删除。 等待信号量的Task进入Ready。 err:操作成功返回OS_NO_ERR

等待信号量
void OSSemPend (
OS_EVENT *pevent, /* 信号量指针(句柄,ID) */ INT16U timeout, /* 等待时间(Tick数) */ INT8U *err /* 错误码缓冲指针 */

) ISR不能调用 如果得到信号量,内部计数-1返回OS_NO_ERR,否则进 Pend timeout: >0 -> 最长等待时间 =0 -> 永远等待 如果timeout后仍未得到信号量,返回OS_TIMEOUT 可能产生任务切换

发出信号量
INT8U OSSemPost (OS_EVENT *pevent) 操作成功,内部计数+1,返回 OS_NO_ERR 可能产生任务切换 内部计数溢出,返回OS_SEM_OVF

信号量请求(无等待)
当一个任务请求一个信号量时,如果该信 号量暂时无效,也可以让该任务简单地返 回,而不是进入睡眠等待状态。 INT16U OSSemAccept (OS_EVENT *pevent) ISR可以使用,但不推荐使用 返回内部计数值(减1之前的),调用者用 于判断是否成功(成功时应>0,否则=0)

信号量状态查询
INT8U OSSemQuery (
OS_EVENT *pevent,/* 信号量指针(句柄,ID) */ OS_SEM_DATA *pdata /*信号量数据结构指针*/

) 成功返回OS_NO_ERR,同时拷贝相应内容进 *pdata OS_SEM_DATA 包括当前计数值、等待任务列表 等

Task同步
为某个资源创建信号量,并规定:
>0 (资源有效). 0 (资源无法获取).

Task调用OSSemPend进入Pending直到信 号量被发出 其它Task或中断服务程序(ISR)在资源有效 时调用OSSemPost 等待信号量的Task被激活(Run/Ready) 不需要时用OSSemDel删除并释放

互斥-临界资源的操作

互斥信号量
互斥信号量(Mutual exclusion semaphores) 是专门设计用于实现对共享资源的独占式 处理 是二值信号量 同时设计可解决优先级反转问题 为TASK设计,ISR不能使用

优先级反转(1/2)
高 任务优先级 task2

低 图 例 - semTake - semGive - 占有信号量

task1 时间 - 优先级抢占 - 阻塞

优先级反转(2/2)

优先级继承 Priority Inheritance

uC/OS-II实际采用的方法是由互斥信号量先预占一个优先级

互斥信号量相关
互斥信号量创建:OSMutexCreate() 互斥信号量删除:OSMutexDel() 互斥信号量等待:OSMutexPend() 互斥信号量发出:OSMutexPost() 互斥信号量请求(无等待): OSMutexAccept() 互斥信号量状态查询: OSMutexQuery()

互斥信号量创建
OS_EVENT *OSMutexCreate( INT8U prio, /* 预占的优先级 */ INT8U *err /* 错误码缓冲指针 */ ) prio未被占用(否则*err = OS_PRIO_EXIST) 初值为1(资源有效)

互斥信号量删除
OS_EVENT *OSMutexDel( OS_EVENT *pevent, /* 信号量指针 */ INT8U opt, /* 删除方式选项 */ INT8U *err /* 错误码缓冲指针 */ )

Opt:OS_DEL_NO_PEND -> 没有Task因该信号量被挂 起时删除,否则返回OS_ERR_TASK_WAITING OS_DEL_ALWAYS -> 强制删除,所有正在等待该 信号量的Task进入就绪态 成功返回空指针,*err = OS_NO_ERR

互斥信号量等待
Void OSMutexPend( OS_EVENT *pevent, /* 信号量指针 */ INT16U timeout, /* 等待时间(Tick数) */ INT8U *err /*错误码缓冲指针 */

)

内部处理优先级反转(优先级可能变高) 如果得到信号量,内部状态=0, *err = OS_NO_ERR, 否则进Pend timeout: >0 -> 最长等待时间 =0 -> 永远等待 如果timeout后仍未得到信号量,返回OS_TIMEOUT 可能产生任务切换

互斥信号量释放
INT8U OSMutexPost(OS_EVENT *pevent) 操作成功,内部状态=1,返回 OS_NO_ERR 可能产生任务切换

互斥信号量无等待获取
INT8U OSMutexAccept( OS_EVENT *pevent, /* 信号量指针 */ INT8U *err /*错误码缓冲指针 */ ) 若得到信号量,返回1(优先级可能被改 变),否则返回0。

获取互斥信号量状态
INT8U OSMutexQuery( OS_EVENT *pevent, /* 信号量指针 */ OS_MUTEX_DATA *pdata, /*互斥信号 量数据结构指针*/ ) 成功返回OS_NO_ERR,同时拷贝相应内容 进*pdata

Task 与信号量练习
Semaphore tSender tReceiver

Acive by Delay

Wait Semaphore

所有Task都处在 “等待激活”→“处理”的死循环中 优先级最低的可以例外

消息邮箱
Task或ISR向其它Task传递信息内容的一 种方式 是用一个指针型变量,通常该指针指向一 个特定“信息”的数据结构
Task Task ISR Data

消息邮箱相关
消息邮箱创建:OSMboxCreate() 消息邮箱删除:OSMboxDel() 消息邮箱等待:OSMboxPend() 消息邮箱发送:OSMboxPost() 消息邮箱发送(扩展):OSMboxPostOpt() 从消息邮箱取消息(无等待): OSMboxAccept() 消息邮箱状态查询: OSMboxQuery()

消息邮箱使用
OSMboxCreate() OSMboxDel() OSMboxPost() OSMboxPostOpt() Task OSMboxAccept() OSMboxPend() OSMboxQuery()

Task

ISR

OSMboxPost() OSMboxPostOpt() msg

OSMboxAccept()

ISR

消息邮箱创建
OS_EVENT *OSMboxCreate(void *msg) 创建成功返回非空指针(句柄) *msg:信息指针的初值
空指针(NULL) -> 邮箱内无信息 非空指针 -> 指向某一数据结构的指针

消息邮箱删除
OS_EVENT *OSMboxDel( OS_EVENT * pevent, /* 邮箱指针 */ INT8U *opt, /*删除方式选项 */ INT8U *err /* 错误码缓冲指针 */ ) ISR不能使用,否则返回OS_ERR_DEL_ISR Opt:OS_DEL_NO_PEND -> 没有Task因等待该消息邮 箱被挂起时删除,否则返回OS_ERR_TASK_WAITING OS_DEL_ALWAYS -> 强制删除,所有正在等待该 消息邮箱的Task进入就绪态 成功返回空指针,*err = OS_NO_ERR

等待邮箱中的消息
void *OSMboxPend( OS_EVENT *pevent, /* 邮箱指针 */ INT16U timeout, /* 等待时间(Tick数) */ INT8U *err /* 错误码缓冲指针 */ ISR不能使用,否则返回OS_ERR_PEND_ISR 如果得到消息:*err = OS_NO_ERR,返回消息指针,否则进Pend timeout: >0 -> 最长等待时间 =0 -> 永远等待 如果timeout后仍未得到消息, *err = OS_TIMEOUT,返回空指针 可能产生任务切换

)

向邮箱发送一则消息
INT8U OSMboxPost( OS_EVENT *pevent, void *msg /* 邮箱指针 */ /* 消息指针 */

)

操作成功,返回OS_NO_ERR pevent要求为非空指针,否则返回 OS_ERR_PEVENT_NULL msg要求为非空指针,否则返回 OS_ERR_POST_NULL_PTR 若邮箱已有消息未被取走,返回OS_MBOX_FULL,新消 息发送失败 可能产生任务切换

向邮箱发送一则消息(扩展)
INT8U OSMboxPostOpt( OS_EVENT *pevent, /* 邮箱指针 */ void *msg, /* 消息指针 */ INT8U opt /* 发送选项 */

)

操作成功,返回OS_NO_ERR pevent要求为非空指针,否则返回OS_ERR_PEVENT_NULL msg要求为非空指针,否则返回OS_ERR_POST_NULL_PTR 若邮箱已有消息未被取走,返回OS_MBOX_FULL,新消息发送失败 可以向所有在该邮箱等待消息的Task广播消息, opt=OS_POST_OPT_BOARDCAST 可能产生任务切换

无等待地从邮箱得到消息
Void *OSMboxAccept( OS_EVENT *pevent /* 邮箱指针 */ ) 若得到消息,返回消息指针,否则返回空 指针 ISR可以使用

查询邮箱状态
INT8U OSMboxQuery( OS_EVENT *pevent, /* 邮箱指针 */ OS_MBOX_DATA *pdata, /*邮箱数据结 构指针*/ ) 成功返回OS_NO_ERR,同时拷贝相应内容 到*pdata

用邮箱作为二值信号量
对于互斥方式,初始化邮箱为非空指针(如void *1),使“信号量”有效 使用者先利用OSMboxPend()请求该“信号量”,操作完临界资源后再利用 OSMboxPost() 释放该“信号量” OS_EVENT *MboxSem; OS_ENENT *Mboxsem_init(void){ MboxSem = OSMboxCreate((void*)1); return(MboxSem); } void Mybufput(char ch){ INT8U err; OSMboxPend(MboxSem, 0, &err); . . /* 对临界资源的访问 */ . OSMboxPost(MboxSem, (void*)1);

}

用邮箱实现延时
OS_EVENT *MboxTimeDly; void Task1(void *pdata){ INT8U err; while(1){ OSMBoxPend(MboxTimeDly, TIMEOUT, &err); /* 延时 */ . . /* 延时后执行的代码 */ . } } void Task2(void *pdata){ INT8U err; for(;;){ . OSMboxPost(MboxTimeDly, (void *)1); /* 取消Task1的延时 */ .

}

}

利用消息邮箱实现多Task启动同步
tWaitTask1() { : OSMboxPend(); : }

同 步 点

OSMboxPostOpt()

tWaitTask2() { : OSMboxPend(); : }

同 步 点

消息队列相关
消息队列创建:OSQCreate() 消息队列删除:OSQDel() 消息队列等待:OSQPend() 消息队列发送:OSQPost() 消息队列发送:OSQPostFront() 消息队列发送(扩展):OSQPostOpt() 从消息队列取消息(无等待):OSQAccept() 消息队列清空:OSQFlush() 消息队列状态查询: OSQQuery()

消息队列使用
OSQCreate() OSQDel() OSQFlush() OSQPost() OSQPostFront() OSQPostOpt() OSQAccept() OSQPend() OSQQuery()

Task

Task

ISR

OSQFlush() OSQPost() OSQPostFront() OSQPostOpt()

OSQAccept() msgs

ISR

消息队列创建
OS_EVENT *OSQCreate( void **start, /* 消息数组指针 */ INT16U size /* 消息数组大小 */ ) 事先准备一个消息指针数组(void类型), 如: void *MyArrayofMsg[SIZE]; 创建成功返回非空指针(句柄)

消息队列删除
OS_EVENT *OSQDel( OS_EVENT * pevent, INT8U opt, INT8U *err ) ISR不能使用,否则返回OS_ERR_DEL_ISR Opt:OS_DEL_NO_PEND -> 没有Task因等待该消息队 列被挂起时删除,否则返回OS_ERR_TASK_WAITING OS_DEL_ALWAYS -> 强制删除,所有正在等待该 消息队列的Task进入就绪态 成功返回空指针,*err = OS_NO_ERR /* 消息队列指针 */ /* 删除方式选项 */ /* 错误码缓冲指针 */

在消息队列等待消息
void *OSQPend( OS_EVENT *pevent, INT16U timeout, INT8U *err /* 消息队列指针 */ /* 等待时间(Tick数) */ /* 错误码缓冲指针 */

)

ISR不能使用,否则返回OS_ERR_PEND_ISR 如果得到消息:*err = OS_NO_ERR,返回消息指针,否则进Pend timeout: >0 -> 最长等待时间 =0 -> 永远等待 如果timeout后仍未得到消息, *err = OS_TIMEOUT,返回空指针 可能产生任务切换

向消息队列发送消息(FIFO)
INT8U OSQPost( OS_EVENT *pevent, void *msg /* 消息队列指针 */ /* 消息指针 */

)

以FIFO方式发送消息 操作成功,返回OS_NO_ERR pevent要求为非空指针,否则返回 OS_ERR_PEVENT_NULL msg要求为非空指针,否则返回 OS_ERR_POST_NULL_PTR 若消息队列满,返回OS_Q_FULL,新消息发送失败 可能产生任务切换

向消息队列发送消息(LIFO)
INT8U OSQPostFront( OS_EVENT *pevent, void *msg /* 消息队列指针 */ /* 消息指针 */

)

以LIFO方式发送消息,将消息插在最前面 操作成功,返回OS_NO_ERR pevent要求为非空指针,否则返回 OS_ERR_PEVENT_NULL msg要求为非空指针,否则返回 OS_ERR_POST_NULL_PTR 若消息队列满,返回OS_Q_FULL,新消息发送失败 可能产生任务切换

向消息队列发送消息(扩展)
INT8U OSQPostOpt( OS_EVENT *pevent, /* 消息队列指针 */ void *msg, /* 消息指针 */ INT8U opt /* 发送选项 */

)

操作成功,返回OS_NO_ERR pevent要求为非空指针,否则返回OS_ERR_PEVENT_NULL msg要求为非空指针,否则返回OS_ERR_POST_NULL_PTR 若消息队列满,返回OS_Q_FULL,新消息发送失败 可选的opt:
OS_POST_OPT_BOARDCAST OS_POST_OPT_FRONT ‘0’或其它值 广播 LIFO FIFO

可能产生任务切换

从消息队列取消息(无等待)
Void *OSQAccept( OS_EVENT *pevent /* 消息队列指针 */ ) 若得到消息,返回消息指针,否则返回空 指针 ISR可以使用

清空消息队列
INT8U OSQFlush( OS_EVENT *pevent /* 消息队列指针 */ ) 清空给定消息队列的所有消息。成功返回 OS_NO_ERR

消息队列信息获取
INT8U OSQQuery( OS_EVENT *pevent, /* 消息队列指针 */ OS_Q_DATA *pdata, /*消息队列数据结 构指针*/ ) 成功返回OS_NO_ERR,同时拷贝相应内容 到*pdata

用消息队列做计数信号量
初始化消息队列数组的多个指针为非NULL 使用者先利用OSQPend()请求该“信号量”,操作完临界资源后再利用OSQPost() 释放 该“信号量” OS_EVENT *QSem; void *QMsgTbl[N_RESOURCES]; void main(void){ int i; OSInit(); QSem = OSQCreate(&QMsgTbl[0], N_RESOURCES); for(i = 0; i<N_RESOURCES; i++) OSQPost(QSem, (void *)1); OSTaskCreate(Task1, ..,…); OSStart(); . . }

}

用消息队列做计数信号量(续)
void Task1(void *pdata){ INT8U err; for(;;){ OSQPend(QSem, 0, &err); . . /* 操作资源 */ . OSQPost(QSem, (void *)1); }

}

Task的“私有”消息队列模式
为每一个Task创建专用消息队列 所有需发给该Task的消息都送到唯一消息队列

Client-Server模式

Task 与消息邮箱/消息队列练习
消息 tSender tReceiver

Acive by Delay

Wait messaeg

内存管理
内存碎片
C语言中使用malloc()/free()申请/释放内存堆(Heap) 中的内存
A B C B C A

当堆中所有的空闲内存块都小于请求的内存大小时, 这些内存块称为(外部)碎片 malloc()/free()的执行时间不确定,不利于实时系统

内存管理要点
在μC/OS-II 中,操作系统把连续的大块 内存按分区来管理。每个分区中包含有整 数个大小相同的内存块。 利用这种机制,μC/OS-II 对malloc()和 free()函数进行了改进,使得它们可以分配 和释放固定大小的内存块。这样一来,函 数的执行时间也是固定的了。

内存管理要点
在一个系统中可以有多个内存分区。这 样,用户的应用程序就可以从不同的内存 分区中得到不同大小的内存块。
分区1 分区2 分区3

内存管理相关
建立内存分区:OSMemCreate() 分配内存块:OSMemGet() 释放内存块:OSMemPut() 查询内存分区状态:OSMemQuery()

建立内存分区
OS_MEM *OSMemCreate( void *addr, /* 分区基址 */ INT32U nblks, /* 分区内内存块数量 */ INT32U blksize, /* 内存块大小 */ INT8U *err /* 错误码缓冲指针 */ ) 成功返回分区指针(句柄),否则返回空指针 要预先定义内存分区数组(二维)

建立内存分区(例)
OS_MEM *CommTxBuf; INT8U CommTxPart[100][32]; void main (void) { INT8U err; OSInit(); . . CommTxBuf = OSMemCreate(CommTxPart, 100, 32, &err); . . OSStart();

}

OSMemCreate()

分配内存块
void *OSMemGet ( OS_MEM *pmem, /* 分区指针(句柄) */ INT8U *err ) 成功返回内存块指针,否则返回空指针 内存块大小固定(不同分区可能不同), 可能存在内部碎片

释放内存块
INT8U OSMemPut ( OS_MEM *pmem, /* 分区指针(句柄) */ void *pblk /* 内存块指针 */ ) 成功返回OS_NO_ERR 失败原因:
OS_MEM_INVALID_PMEM OS_MEM_INVALID_PBLK OS_MEM_FULL

查询内存分区状态
INT8U OSMemQuery ( OS_MEM *pmem, /*分区指针(句柄) */ OS_MEM_DATA *pdata /* 分区数据结构指针*/

)

成功返回OS_NO_ERR OS_MEM_DATA数据结构:

typedef struct { void *OSAddr; /* 指向内存分区首地址的指针 */ void *OSFreeList; /* 指向空闲内存块链表首地址的指针 */ INT32U OSBlkSize; /* 每个内存块所含的字节数 */ INT32U OSNBlks; /* 内存分区总的内存块数 */ INT32U OSNFree; /* 空闲内存块总数 */ INT32U OSNUsed; /* 正在使用的内存块总数 */ } OS_MEM_DATA;

使用内存分区(例)

等待内存分区的内存块(1/2)
在内存分区暂时没有可用的空闲内存块的情况下,让一个申请内存块的任务等待 -为特定内存分 区加信号量 OS_EVENT *SemaphorePtr; OS_MEM *PartitionPtr; INT8U Partition[100][32]; OS_STK TaskStk[1000]; void main (void) { INT8U err; OSInit(); . . SemaphorePtr = OSSemCreate(100); PartitionPtr = OSMemCreate(Partition, 100, 32, &err); . OSTaskCreate(Task, (void *)0, &TaskStk[999], &err); . OSStart(); }

等待内存分区的内存块(2/2)
void Task (void *pdata) { INT8U err; INT8U *pblock; for (;;) { OSSemPend(SemaphorePtr, 0, &err); (7) pblock = OSMemGet(PartitionPtr, &err); (8) . . /* 使用内存块 */ . OSMemPut(PartitionPtr, pblock); (9) OSSemPost(SemaphorePtr); (10) }

}

设计实现自己的malloc()/free()
创建多个内存分区。根据系统需求,每个分区有 不同的块大小和数量 建立多分区统一管理接口函数,根据申请内存大 小到适合分区取内存块。 主要接口函数包括:
memInit():多分区初始化 memMalloc():根据申请内存大小到适合的分区申请 内存块 memFree():根据内存块指针释放到原有分区 memQuery():取各分区状态

保护机制(互斥?) 等待机制

事件标志组(event flag)
“事件标志组”是由2进制比特组(数量: 8/16/32)标识的0/1组合,每个比特表示一 个事件 被创建后,组合中的比特可被置1或清0 Task可以等待某种事件组合条件的发生 (ISR只能以无等待方式操作)

事件标志组相关
事件标志组创建:OSFlagCreate() 事件标志组删除:OSFlagDel() 事件标志组等待:OSFlagPend() 事件标志组标志置1或清0:OSFlagPost() 无等待获取事件标志组标志: OSFlagAccept() 事件标志组状态查询: OSFlagQuery()

事件标志组操作
OSFlagCreate() OSFlagDel() OSFlagPost() Task OSFlagAccept() OSFlagPend() OSFlagQuery()

Task

ISR

OSFlagPost()

OSFlagAccept()

ISR

事件标志组的事件等待条件组合
OS_FLAG_WAIT_CLR_ALL OS_FLAG_WAIT_CLR_AND OS_FLAG_WAIT_CLR_ANY OS_FLAG_WAIT_CLR_OR OS_FLAG_WAIT_SET_ALL OS_FLAG_WAIT_SET_AND OS_FLAG_WAIT_SET_ANY OS_FLAG_WAIT_SET_OR :指定标志全为“0”

:指定标志有一个为“0”

:指定标志全为“1”

:指定标志有一个为“1”

事件标志组创建
OS_FLAG_GRP *OSFlagCreate( OS_FLAGS flags, /* 事件标志初值 */ INT8U *err /* 错误码缓冲指针 */ ) 成功返回事件标志组节点指针(句柄),err = OS_NO_ERR 失败原因:OS_ERR_CREATE_ISR (ISR不能创 建)/ OS_FLAG_GRP_DEPLETED (没有空闲资源) OS_FLAG可定义为INT8U/INT16U/INT32U

事件标志组删除
OS_FLAG_GRP *OSFlagDel( OS_FLAG_GRP *pgrp, /* 标志组句柄 */ INT8U opt, /* 删除选项 */ INT8U *err /* 错误码缓冲指针 */ ) ISR不能使用,否则返回OS_ERR_DEL_ISR opt:OS_DEL_NO_PEND -> 没有Task因等待该标志组被 挂起时删除,否则返回OS_ERR_TASK_WAITING OS_DEL_ALWAYS -> 强制删除,所有正在等待该 标志组的Task进入就绪态 成功返回空指针,*err = OS_NO_ERR

事件标志组等待(1/2)
OS_FLAGS OSFlagPend( OS_FLAG_GRP *pgrp, /* 标志组句柄 */ OS_FLAGS flags, /* 指定事件标志(置1) */ INT8U wait_type, /* 等待条件类型 */ INT16U timeout, /* 等待时间(Tick数) */ INT8U *err /* 错误码缓冲指针 */ ISR不能使用,否则返回OS_ERR_PEND_ISR 如果事件条件满足:*err = OS_NO_ERR,返回标志组当前flag值 (可能被consume过),否则进Pend timeout: >0 -> 最长等待时间 =0 -> 永远等待 如果timeout后条件仍未满足, *err = OS_TIMEOUT,返回标志组 当前flag值 可能产生任务切换

)

事件标志组等待(2/2)
consume(标志消费)
函数允许在所等待事件发生后,重新清除或设置对应 事件标志位,即相应标志位取反 利用OS_FLAG_CONSUME同wait_type的或操作实现 若不选此功能,事件标志状态不变 例如: OSFlagPend( OSFlagMyGrp, (OS_FLAGS)0x03, (FLAG_WAIT_SET_ANY + OS_FLAG_CONSUME), 0, &err);

事件标志组标志置1或清0
OS_FLAGS OSFlagPost( OS_FLAG_GRP *pgrp, /* 标志组句柄 */ OS_FLAGS flags, /* 指定事件标志(置1) */ INT8U operation, /* 标志操作类型 */ INT8U *err /* 错误码缓冲指针 */ 成功返回当前flag值,*err = OS_NO_ERR 失败flag返回0,err = 出错原因,包括:
OS_FLAG_INVALID_PGRP OS_ERR_EVENT_TYPE OS_FLAG_INVALID_OPT OS_FLAG_CLR OS_FLAG_SET

)

Operation:

可能产生任务切换

无等待获取事件标志组标志
OS_FLAGS OSFlagAccept( OS_FLAG_GRP *pgrp, /* 标志组句柄 */ OS_FLAGS flags, /* 指定事件标志(置1) */ INT8U wait_type, /* 等待条件类型 */ INT8U *err /* 错误码缓冲指针 */ ) ISR可以使用,不产生任务切换 其他同OSFlagPost

事件标志组状态查询
OS_FLAGS OSFlagAccept( OS_FLAG_GRP *pgrp, /* 标志组句柄 */ INT8U *err /* 错误码缓冲指针 */ ) 成功返回当前flag,*err = OS_NO_ERR

事件标志组内部结构
OS_FLAG_GRP OS_FLAG_NODE

OS_EVENT_TYPE_FLAG

wait_type
NULL

wait_type

wait_type

OS_TCB

OS_TCB

OS_TCB

系统启动
void OSInit(void);
系统初始化

void OSStart(void);
系统启动,选择优先级最高的Task调度运行。 在此之前应至少创建一个Task。 用户必须在OSStart()之后再开启系统Tick,因 此在Task中进行

中断相关
void OSIntEnter(void);
关中断;中断嵌套计数加1;开中断

void OSIntExit(void);
关中断;中断嵌套计数减1;[处理堆栈使之能返回被打断的 Task];开中断

以上API在某些处理器环境中( 如RISC )使用 例:用户中断服务子程序:
保存全部CPU寄存器; 调用OSIntEnter()或OSIntNesting直接加1 执行用户代码做中断服务; 调用OSIntExit(); 恢复所有CPU寄存器; 执行中断返回指令;

临界资源的极端保护
void OSSchedLock(void);
关闭内核Task调度

void OSSchedUnlock(void);
回复内核Task调度

OS_ENTER_CRITICAL()
关中断

OS_EXIT_CRITICAL()
开中断

其他API
INT16U OSVersion(void);
返回系统版本号

void OSStatInit(void);
初始化统计Task OSStatInit()必须在时钟节拍启动之后调用 如果用户应用程序打算使用统计任务,用户必 须在初始化时建立一个唯一的任务,在这个任 务中调用OSStatInit()。

系统启动示例
void main (void) { OSInit(); /* 初始化uC/OS-II */ /* 创建用户起始任务(为了方便讨论,这里以TaskStart()作为起始任务) */ OSStart(); /* 开始多任务调度 */ } void TaskStart (void *pdata) { /* 安装并启动Tick时钟 */ OSStatInit(); /* 初始化统计任务*/ /* 创建用户应用程序任务 */ for (;;) { /* TaskStart()的代码 */ } }

demo

DEMO CODE


相关文章:
嵌入式实时操作系统_uCOSII_图文.pdf
嵌入式实时操作系统_uCOSII - uC/OS-II 北京邮电大学计算机学院
嵌入式实时操作系统(uCOS_II)详解_图文.pdf
嵌入式实时操作系统(uCOS_II)详解_信息与通信_工程科技_专业资料。知名的开源实时嵌入式操作系统uC OS的比较详细的介绍,比较适合初学者入门 ...
嵌入式实时操作系统uCOS-II经典实例 基于STM32处理器_图文.pdf
很好的文章,嵌入式实时操作系统uCOS-II经典实例 基于STM32处理器 2018-06-21 00:55:45 很好,正需要,嵌入式实时操作系统uCOS-II经典实例 基于STM32处理器 2018...
uCOS-II嵌入式实时操作系统原理与移植_图文.pdf
uCOS-II嵌入式实时操作系统原理与移植 - 采用结构图、表格方式清晰地介绍了uC/OS-II嵌入式操作系统的特点、文件结构、任务调度与通信、操作系统在硬件上的运行过程...
第九讲 uCOS-II嵌入式实时操作系统_图文.ppt
第九讲 uCOS-II嵌入式实时操作系统_工学_高等教育_教育专区。uCOS-II嵌入式实时操作系统 第九讲 uC/OS-II 实时操作系统 第九讲 uC/OS-II 嵌入式实时操作...
嵌入式实时操作系统uCOS-II(就绪算法)_图文.ppt
嵌入式实时操作系统uCOS-II(就绪算法)_计算机软件及应用_IT/计算机_专业资料。嵌入式系统技术福州大学物理与信息工程学院 孙旭飞 任务控制块(TCB) ? μC/OS-II ...
嵌入式实时操作系统(uCOS)分析_图文.ppt
嵌入式实时操作系统(uCOS)分析_信息与通信_工程科技_专业资料。主要对现在中小型嵌入式应用中采用的嵌入式实时操作系统UCOS进行分析 ...
以UCOSIII为例-嵌入式实时操作系统概述_图文.pdf
UCOSIII为例-嵌入式实时操作系统概述 - 嵌入式实时操作系统概述 以μC
第十二讲(嵌入式实时操作系统ucosII程序设计④)_图文.ppt
第十二讲(嵌入式实时操作系统ucosII程序设计④) - “嵌才工程”-ARM系统设计开 发 中断处理在裸机操作和ucos-ii操作下的不同 对于嵌入式系统来说,中断处理是...
嵌入式实时操作系统UCOSⅡ的移植_图文.pdf
嵌入式实时操作系统UCOSⅡ的移植 - 嵌人式实时操作系统UC/OSI¨的移植
嵌入式系统第八章 嵌入式实时操作系统cos -ii图文_图文.ppt
嵌入式系统第八章 嵌入式实时操作系统cos -ii图文_计算机软件及应用_IT/
嵌入式实时操作系统UCOS原理与实践1_图文.ppt
嵌入式实时操作系统UCOS原理与实践1_信息与通信_工程科技_专业资料。嵌入式实时操作系统 μC/OS原理与实践科技大学 引言:关于图书 1.专业说明 ? 考虑到各专业读者...
嵌入式实时操作系统_图文.ppt
嵌入式实时操作系统 - 基于STM32的μC/OS-II移植 控制工程 μC/O
Chap8_嵌入式实时操作系统uCOS-Ⅱ分析_图文.ppt
Chap8_嵌入式实时操作系统uCOS-Ⅱ分析 - 嵌入式系统 嵌入式实时操作系统?C/OS-Ⅱ分析 2011年9月 1 主要内容 ? ? ? ? ? 嵌入式操作系统 ?C/OS-Ⅱ...
嵌入式实时操作系统uCOS-II(高清).pdf
嵌入式实时操作系统uCOS-II(高清) - 第一章:范例 在这一章里将提供三个范例来说明如何使用 ?C/OS-II。笔者之所以在本书一开始就写 这一章是为了让读者尽快...
嵌入式实时操作系统UCOS原理与实践实验教程1_图文.ppt
嵌入式实时操作系统UCOS原理与实践实验教程1 - 嵌入式实时操作系统μC/OS
嵌入式实时操作系统简介_图文.ppt
嵌入式实时操作系统简介 - 嵌入式系统设计与实例开发 ARM与?C/OS-Ⅱ 第三讲 实时嵌入式操作系统简介 1 第三讲、嵌入式实时操作系统简介 一、嵌入式实时操作...
chapter-4-嵌入式实时操作系统_图文.ppt
chapter-4-嵌入式实时操作系统 - 第四章 嵌入式操作系统RTOS 1.
嵌入式实时操作系统uCOSII的分析.doc
嵌入式实时操作系统uCOSII的分析_语文_初中教育_教育专区。嵌入式实时操作系统uCOSII的分析.doc 嵌入式实时操作系统 uCOSII 的分析 引言 早在 20 世纪 60 年代,...
嵌入式实时操作系统ucosii课后答案.doc
嵌入式实时操作系统ucosii课后答案_信息与通信_工程科技_专业资料。嵌入式实时操作系统ucosii 第一章 1.什么是操作系统?它应具备什么功能? 操作系统是控制其他程序...