uC/os-ii中任务间相互通信的媒介叫做事件。
关于OS_EVENT数据结构
#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0u)
typedef struct os_event
{
INT8U OSEventType; /* Type of event control block (see OS_EVENT_TYPE_xxxx) */
void *OSEventPtr; /* Pointer to message or queue structure */
INT16U OSEventCnt; /* Semaphore Count (not used if other EVENT type) */
OS_PRIO OSEventGrp; /* Group corresponding to tasks waiting for event to occur */
OS_PRIO OSEventTbl[OS_EVENT_TBL_SIZE]; /* List of tasks waiting for event to occur */
#if OS_EVENT_NAME_EN > 0u
INT8U *OSEventName;
#endif
} OS_EVENT;
#endif
OSEventType:事件类型(信号量、互斥信号量、邮箱、消息列队)
OSEventCnt:计数器
OSEventPtr:指向一个消息
OSEventGrp与OSEventTbl[OS_EVENT_TBL_SIZE]:等待事件任务(类似于OSRdyTbl[]和OSRdyGrp)
事件块实质是一个链表
不同的任务如果使用共享资源,可能会出错。信号量类似于共享资源访问的一个标志。
比如……我们把串口终端当做一个资源。
TASK_1与TASK_2(TASK1优先级高于TASK_2)
OS_EVENT MyFirstSem;
char * CommonzSoure = "";
void Task_1(void *pdata)
{
U32 i;
#if OS_CRITICAL_METHOD == 3 //关中断的方法为3
OS_CPU_SR cpu_sr;
#endif
OS_ENTER_CRITICAL();
OS_CPU_SysTickInit(100000000/OS_TICKS_PER_SEC);
OS_EXIT_CRITICAL();
OSStatInit(); //统计任务 优先级最低
MyFirstSem = *(OSSemCreate(1));
//PIT0_Init(50000000);
UART4_Init(115200);
init_LED();
pdata = pdata;
while(1)
{
CommonzSoure = "TASK1 Using Common source ";
for(i=0;CommonzSoure[i];i++)
Uart4_SendByte(CommonzSoure[i]);
OSTimeDly(1);
}
}
void Task_2(void *pdata)
{
U32 i;
pdata = pdata;
while(1)
{
CommonzSoure = "TASK2 Using Common source ";
for(i=0;CommonzSoure[i];i++)
Uart4_SendByte(CommonzSoure[i]);
}
}
任务1发送数据“TASK1 Using Common source”
任务2发送数据“TASK2 Using Common source”
任务切换的时候 数据发送会出错。(比如我们把串口终端当做一个实体的打印机)
如果加入信号量(标记共享资源)
OS_EVENT MyFirstSem;
char * CommonzSoure = "";
void Task_1(void *pdata)
{
U32 i;
U8 err;
#if OS_CRITICAL_METHOD == 3 //关中断的方法为3
OS_CPU_SR cpu_sr;
#endif
OS_ENTER_CRITICAL();
OS_CPU_SysTickInit(100000000/OS_TICKS_PER_SEC);
OS_EXIT_CRITICAL();
OSStatInit(); //统计任务 优先级最低
MyFirstSem = *(OSSemCreate(1));
//PIT0_Init(50000000);
UART4_Init(115200);
init_LED();
pdata = pdata;
while(1)
{
OSSemPend(&MyFirstSem,0,&err);
CommonzSoure = "TASK1 Using Common source ";
for(i=0;CommonzSoure[i];i++)
Uart4_SendByte(CommonzSoure[i]);
OSSemPost(&MyFirstSem);
OSTimeDly(1);
}
}
void Task_2(void *pdata)
{
U32 i;
U8 err;
pdata = pdata;
while(1)
{
OSSemPend(&MyFirstSem,0,&err);
CommonzSoure = "TASK2 Using Common source ";
for(i=0;CommonzSoure[i];i++)
Uart4_SendByte(CommonzSoure[i]);
OSSemPost(&MyFirstSem);
}
}
OSSemAccept()可以无等待请求一个信号量。
该函数只简单返回OSEventCnt的值,并在OSEventCnt值为真的时候做OSEventCnt--;
调用OSSemAccept()函数,……不过目测资源都被TASK_2独占了。→_→
同样,信号量也可以用于限制某个资源的任务个数。
关于优先级反转与互斥信号量。
信号量的使用可能会导致优先级反转。
比如……
由于任务C(低)得到信号量,任务A等待。任务B的优先级高于任务C,故任务B先运行。直到任务B,C运行完,任务C释放信号量,优先级最高的任务A才得到CPU资源。
防止优先级反转的方法,在任务C得到信号量时把任务C的优先级升高,结束后再恢复。
uC/OS-II,互斥信号量机制可以防止优先级反转。
由于uC/OS-II不支持相同优先级,互斥信号量机制,可以使某个人物得到信号量时,优先级提到共享相同资源任务最高。
OSMutexCreate(INT8U prio,INT8U *error)
创建互斥信号量。
uC/OS-II互斥信号量支持六种操作:创建、删除、等待、释放、无条件等待获取互斥信号量、获取互斥信号量当前状态。