职业类型:电子爱好者
平均每日在线时长:晚上21 - 24
对ST产品的了解及使用情况:是上大学时通过同学了解到,用在工业上比较多,抗干扰性能强,市场占有量大。
如果我是版主将如何为网友服务及我的竞争优势:本来准备买北京麦克泰克公司的uC/Eval-STM32F107 评估板,学习一下ST的Cortex-M3芯片、uc/os-iii和网络 ,偶然间看到这么好的活动,参加一下。我的竞争优势是对uc/os-ii比较了解,如果网友对这方面有什么问题,及时给予帮助。下面是刚看完邵贝贝老师的嵌入式实时操作系统uc/os-ii 写的总结,还没有写完。初学者,有什么地方理解不对地方,欢迎大家拍砖。
UC/OS—II 四、任务管理任务可以是一个无限的循环,也可以在一次执行完毕后被删除掉(并不是真正的删除掉,只是内核不在理会该任务),任务看起来与C函数一样,有一个参数和返回类型,只是绝不返回。任务返回类型必须是viod。 Void YourTask(void *pdata) { For(;;){ /*用户代码*/ 调用内核服务: OSFlagPend(); OSMboxPend(); OSMutexPend(); OSQPend(); OSSemPend(); OSTaskSuspend(OS_PRIO_SELF); OSTimDly(); OSTimDlyHSM(); /*用户代码*/ } Void YourTask(void *pdata) { /*用户代码*/ OSTaskDel(OS_PRIO_SELF); }
优先级的值越低,表示任务的优先级越高。
1、INT8U OSTaskCreate(void (*task)(void *pd),void *pdata,OS_STK *ptos,INT8U prio)建立任务函数,建立同时任务插入就绪表。
task 函数指针指向任务代码;padat传任务的参数的指针;ptos分配给任务的堆栈的栈顶指针;prio 分配给任务的优先级;
如果想让内核管理任务,必须先建立任务。任务可以多任务调度开始前建立,也可以在其他任务执行的过程中建立。在多任务调度前(OSStart()),必须至少建立一个任务。任务不能中断服务程序建立。
该函数会对要建立的任务进行一次堆栈初始化和任务控制块初始化。如果函数是在某个任务运行中调用的,它会进行一次调度
(判断新建立的任务的优先级是否比建立它的任务的优先级高,如果高进行一次调度,否则继续运行。),否则返回。
2 、INT8U OSTaskCreateExt( void (*task)(void *pd)
void *Pdata,
OS_STK *ptos,
INT8U prio,
INT16U id,
OS_STK *pbos,
INT32 stk_size,
void *pext,
INT16U opt)
|
五、时间管理
1、Void OSTimeDly(INT16U ticks) 延时函数
任务通过调用本函数进行延时,实质是任务脱离就绪表同时把延时时间赋给本任务的任务控制块的[url=]OSTCBDly[/url]域,然后进行任务调度。当 延时时间到了时钟节拍函数void OSTimeTick(void)会把任务插入就绪态表中(有可能由于其他原因而不能进入就绪态如等待消息)。 2、INT8U OSTimeDlyHSM(INT8U hours,INT8U minutes,INT8U seconds,INT16U milli) 按时分秒延时 3、INT8U OSTimeDlyResume(INT8U prio) 恢复延时的任务
通过把任务控制块的OSTCBDly域,把任务插入就绪表(也可能由于其他原因而不能进入就绪态如等待消息)
六、事件控制块管理
有关事件控制块发送消息的说明:
1、 当有任务等待邮箱中的消息或消息队列中的消息被阻塞时,另外一个任务向共同的消息邮箱和消息队列发送消息是通过调用
INT8U OS_EventTaskRy(OS_EVENT *pevent,void *msg,INT8U msk) 函数发送消息(实质是向事件控制块的等待消息的任务列表的最高优先级任务的任务控制块的OSTCBMsg存放一个消息指针) 2、当有任务等待信号量和互斥信号量时被阻塞时,另外一个发送信号量的任务通过调用
INT8U OS_EventTaskRy(OS_EVENT *pevent,void (*)0,INT8U msk) 函数发送消息给等待这个消息的任务(实质是把事件控制块的等待信号量的任务列表的最高优先级任务的任务控制块的OSTCBStat的OS_STAT_SEM位清零)
3、当有任务等待互斥信号量时被阻塞时,另外一个任务置互斥信号量有效是通过
INT8U OS_EventTaskRy(OS_EVENT *pevent,(void *)0,INT8U msk) 函数发送消息(实质是把事件控制块的等待信号量的任务列表的最高优先级任务的任务控制块的OSTCBStat的OS_STAT_MUTEX位清零)
typedef struct {
INT8U OSEventTpye; //表示事件控制块类型:信号量、互斥信号量、消息邮箱、消息队列
INT8U OSEventGRP;
INT16U OSEventCtr;//没有任务等待信号量时简单对OSEventCtr加一;标志互斥信号量可用是使OSEventCtr低八位置FF
void *OSEventPtr;//消息邮箱用来存放一个指向消息的指针;消息队列用来存放一个指向队列控制块的指针,消息指针存放在队列控制块的OSQin或OSQout中
INT8U OSEventTbl[ OS_EVNT_TBL_SIZE];
}OS_EVENT;
1、void OS_EventWaitLlistInit( OS_EVENT *pevent) 初始化ECB块的等待任务列表
任务通过调用这个函数初始化一个空的等待任务列表(是把ECB的OSEventGrp和OSEventTbl[ ]给初始化了);
2、INT8U OS_EventTaskRy(OS_EVENT *pevent,void *msg,INT8U msk)
3、Void OS_EventTaskWait( OS_EVENT *pevent)使一个任务进入等待状态, 插入事件的等待任务列表中。
任务得不到消息通过调用本函数把自己插入等待任务列表给阻塞掉。
4、Void OS_EventTo(OS_EVENT *pevent) 由于等待超时而将任务置位就绪态
等待超时时 时钟节拍函数void OSTimeTick(void)会把任务插入就绪态表中。
等待的消息任务从阻塞态变为运行态时,任务会检查是由于什么原因运行,如果是由于等待超时调用本函数使任务脱离等待任务列表。
七、信号量管理
1、 OS_EVENT *OSSemCreate( INT16U cnt) 1. 表示事件时信号量初始化为0。2.对共享资源的访问时,信号量初始化为1。3.表示可以可访问的N个相同资源,信号量初始化为N。
2、OS_EVENT *OSSemDel( OS_EVENT *pevent,INT8U opt,INT8U *err)1. 无等待的删除信号量,所有等待的任务都得到该信号量,然后把这个事件控制块标志位未使用。这种删除行为比较危险,违背了设置Sem初衷。如果有任务等待在该信号量,然后进行任务调度。2.有等的删除信号量,如果没有任务等待互斥信号量直接删除并返回,否则不删除信号量直接返回。
3、void OSSemPend(OS_EVENT *pevent , INT16U timeout, INT8U *err)等待一个信号量
如果有信号量可用,事件控制块的OSEventCnt域减一,直接返回。否则挂起调用本函数的任务,然后进行任务调度,再次返回时需要检测是由于什么原因返回;是等待超时还等到信号量了,如果超时该任务需要从事件控制的等待信号量的任务列表中删除。
4、INT8U OSSemPost (OS_EVENT *pevent) 发送一个信号量(置等待该信号量的任务列表中最高优先级的任务的任务控制块中的OSTCBStat中的OS_STAT_SEM位零)
如果有任务等待信号量,使等待该信号量的任务列表中最高优先级的任务置于就绪态,否则使事件控制块的OSEventCnt加一
八、互斥信号量管理mutex(实现共享资源的独占式处理)
1、OS_EVENT *OSMutexCreat(INT8U prio,INT8U *err)建立互斥信号量 prio :优先级继承优先级
2、OS_EVENT *OSMutexCreat(OS_EVENT *pevent,INT8U opt,INT8U * err) 删除互斥信号量
说明:删除互斥信号量之前,应删除所有可能用到mutex的任务。1. 无等待的删除互斥信号量,所有等待的任务好像都得到消息一个互斥信号量,这种行为比较危险,违背了设置mutex初衷(如果有任务等待互斥信号量,然后进行任务调度);2.有等的删除互斥信号量,如果没有任务等待互斥信号量直接删除并返回,否则不删除互斥信号量直接返回。
3、void OSMutexPend(OS_EVENT *pevent,INT16U timeout,INT8U * err)等待互斥信号量
如果这个事件控制块可以用直接返回调用函数,否则挂起自己,等待再次运行,再次运行时需检查是由于什么原因运行(得到互斥信号量还是由于等待超时),是否得到互斥信号量通过检测任务控制块的OSTCBSstat。
4、void OSMutexPost(OS_EVENT *pevent) 释放互斥信号量
要检测是否在优先级继承优先级释放,如果是脱离就绪表并还原到原来的优先级上。还要检测是否有任务在等待这个互斥信号量,如果有事件控制块的等待互斥信号量的任务列表中优先级最高的任务得到互斥信号量,并在事件控制块中(OSEventCnt)标志被这个任务占有,否则在事件控制块中标志它可用。
九、事件标志组管理
组成:1.保存当前事件标志组中各事件状态的一些标志位 2.等待这些标志位置位或清除的任务列表
事件标志组:
typedef struct {
INT8U OSFlagType;
void *OSFlagWaitList; 和uc/os中的其他等待任务列表(数组)不同,是一个双向链表
OS_FLAGS OSFlagFlags; 保存当前事件标志组 事件标志 状态
} OS_FLAG_GRP;
事件标志节点:
事件标志节点链表就相当于等待任务列表。当任务开始等待事件标志位时建立一个OS_FLAG_NODE,当等待的事件标志位发生后删除OS_FLAG_NODE。
typedef struct {
void *OSFlagNodeNext;
void *OSFlagNodePrev;
void *OSFlagNodeTCB; 指向任务控制块
void *OSFlagNodeFlagGrp; 在删除一个事件标志节点和删除仍在等待等待事件标志组的事件的任务时用到
OS_FLAGS OSFlagNodeFlags; 指明任务等待事件标志组中的那些事件标志
INT8U OSFlagNodeWaitType;
}OS_FLAG_NODE;
1、OS_FLAG_GRP *OSFlagCreate(OS_FLAGS flags, INT8U *err) 建立一个事件标志组,刚建立时事件标志节点为空(等待任务列表为空)。
2、OS_FLAG_GRP *OSFlagDel(OS_FLAG_GRP *pgrp,INT8U opt, INT8U *err) 删除一个事件标志组,opt设置删除模式:1. 无等待的删除事件标志组(如果有任务等待,进行任务调度);2.有等待的删除事件标志组
3、OS_FLAGS OSFlagPend(OS_FLAG_GRP * pgrp, OS_FLAGS flags , INT8U wait_type, INT8U timeout, INT8U *erro):等待事件标志组的事件标志位
如果得到指定的事件得到直接返回,否则挂起调用这个函数的任务再进行任务调度,再次继续运行时需判断是由于什么原因运行(等待超时或等到指定的事件(任务控制块中的OSTCBFlag)),是否得到指定事件通过检测任务控制块的OSTCBSstat。
否则挂起:挂起函数
static void OS_FlagBlock( OS_FLAG_GRP *pgrp, OS_FLAG_NODE *pnode, OS_FLAGS flags, INU8U wait_type, INT8U timeout)。
4、OS_FLAGS OSFlagPost( OS_FLAG_GRP *pgrp,OS_FLAGS flags,INT8U opt,INT8U *err) 置位或清零事件标志组中的 事件标志
遍历所有的事件标志节点,查看新设定的事件标志(flags)是否满足某个任务,遍历完检查是否进行调度。
5、static BOOLEAN OS_FlagTaskRdy(OS_FLAG_NODE* pode, OS_FLAGS flags_rdy) 等待事件标志的任务进入就绪态,释放的事件标志是存放在任务控制块中OSTCBFlagsRdy。
6 、void OS_FlagUnlink( OS_FLAG_NODE *pnode) 从事件标志 组的等待链表中删除pnode节点。
消息邮箱通过事件控制块的*OSEventPtr直接发送消息
如果有任务等待消息,消息邮箱和消息队列 都是通过任务控制块的OSTCBMsg发送消息的
十、消息邮箱:可通知一件事的发生 (邮箱初始化为NULL)或共享资源(非空指针),可以广播发送消息。
1、OS_EVENT *OSMboxCreat(void *msg) 建立一个消息邮箱 ,用于共享资源msg设置为一个非空指针。通知某件事的发生设置为NULL。
2、OS_EVENT *OSMboxDel(OS_EVENT *pevent ,INT8U opt,INT8U *err) 删除一个邮箱指:把事件控制块归还给空闲事件控制块以供再次使用1. 无等待的删除邮箱,所有等待的任务都得到消息一个邮箱(如果有任务等待,进行任务调度);2.有等的删除邮箱
3、void *OSMboxPend(OS_EVENT *pevent ,INT8U timeout,INT8U *err) 如果有消息得到直接返回,否则挂起再进行任务调度,再次继续运行时需判断是由于什么原因运行(等待超时或等到消息)
4、INT8U OSMboxPost( OS_EVENT *pevent,void *msg) 向邮箱发送一条消息 。如果有任务等待消息,向事件控制块的等待任务列表中最高优先级任务的任务控制块(ptcb->OSTCBMsg)放一条消息;否则:如果邮箱满则返回调用函数邮箱满错误,否则插入任务控制块中的OSTCBMsg
5、INT8U OSMBoxPostOpt(OS_EVENT *pevent ,void *msg, INT8U opt) opt(设置是否广播发送消息) 可以设置是否向事件控制块中的等待任务列表中的所有任务发消息
消息队列直接发送消息通过事件控制块的OSEventPtr指向的消息队列
十一、消息队列: 相当于邮箱阵列,可以广播发送消息。
1、OS_EVENT *OSQCeat(void **start, int16u size) 建立一个消息队列
2、OS_EVENT *OSQDel(OS_EVENT * pevent,int8u opt,intu *err) 删除一个消息队列指:把消息队列归还给空闲队列控制块和把事件控制块归还给空闲事件控制块。分两种情况:1. 无等待的删除消息队列,所有等待的任务都得到一个消息(如果有任务等待,进行任务调度);2.有等的删除消息队列
3、void * OSQPend( OS_EVENT *pevent,INT16U timeoutm, INT8U *error) 如果有消息得到直接返回,否则挂起再进行任务调度,再次继续运行时需判断是由于什么原因运行(等待超时或等到消息(消息在任务控制块中))
4、INT8U OSQPost(OS_EVENT*pevent,void *msg) 向消息队列发送一条消息 。如果有任务等待消息,向事件控制块的等待任务列表中最高优先级的任务的任务控制块的OSTCBSMsg(消息指针)中放一条消息;否则:如果消息队列满则返回调用函数消息队列满错误,否则插入消息队列。
十二、内存管理
在嵌入式实时操作系统中,用malloc()和free()分配内存和释放内存很危险,造成内存碎片。在uc/os-ii中,操作系统把连续的大块内存安分区来管理。每个分区包含整数个大小相同的内存块。利用这种机制,uc/os-ii对malloc和free函数进行改进,使得它们可以得到和释放固定大小的内存块。这样malloc和free函数的执行时间就确定。
在一个系统中可以有多个内存分区,这样应用程序就可以从不同内存分区中得到不同大小的内存块;但是内存块释放时,必须重新放回到它以前所属的内存分区。内存碎片就得到解决。
1、内存控制块
在uc/os-ii中使用内存控制块的数据结构跟踪每一个内存分区,系统中每一个内存分区都有它自己的内存控制块。
typedef struct {
void *OSMemAddr;
void *OSMemFreeList;
INT32U OSMemBlkSize;
INT32U OSMemNBlks;
INT32U OSMemNFree;
}OS_MEM;
uc/os-ii在启动时就对内存管理器进行初始化 ,OSinit()调用OSMemInit()函数建立一条空余内存控制块链表。
2、OS_Mem *OSMemCreate(void * addr,INT32U nblks,INT8U blksize,INT8U *err)建立一个内存分区
addr内存分区的起始地址, nblks分区内的内存块总数, blksize每个内存块的字节数,err指向出错信息代码的指针。
同一分区中的所有空余内存块是由指针链串联起来的。
关键代码:
void **plink;
INT8U *pblk;
plink = (void ** )addr;
pblk = ( INT8U *) addr + blksize;
for (i =0; i<(nbks-1);i++) {
*plink = (void *)pblik;
plink = (void **) pblk;
pblk = pblk + blksize;
}
3、void * OSMemGet(OS_MEM *pmem,INT8U *err) 分配一个内存块 注意:(OSMemGet() 函数并不知道非空指针pmem是否指向了一个合法的内存分区)
应用程序调用 OSMemGet() 函数从已建立的内存分区中申请一个内存块,pmem是建立分区时由OSMemCreate()函数返回的。
应用程序必须知道内存块大小,而且在使用时不能超过内存的大小。不再使用时内存块时,必须及时释放,重新放回到所属内存分区中。
pblk = pmem->OSEMemFreeList;
pmem->OSEMemFreeLis = *( void **)pblk;
pmem->OSMemNFree--;
4、INT8U OSMem( OS_MEM *pmem, void *pblk)释放一个内存块 OSMem() 函数并知道内存块是属于哪个内存分区的。 由应用程序确保把内存块释放到合理的内存分区中。
*(void **)pblk = pmem->OSMemFreeList;
pmem->OSMemFreeList = pblk;
分配内存块时pmem指向一个合法的内存分区,使用内存块不能超过它容量,不再使用时必须及时释放到相应的内存分区中。
|
|