uC/OS-III之事件标志组
来源:互联网 发布:在线淘宝网 编辑:程序博客网 时间:2024/05/29 04:37
1.当任务需要与多个事件的发生同步时,可以使用事件标志组。
等待多个事件时,任何一个事件发生,任务都被同步,这种同步机制称为“或”同步(逻辑“或运算”);
当所有事件都发生时,任务才被同步,这种同步机制被称为“与”同步(逻辑“与”运算)。
2.使用事件标志组前需要先配置事件标志组相关的宏定义,它们的定义位于os_cfg.h中
#define OS_CFG_FLAG_EN 1u // 事件标志组使能标志#define OS_CFG_FLAG_DEL_EN 1u // 包含函数OSFlagDel()的代码#define OS_CFG_FLAG_MODE_CLR_EN 1u // #define OS_CFG_FLAG_PEND_ABORT_EN 1u // 包含函数OSFlagPendAbort()的代码
3.事件标志组的使用
(1)当任务或ISR向事件标志组发布事件标志时,所有满足等待条件的任务都会进入就绪态。
(2)事件标志组的创建最好放在启动代码中,也就是main函数中。
(3)事件标志通常有两种用途:状态信息监控和瞬时事件监控。
状态信息监控一般通过非阻塞调用来监控相关的事件标志;瞬时事件监控则是通过阻塞等待的方式来实现。
4.事件标志组的类型为OS_FLAG_GRP,它的定义位于os.h中
typedef struct os_flag_grp OS_FLAG_GRP; // 617行struct os_flag_grp { // 742行 - 753行,事件标志组 OS_OBJ_TYPE Type; // 类型必须设置成OS_OBJ_TYPE_FLAG CPU_CHAR *NamePtr; // 名称 OS_PEND_LIST PendList; // 挂起标#if OS_CFG_DBG_EN > 0u // 调试相关 OS_FLAG_GRP *DbgPrevPtr; OS_FLAG_GRP *DbgNextPtr; CPU_CHAR *DbgNamePtr;#endif OS_FLAGS Flags; // 事件标志 CPU_TS TS; // 最近一次发布事件标志的时间戳};
5.事件标志组的创建使用函数OSTaskCreate(),它的定义位于os_flag.c中。
void OSFlagCreate (OS_FLAG_GRP *p_grp, // 69行 - 120行,事件标志组的地址 CPU_CHAR *p_name, // 名称 OS_FLAGS flags, // 标志初始值 OS_ERR *p_err) // 返回的错误码{ CPU_SR_ALLOC(); // 声明变量cpu_sr,用来临时存储CPU的状态寄存器#ifdef OS_SAFETY_CRITICAL // 允许进行系统安全性检查 if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return; }#endif#ifdef OS_SAFETY_CRITICAL_IEC61508 // 允许进行系统安全性检查--IEC61508 if (OSSafetyCriticalStartFlag == DEF_TRUE) { *p_err = OS_ERR_ILLEGAL_CREATE_RUN_TIME; return; }#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u // 允许进行ISR调用检查 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { // 查看是否是在ISR中调用该函数 *p_err = OS_ERR_CREATE_ISR; // 不能再ISR中创建 return; }#endif#if OS_CFG_ARG_CHK_EN > 0u // 允许进行参数检查 if (p_grp == (OS_FLAG_GRP *)0) { // 无效的事件标志组 *p_err = OS_ERR_OBJ_PTR_NULL; return; }#endif OS_CRITICAL_ENTER(); // 进入临界区 p_grp->Type = OS_OBJ_TYPE_FLAG; // 设置类型为OS_OBJ_TYPE_FLAG p_grp->NamePtr = p_name; p_grp->Flags = flags; // 设置事件标志初始值 p_grp->TS = (CPU_TS)0; OS_PendListInit(&p_grp->PendList); // 创建挂起表#if OS_CFG_DBG_EN > 0u // 调试相关 OS_FlagDbgListAdd(p_grp);#endif OSFlagQty++; // 系统事件标志组的数目加1 OS_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_NONE;}
6.等待事件标志组使用OSFlagPend(),它的定义位于os_flag.c中。
OS_FLAGS OSFlagPend (OS_FLAG_GRP *p_grp, // 313行 - 585行 OS_FLAGS flags, // 等待的标志 OS_TICK timeout, // 超时时间 OS_OPT opt, // 等待选项 CPU_TS *p_ts, // 返回的时间戳 OS_ERR *p_err) // 返回的调用结果{ CPU_BOOLEAN consume; OS_FLAGS flags_rdy; OS_OPT mode; OS_PEND_DATA pend_data; CPU_SR_ALLOC(); // 声明变量cpu_sr,用来临时存储CPU的状态寄存器#ifdef OS_SAFETY_CRITICAL // 允许进行系统安全性检查 if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return ((OS_FLAGS)0); }#endif#if OS_CFG_CALLED_FROM_ISR_CHK_EN > 0u // 允许进行ISR调用检查 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { // 查看是否在ISR中调用该函数 *p_err = OS_ERR_PEND_ISR; // 不能在ISR中调用 return ((OS_FLAGS)0); }#endif#if OS_CFG_ARG_CHK_EN > 0u // 允许进行参数检查 if (p_grp == (OS_FLAG_GRP *)0) { // 无效的参数 *p_err = OS_ERR_OBJ_PTR_NULL; return ((OS_FLAGS)0); }#endif#if OS_CFG_OBJ_TYPE_CHK_EN > 0u // 允许进行对象类型检查 if (p_grp->Type != OS_OBJ_TYPE_FLAG) { // 无效的指向 *p_err = OS_ERR_OBJ_TYPE; return ((OS_FLAGS)0); }#endif if ((opt & OS_OPT_PEND_FLAG_CONSUME) != (OS_OPT)0) { // 查看我们是否需要消耗标志 consume = DEF_TRUE; } else { consume = DEF_FALSE; } if (p_ts != (CPU_TS *)0) { *p_ts = (CPU_TS)0; // 初始化要返回的时间戳 } mode = opt & OS_OPT_PEND_FLAG_MASK; CPU_CRITICAL_ENTER(); // 进入临界区 switch (mode) { case OS_OPT_PEND_FLAG_SET_ALL: // 所有的标志置位 flags_rdy = (OS_FLAGS)(p_grp->Flags & flags); // 提取出需要事件标志 if (flags_rdy == flags) { // 所有的事件都已发生 if (consume == DEF_TRUE) { // 查看是否需要消耗掉这些标志 p_grp->Flags &= ~flags_rdy; // 仅仅清理掉那些我们需要的位 } OSTCBCurPtr->FlagsRdy = flags_rdy; // 保存已经准备就绪的位 if (p_ts != (CPU_TS *)0) { *p_ts = p_grp->TS; } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_NONE; return (flags_rdy); } else { // 所有的事件没有全部发生 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { // 不挂起任务 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_PEND_WOULD_BLOCK; return ((OS_FLAGS)0); } else { // 挂起任务 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { // 查看调度器是否已锁定 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_SCHED_LOCKED; return ((OS_FLAGS)0); } } OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); // 进入临界区,使能中断 OS_FlagBlock(&pend_data, // 将任务挂起 p_grp, flags, opt, timeout); OS_CRITICAL_EXIT_NO_SCHED(); // 退出临界区,不调度 } break; case OS_OPT_PEND_FLAG_SET_ANY: // 任意一个标志置位 flags_rdy = (OS_FLAGS)(p_grp->Flags & flags); // 提取需要的事件标志 if (flags_rdy != (OS_FLAGS)0) { // 有事件发生 if (consume == DEF_TRUE) { // 是否需要消耗掉这些位 p_grp->Flags &= ~flags_rdy; // 清空掉这些标志 } OSTCBCurPtr->FlagsRdy = flags_rdy; // 保存已发生的事件标志 if (p_ts != (CPU_TS *)0) { *p_ts = p_grp->TS; } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_NONE; return (flags_rdy); } else { // 没有任何事件发生 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { // 不挂起 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_PEND_WOULD_BLOCK; return ((OS_FLAGS)0); } else { // 挂起 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { // 查看任务调度器是否锁定 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_SCHED_LOCKED; return ((OS_FLAGS)0); } } OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); // 进入临界区,使能中断 OS_FlagBlock(&pend_data, p_grp, flags, opt, timeout); OS_CRITICAL_EXIT_NO_SCHED(); // 退出临界区,不调度 } break;#if OS_CFG_FLAG_MODE_CLR_EN > 0u case OS_OPT_PEND_FLAG_CLR_ALL: // 所有的标志清零 flags_rdy = (OS_FLAGS)(~p_grp->Flags & flags); // 提取需要的事件标志位 if (flags_rdy == flags) { // 所有的事件都已发生 if (consume == DEF_TRUE) { // 查看是否需要消耗这些事件标志位 p_grp->Flags |= flags_rdy; // 仅仅设置需要的事件标志位 } OSTCBCurPtr->FlagsRdy = flags_rdy; // 保存这些事件标志位 if (p_ts != (CPU_TS *)0) { *p_ts = p_grp->TS; } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_NONE; return (flags_rdy); } else { // 所有事件未全部发生 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { // 不挂起 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_PEND_WOULD_BLOCK; return ((OS_FLAGS)0); } else { // 挂起 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { // 查看调度器是否锁定 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_SCHED_LOCKED; return ((OS_FLAGS)0); } } OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); // 进入临界区,使能中断 OS_FlagBlock(&pend_data, // 挂起任务 p_grp, flags, opt, timeout); OS_CRITICAL_EXIT_NO_SCHED(); // 退出临界区,不调度 } break; case OS_OPT_PEND_FLAG_CLR_ANY: // 某一个标志清零 flags_rdy = (OS_FLAGS)(~p_grp->Flags & flags); // 提取出需要的事件标志位 if (flags_rdy != (OS_FLAGS)0) { // 有事件发生 if (consume == DEF_TRUE) { // 查看是否需要消耗掉这些标志位 p_grp->Flags |= flags_rdy; // 仅仅设置需要的标志位 } OSTCBCurPtr->FlagsRdy = flags_rdy; // 保存事件标志位 if (p_ts != (CPU_TS *)0) { *p_ts = p_grp->TS; } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_NONE; return (flags_rdy); } else { // 没有任何事情发生 if ((opt & OS_OPT_PEND_NON_BLOCKING) != (OS_OPT)0) { // 不挂起 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_PEND_WOULD_BLOCK; return ((OS_FLAGS)0); } else { // 挂起 if (OSSchedLockNestingCtr > (OS_NESTING_CTR)0) { // 查看调度器是否锁定 CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_SCHED_LOCKED; return ((OS_FLAGS)0); } } OS_CRITICAL_ENTER_CPU_CRITICAL_EXIT(); // 进入临界区,使能中断 OS_FlagBlock(&pend_data, // 挂起任务 p_grp, flags, opt, timeout); OS_CRITICAL_EXIT_NO_SCHED(); // 退出临界区,不调度 } break;#endif default: CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_OPT_INVALID; return ((OS_FLAGS)0); } OSSched(); // 执行调度程序 CPU_CRITICAL_ENTER(); // 进入临界区 switch (OSTCBCurPtr->PendStatus) { case OS_STATUS_PEND_OK: // 目标事件标志位被置位(清零) if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } *p_err = OS_ERR_NONE; break; case OS_STATUS_PEND_ABORT: // 等待操作被其他任务取消了 if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_PEND_ABORT; return ((OS_FLAGS)0); case OS_STATUS_PEND_TIMEOUT: // 等待超时 if (p_ts != (CPU_TS *)0) { *p_ts = (CPU_TS )0; } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_TIMEOUT; return ((OS_FLAGS)0); case OS_STATUS_PEND_DEL: // 事件标志组被删除了 if (p_ts != (CPU_TS *)0) { *p_ts = OSTCBCurPtr->TS; } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_OBJ_DEL; return ((OS_FLAGS)0); default: CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_STATUS_INVALID; return ((OS_FLAGS)0); } flags_rdy = OSTCBCurPtr->FlagsRdy; if (consume == DEF_TRUE) { // 查看是否需要消耗掉这些标志 switch (mode) { case OS_OPT_PEND_FLAG_SET_ALL: case OS_OPT_PEND_FLAG_SET_ANY: // 清空事件标志位 p_grp->Flags &= ~flags_rdy; break;#if OS_CFG_FLAG_MODE_CLR_EN > 0u case OS_OPT_PEND_FLAG_CLR_ALL: case OS_OPT_PEND_FLAG_CLR_ANY: // 置位事件标志位 p_grp->Flags |= flags_rdy; break;#endif default: CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_OPT_INVALID; return ((OS_FLAGS)0); } } CPU_CRITICAL_EXIT(); // 退出临界区 *p_err = OS_ERR_NONE; return (flags_rdy);}
6.发送事件标志组使用OSFlagPost(),它的定义位于os_flag.c中。
OS_FLAGS OSFlagPost (OS_FLAG_GRP *p_grp, // 790行 - 856行 OS_FLAGS flags, // 事件标志 OS_OPT opt, // 事件标志的选项 OS_ERR *p_err) // 调用的结果{ OS_FLAGS flags_cur; CPU_TS ts;#ifdef OS_SAFETY_CRITICAL // 允许执行系统安全性检查 if (p_err == (OS_ERR *)0) { OS_SAFETY_CRITICAL_EXCEPTION(); return ((OS_FLAGS)0); }#endif#if OS_CFG_ARG_CHK_EN > 0u // 允许进行参数检查 if (p_grp == (OS_FLAG_GRP *)0) { // 检查p_grp *p_err = OS_ERR_OBJ_PTR_NULL; return ((OS_FLAGS)0); } switch (opt) { // 检查opt case OS_OPT_POST_FLAG_SET: case OS_OPT_POST_FLAG_CLR: case OS_OPT_POST_FLAG_SET | OS_OPT_POST_NO_SCHED: case OS_OPT_POST_FLAG_CLR | OS_OPT_POST_NO_SCHED: break; default: *p_err = OS_ERR_OPT_INVALID; return ((OS_FLAGS)0); }#endif#if OS_CFG_OBJ_TYPE_CHK_EN > 0u // 允许进行对象类型检查 if (p_grp->Type != OS_OBJ_TYPE_FLAG) { // 确保是事件标志组 *p_err = OS_ERR_OBJ_TYPE; return ((OS_FLAGS)0); }#endif ts = OS_TS_GET(); // 获取时间戳#if OS_CFG_ISR_POST_DEFERRED_EN > 0u // 延时发布模式 if (OSIntNestingCtr > (OS_NESTING_CTR)0) { // 查看是否是在ISR中调用 OS_IntQPost((OS_OBJ_TYPE)OS_OBJ_TYPE_FLAG, // 发布到ISR队列中 (void *)p_grp, (void *)0, (OS_MSG_SIZE)0, (OS_FLAGS )flags, (OS_OPT )opt, (CPU_TS )ts, (OS_ERR *)p_err); return ((OS_FLAGS)0); }#endif flags_cur = OS_FlagPost(p_grp, // 发布事件标志组 flags, opt, ts, p_err); return (flags_cur);}
阅读全文
0 0
- uC/OS-III之事件标志组
- uC/OS事件标志组(event flag)
- uC/OS事件标志组(event flag
- UC/OS II 事件标志组管理(一)
- UC/OS II 事件标志组管理(二)
- uC/OS-III之资源管理
- uC/OS-III之信号量
- uc/os-iii学习笔记-任务同步(信号量、时间标志组)
- uC/OS-III之系统内部任务
- uC/OS-III之任务调度总结
- uC/OS-III之中断管理总结
- uC/OS-III之学习总结
- uC/OS-III之时钟节拍列表
- uC/OS-III之时间管理
- uC/OS-III之定时器管理
- uC/OS-III之资源管理--互斥型信号量
- uC/OS-III之任务挂起表
- uC/OS-III之任务同步
- VS断点信息无法输出到调试窗口
- 进程的用户栈和内核栈
- webpack入门笔记(一)——漫漫踩坑路
- 赵哲焕 Clock work RNN(CW-RNN)
- MySQL5.7 基于GTID的多源复制
- uC/OS-III之事件标志组
- 输入一个日期,得到这个月的最后一天
- Map排序(java)
- Windows Server 2012 R2 或 2016 无法安装 .NET Framework 3.5.1
- 硬解码软解码
- CString使用(多线程、线程安全)
- java IO流 详解
- Xcode原生项目集成Unity导出的工程
- 不用加减乘除做加法(java版)