μC/OS-II的任务之间的通讯与同步
原因挂起了。[见4.07节,挂起一个任务,OSTaskSuspend(),和4.08节,恢复一个任务,
OSTaskResume()]。
另外,.OSEventTaskRdy()函数要在中断禁止的情况下调用。
程序清单L6.6使一个任务进入就绪状态
voidOSEventTaskRdy(OS_EVENT*pevent,void*msg,INT8Umsk)
{
OS_TCB*ptcb;
INT8Ux;
INT8Uy;
INT8Ubitx;
INT8Ubity;
INT8Uprio;
y=OSUnMapTbl[pevent->OSEventGrp];(1)
bity=OSMapTbl[y];(2)
x=OSUnMapTbl[pevent->OSEventTbl[y]];(3)
bitx=OSMapTbl[x];(4)
prio=(INT8U)((y3)+x);(5)
if((pevent->OSEventTbl[y]=~bitx)==0){(6)
pevent->OSEventGrp=~bity;
}
ptcb=OSTCBPrioTbl[prio];(7)
ptcb->OSTCBDly=0;(8)
ptcb->OSTCBEventPtr=(OS_EVENT*)0;(9)
#if(OS_Q_EN(OS_MAX_QS>=2))||OS_MBOX_EN
ptcb->OSTCBMsg=msg;(10)
#else
msg=msg;
#endif
ptcb->OSTCBStat=~msk;(11)
if(ptcb->OSTCBStat==OS_STAT_RDY){(12)
OSRdyGrp|=bity;(13)
OSRdyTbl[y]|=bitx;
}
}

图F6.4使一个任务进入就绪状态——Figure6.4
6.4 使一个任务进入等待某事件发生状态,OSEventTaskWait()
程序清单L6.7是OSEventTaskWait()函数的源代码。当某个任务要等待一个事件的发生时,相应事件的OSSemPend(),OSMboxPend()或者OSQPend()函数会调用该函数将当前任务从就绪任务表中删除,并放到相应事件的事件控制块的等待任务表中。
程序清单L6.7使一个任务进入等待状态
voidOSEventTaskWait(OS_EVENT*pevent)
{
OSTCBCur->OSTCBEventPtr=pevent;(1)
if((OSRdyTbl[OSTCBCur->OSTCBY]=~OSTCBCur->OSTCBBitX)==0){(2)
OSRdyGrp=~OSTCBCur->OSTCBBitY;
}
pevent->OSEventTbl[OSTCBCur->OSTCBY]|=OSTCBCur->OSTCBBitX;(3)
pevent->OSEventGrp|=OSTCBCur->OSTCBBitY;
}
在该函数中,首先将指向事件控制块的指针放到任务的任务控制块中[L6.7(1)],接着将任务从就绪任务表中删除[L6.7(2)],并把该任务放到事件控制块的等待任务表中[L6.7(3)]。
6.5 由于等待超时而将任务置为就绪态,OSEventTO()
程序清单L6.8是OSEventTO()函数的源代码。当在预先指定的时间内任务等待的事件没有发生时,OSTimeTick()函数会因为等待超时而将任务的状态置为就绪。在这种情况下,事件的OSSemPend(),OSMboxPend()或者OSQPend()函数会调用OSEventTO()来完成这项工作。该函数负责从事件控制块中的等待任务列表里将任务删除[L6.8(1)],并把它置成就绪状态[L6.8(2)]。最后,从任务控制块中将指向事件控制块的指针删除[L6.8(3)]。用户应当注意,调用OSEventTO()也应当先关中断。
程序清单L6.8因为等待超时将任务置为就绪状态
voidOSEventTO(OS_EVENT*pevent)
{
if((pevent->OSEventTbl[OSTCBCur->OSTCBY]=~OSTCBCur->OSTCBBitX) ==0)
{ (1)
pevent->OSEventGrp=~OSTCBCur->OSTCBBitY;
}
OSTCBCur->OSTCBStat=OS_STAT_RDY;(2)
OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0;(3)
}
6.6 信号量
μC/OS-II中的信号量由两部分组成:一个是信号量的计数值,它是一个16位的无符号整数 (0到65,535之间) ; 另一个是由等待该信号量的任务组成的等待任务表。 用户要在OS_CFG.H中将OS_SEM_EN开关量常数置成1,这样μC/OS-II才能支持信号量。
在使用一个信号量之前, 首先要建立该信号量, 也即调用OSSemCreate()函数(见下一节) ,
对信号量的初始计数值赋值。该初始值为0到65,535之间的一个数。如果信号量是用来表示一个或者多个事件的发生, 那么该信号量的初始值应设为0。 如果信号量是用于对共享资源的访问,那么该信号量的初始值应设为1(例如,把它当作二值信号量使用)。最后,如果该信号量是用来表示允许任务访问n个相同的资源,那么该初始值显然应该是n,并把该信号量作为一个可计数的信号量使用。
μC/OS-II提供了5个对信号量进行操作的函数。它们是:OSSemCreate(),OSSemPend(),
OSSemPost(),OSSemAccept()和OSSemQuery()函数。图F6.5说明了任务、中断服务子程序和
信号量之间的关系。图中用钥匙或者旗帜的符号来表示信号量:如果信号量用于对共享资源的
访问,那么信号量就用钥匙符号。符号旁边的数字N代表可用资源数。对于二值信号量,该值
就是1;如果信号量用于表示某事件的发生,那么就用旗帜符号。这时的数字N代表事件已经发
生的次数。从图F6.5中可以看出OSSemPost()函数可以由任务或者中断服务子程序调用,而
OSSemPend()和OSSemQuery()函数只能有任务程序调用。

图F6.5任务、中断服务子程序和信号量之间的关系——Figure6.5
6.6.1 建立一个信号量,OSSemCreate()
程序清单L6.9是OSSemCreate()函数的源代码。首先,它从空闲任务控制块链表中得到一个事件控制块[L6.9(1)],并对空闲事件控制链表的指针进行适当的调整,使它指向下一个空闲的事件控制块[L6.9(2)]。如果这时有任务控制块可用[L6.9(3)],就将该任务控制块的事件类型设置成信号量OS_EVENT_TYPE_SEM[L6.9(4)]。其它的信号量操作函数OSSem???()通过检查该域来保证所操作的任务控制块类型的正确。例如,这可以防止调用OSSemPost()函数对一个用作邮箱的任务控制块进行操作[6.06节,邮箱]。接着,用信号量的初始值对任务控制块进行初始化[L6.9(5)],并调用 OSEventWaitListInit()函数对事件控制任务控制块的等待任务列表进行初始化[见6.01节,初始化一个任务控制块,OSEventWaitListInit()][L6.9(6)]。因为信号量正在被初始化,所以这时没有任何任务等待该信号量。最后,OSSemCreate()返回给调用函数一个指向任务控制块的指针。以后对信号量的所有操作,如OSSemPend(),OSSemPost(),OSSemAccept()和OSSemQuery()都是通过该指针完成的。因此,这个指针实际上就是该信号量的句柄。如果系统中没有可用的任务控制块,OSSemCreate()将返回一个NULL指针。
评论