STM32F4X UCOSIII 事件集
- 事件的应用场景
- UCOSIII事件工作机制
- UCOSIII事件操作函数
- 事件创建函数
- 事件删除函数
- 事件发送函数
- 事件接收函数
- UCOSIII事件例程
事件在RTOS中也是一种任务间同步的机制,事件不能传递数据。跟信号量不同的是,事件可以实现一对多,多对多的同步,也就是一个事件可以唤醒多个任务,一个任务也可以等待多个事件,也可以是几个事件都发生后才唤醒任务进行事件处理。同样,也可以是多个任务同步多个事件。
事件的应用场景
- 场景1:P1需要坐公交车去某地,只有A公交可以去目的地,此时P1必须等到A公交到达后才可以出发。
- 场景2:P1需要坐公交车去某地,有A公交和B公交可以去目的地,此时P1只需等到A公交或者B公交到达后才可以出发。
- 场景3:P1约定和P2一起去某地,可以乘坐A公交和B公交去目的地,此时P1必须等待P2和公交到达才可以出发
在上述的几个场景中,我们可以将P1当做任务1,乘坐公交为事件1,同伴P2为事件2。则场景1为特定事件唤醒任务,场景2为任意事件唤醒任务,场景3为多个事件同时发生唤醒任务。
UCOSIII事件工作机制
在UCOSIII中每一个事件对象都定义了一个32位的事件标志位,也就是说每一个事件对象最多可以产生32个事件。当事件标志位为1时,则代表该事件发生,当事件标志位为0时,则代表该事件没有发生。下图就是一个事件对象里面的事件表示位,bit1/4/6/31被置1,则代表事件1、事件4、事件6和事件31发生。
假设现在有两个任务,任务1的唤醒条件是事件3或者事件5中的任意一个被置位,而任务2的唤醒条件是事件3和事件5同时发生。当事件3发生时,任务1会被唤醒,此时因为事件5还没发生,所以任务2没有被唤醒。当任务5发生时,任务2才会被唤醒。当任务接收到事件后,可以选择清除或者不清除事件标志位,当选择清除事件标志位后,改事件标志位就会被清0,如果选择不清除事件标志位,则该事件会一直存在。
UCOSIII事件操作函数
事件创建函数
/*
*p_grp:事件类型对象
*p_name:事件对象名字
*flags:初始化的事件标志位,通常为0
*p_err:错误代码
*/
void OSFlagCreate (OS_FLAG_GRP *p_grp,
CPU_CHAR *p_name,
OS_FLAGS flags,
OS_ERR *p_err)
事件删除函数
/*
*p_grp:事件类型对象
*opt:用户选项
*p_err:错误代码
*/
OS_OBJ_QTY OSFlagDel (OS_FLAG_GRP *p_grp,
OS_OPT opt,
OS_ERR *p_err)
opt可以选择OS_OPT_DEL_NO_PEND和OS_OPT_DEL_ALWAYS
- OS_OPT_DEL_NO_PEND:删除事件,如果该事件上有挂起的任务,则等待挂起的任务恢复才删除
- OS_OPT_DEL_ALWAYS:不管该事件上是否有挂起的任务,直接删除事件
事件发送函数
/*
*p_grp:事件类型对象
*flags:需要发送的事件
*opt:用户选项
*p_err:错误代码
返回值:返回事件标志位的值
*/
OS_FLAGS OSFlagPost (OS_FLAG_GRP *p_grp,
OS_FLAGS flags,
OS_OPT opt,
OS_ERR *p_err)
opt可以选择OS_OPT_POST_FLAG_SET、OS_OPT_POST_FLAG_CLR和OS_OPT_POST_NO_SCHED
- OS_OPT_POST_FLAG_SET:设置事件为置1触发
- OS_OPT_POST_FLAG_CLR:设置事件为清0触发
- OS_OPT_POST_NO_SCHED:发生事件后不调度
事件接收函数
/*
*p_grp:事件类型对象
*flags:需要接收的事件
*timeout:超时等待时间
*opt:用户选项
*p_ts:时间戳
*p_err:错误代码
返回值:返回接收到的事件标志位的值
*/
OS_FLAGS OSFlagPend (OS_FLAG_GRP *p_grp,
OS_FLAGS flags,
OS_TICK timeout,
OS_OPT opt,
CPU_TS *p_ts,
OS_ERR *p_err)
opt可以选择OS_OPT_PEND_FLAG_CLR_ALL、OS_OPT_PEND_FLAG_CLR_ANY、OS_OPT_PEND_FLAG_SET_ALL、OS_OPT_PEND_FLAG_SET_ANY、OS_OPT_PEND_FLAG_CONSUME、OS_OPT_PEND_NON_BLOCKING和OS_OPT_PEND_BLOCKING
- OS_OPT_PEND_FLAG_CLR_ALL:等待事件中所有位被清除
- OS_OPT_PEND_FLAG_CLR_ANY:等待事件中任意的位被清除
- OS_OPT_PEND_FLAG_SET_ALL:等待事件中所有位被置1
- OS_OPT_PEND_FLAG_SET_ANY:等待事件中任意的位被置1
- OS_OPT_PEND_FLAG_CONSUME:任务被唤醒后是否将标志位清除
- OS_OPT_PEND_BLOCKING:阻塞等待事件,除非事件发生,否则任务不会恢复
- OS_OPT_PEND_NON_BLOCKING:不阻塞等待事件,如果任务等待时间超过设定的超时时间,任务会恢复并返回一个错误代码
UCOSIII事件例程
/*
*********************************************************************************************************
* EXAMPLE CODE
*
* (c) Copyright 2013; Micrium, Inc.; Weston, FL
*
* All rights reserved. Protected by international copyright laws.
* Knowledge of the source code may not be used to write a similar
* product. This file may only be used in accordance with a license
* and should not be redistributed in any way.
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*
* EXAMPLE CODE
*
* IAR Development Kits
* on the
*
* STM32F429II-SK KICKSTART KIT
*
* Filename : app.c
* Version : V1.00
* Programmer(s) : YS
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#include <includes.h>
/*
*********************************************************************************************************
* LOCAL DEFINES
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* LOCAL GLOBAL VARIABLES
*********************************************************************************************************
*/
#define EVENT1_FLAG (1 << 0) // 事件1标志位
#define EVENT2_FLAG (1 << 1) // 事件2标志位
#define EVENT3_FLAG (1 << 2) // 事件3标志位
#define EVENT4_FLAG (1 << 3) // 事件4标志位
/* ----------------- APPLICATION GLOBALS -------------- */
static OS_TCB AppTaskStartTCB;
static CPU_STK AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE];
#define APPTASK1NAME "App Task1"
#define APP_TASK1_PRIO 3
#define APP_TASK1_STK_SIZE 1024
static OS_TCB AppTask1TCB;
static void AppTask1 (void *p_arg);
static CPU_STK AppTask1Stk[APP_TASK1_STK_SIZE];
#define APPTASK2NAME "App Task2"
#define APP_TASK2_PRIO 4
#define APP_TASK2_STK_SIZE 1024
static OS_TCB AppTask2TCB;
static void AppTask2 (void *p_arg);
static CPU_STK AppTask2Stk[APP_TASK2_STK_SIZE];
#define APPTASK3NAME "App Task3"
#define APP_TASK3_PRIO 4
#define APP_TASK3_STK_SIZE 1024
static OS_TCB AppTask3TCB;
static void AppTask3 (void *p_arg);
static CPU_STK AppTask3Stk[APP_TASK3_STK_SIZE];
static OS_FLAG_GRP grp;
/*
*********************************************************************************************************
* FUNCTION PROTOTYPES
*********************************************************************************************************
*/
static void AppTaskStart (void *p_arg);
/*
*********************************************************************************************************
* main()
*
* Description : This is the standard entry point for C code. It is assumed that your code will call
* main() once you have performed all necessary initialization.
*
* Arguments : none
*
* Returns : none
*********************************************************************************************************
*/
int main(void)
{
OS_ERR err;
OSInit(&err); /* Init uC/OS-III. */
OSTaskCreate((OS_TCB *)&AppTaskStartTCB, /* Create the start task */
(CPU_CHAR *)"App Task Start",
(OS_TASK_PTR )AppTaskStart,
(void *)0u,
(OS_PRIO )APP_CFG_TASK_START_PRIO,
(CPU_STK *)&AppTaskStartStk[0u],
(CPU_STK_SIZE )AppTaskStartStk[APP_CFG_TASK_START_STK_SIZE / 10u],
(CPU_STK_SIZE )APP_CFG_TASK_START_STK_SIZE,
(OS_MSG_QTY )0u,
(OS_TICK )0u,
(void *)0u,
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR),
(OS_ERR *)&err);
OSStart(&err); /* Start multitasking (i.e. give control to uC/OS-III). */
}
/*
*********************************************************************************************************
* STARTUP TASK
*
* Description : This is an example of a startup task. As mentioned in the book's text, you MUST
* initialize the ticker only once multitasking has started.
*
* Arguments : p_arg is the argument passed to 'AppTaskStart()' by 'OSTaskCreate()'.
*
* Returns : none
*
* Notes : 1) The first line of code is used to prevent a compiler warning because 'p_arg' is not
* used. The compiler should not generate any code for this statement.
*********************************************************************************************************
*/
static void AppTaskStart (void *p_arg)
{
CPU_INT32U cpu_clk_freq;
CPU_INT32U cnts;
OS_ERR err;
(void)p_arg;
BSP_Init();
CPU_Init(); /* Initialize the uC/CPU services */
cpu_clk_freq = BSP_CPU_ClkFreq(); /* Determine SysTick reference freq. */
cnts = cpu_clk_freq /* Determine nbr SysTick increments */
/ (CPU_INT32U)OSCfg_TickRate_Hz;
OS_CPU_SysTickInit(cnts); /* Init uC/OS periodic time src (SysTick). */
Mem_Init(); /* Initialize memory managment module */
Math_Init(); /* Initialize mathematical module */
#if OS_CFG_STAT_TASK_EN > 0u
OSStatTaskCPUUsageInit(&err); /* Compute CPU capacity with no task running */
#endif
#ifdef CPU_CFG_INT_DIS_MEAS_EN
CPU_IntDisMeasMaxCurReset();
#endif
#if (APP_CFG_SERIAL_EN == DEF_ENABLED)
App_SerialInit(); /* Initialize Serial communication for application ... */
#endif
OSTaskCreate((OS_TCB *)&AppTask1TCB, // 线程TCB
(CPU_CHAR *)APPTASK1NAME, // 线程名字
(OS_TASK_PTR ) AppTask1, // 线程入口函数
(void *) "TASK1", // 线程参数
(OS_PRIO ) APP_TASK1_PRIO, // 线程优先级
(CPU_STK *)&AppTask1Stk[0], // 线程栈起始地址
(CPU_STK_SIZE) APP_TASK1_STK_SIZE / 10, // 栈深度的限制位置
(CPU_STK_SIZE) APP_TASK1_STK_SIZE, // 栈大小
(OS_MSG_QTY ) 5u, // 最大的消息个数
(OS_TICK ) 0u, // 时间片
(void *) 0, // 向用户提供的内存位置的指针
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
(OS_ERR *)&err); // 错误标志
if(OS_ERR_NONE == err)
printf("%s Create Success\r\n",APPTASK1NAME);
else
printf("%s Create Error\r\n",APPTASK1NAME);
OSTaskCreate((OS_TCB *)&AppTask2TCB, // 线程TCB
(CPU_CHAR *)APPTASK2NAME, // 线程名字
(OS_TASK_PTR ) AppTask2, // 线程入口函数
(void *) "TASK2", // 线程参数
(OS_PRIO ) APP_TASK2_PRIO, // 线程优先级
(CPU_STK *)&AppTask2Stk[0], // 线程栈起始地址
(CPU_STK_SIZE) APP_TASK2_STK_SIZE / 10, // 栈深度的限制位置
(CPU_STK_SIZE) APP_TASK2_STK_SIZE, // 栈大小
(OS_MSG_QTY ) 5u, // 最大的消息个数
(OS_TICK ) 0u, // 时间片
(void *) 0, // 向用户提供的内存位置的指针
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
(OS_ERR *)&err); // 错误标志
if(OS_ERR_NONE == err)
printf("%s Create Success\r\n",APPTASK2NAME);
else
printf("%s Create Error\r\n",APPTASK2NAME);
OSTaskCreate((OS_TCB *)&AppTask3TCB, // 线程TCB
(CPU_CHAR *)APPTASK3NAME, // 线程名字
(OS_TASK_PTR ) AppTask3, // 线程入口函数
(void *) "TASK3", // 线程参数
(OS_PRIO ) APP_TASK3_PRIO, // 线程优先级
(CPU_STK *)&AppTask3Stk[0], // 线程栈起始地址
(CPU_STK_SIZE) APP_TASK3_STK_SIZE / 10, // 栈深度的限制位置
(CPU_STK_SIZE) APP_TASK3_STK_SIZE, // 栈大小
(OS_MSG_QTY ) 5u, // 最大的消息个数
(OS_TICK ) 0u, // 时间片
(void *) 0, // 向用户提供的内存位置的指针
(OS_OPT )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR), // 线程特定选项
(OS_ERR *)&err); // 错误标志
if(OS_ERR_NONE == err)
printf("%s Create Success\r\n",APPTASK3NAME);
else
printf("%s Create Error\r\n",APPTASK3NAME);
OSFlagCreate(&grp,"flag",0,&err);
if(OS_ERR_NONE == err)
printf("Flag Create Success\r\n");
else
printf("Flag Create Error\r\n");
OSTaskDel ( & AppTaskStartTCB, & err );
}
static void AppTask1 (void *p_arg)
{
OS_ERR err;
static CPU_INT32U i = 0;
while(DEF_TRUE)
{
OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err ); // 1s运行一次
OSFlagPost(&grp,EVENT1_FLAG | EVENT2_FLAG,OS_OPT_POST_FLAG_SET,&err); // 将事件1和事件2设置为置1触发
OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err ); // 1s运行一次
if(i % 2 == 0)
OSFlagPost(&grp,EVENT3_FLAG,OS_OPT_POST_FLAG_CLR,&err); // 将事件3设置为清0触发
else
OSFlagPost(&grp,EVENT4_FLAG,OS_OPT_POST_FLAG_CLR,&err); // 将事件4设置为清0触发
i++;
}
}
static void AppTask2 (void *p_arg)
{
OS_ERR err;
OS_FLAGS flag;
while(DEF_TRUE)
{
flag = OSFlagPend(&grp,EVENT1_FLAG | EVENT2_FLAG,0,OS_OPT_PEND_FLAG_SET_ALL | OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_BLOCKING,0,&err); // 同时接收事件1和事件2
if(OS_ERR_NONE == err)
printf("%s Flag Recv Success flag = %d\r\n",__func__,flag); // 接收成功打印出接收到事件值
else
printf("%s Flag Recv Error\r\n",__func__);
}
}
static void AppTask3 (void *p_arg)
{
OS_ERR err;
OS_FLAGS flag;
while(DEF_TRUE)
{
flag = OSFlagPend(&grp,EVENT3_FLAG | EVENT4_FLAG ,0,OS_OPT_PEND_FLAG_CLR_ANY | OS_OPT_PEND_FLAG_CONSUME | OS_OPT_PEND_BLOCKING,0,&err); // 接收事件3或者事件4
if(OS_ERR_NONE == err)
printf("%s Flag Recv Success flag = %d\r\n",__func__,flag); // 接收成功打印出接收到事件值
else
printf("%s Flag Recv Error\r\n",__func__);
}
}