当前位置: 首页 > news >正文

天津市建设公司网站中山古镇做网站

天津市建设公司网站,中山古镇做网站,网站做二级域名,wordpress 关键字 插件快速回顾 μC/OS-Ⅱ中的多任务 μC/OS-Ⅱ源码学习(1)---多任务系统的实现 μC/OS-Ⅱ源码学习(2)---多任务系统的实现(下) 本文开始,进入事件源码的学习。 事件模型 在一个多任务系统里,各个任务在系统的统筹下相继执行,由于执行速度极快&a…

快速回顾

μC/OS-Ⅱ中的多任务

μC/OS-Ⅱ源码学习(1)---多任务系统的实现

μC/OS-Ⅱ源码学习(2)---多任务系统的实现(下)

        本文开始,进入事件源码的学习。

事件模型

        在一个多任务系统里,各个任务在系统的统筹下相继执行,由于执行速度极快,就好像在一段时间内同时执行多个任务的代码一样,在更高级复杂的操作系统里,这叫做并发

        如果各个任务相互独立,没有资源的依赖和耦合,就可以凭借优先级的来决定先后执行的顺序,这是一种简单的多任务系统模型。但对于一块单片机来说,片上的资源(内存以及各种外设)是紧缺的,在完成需求的前提,可用的资源余量通常不多,这还只是平均余量,在复杂的应用场景下可能接近满载,此时各个任务就不能随心所欲的使用资源了,而是要按顺序依次排队等候使用(道理就是,即便空载也要保持这种编写习惯)。

        这种资源不仅是指硬件外设的使用,还体现在内存资源的使用上,一个简单的例子,当我们已经打开了某个文件时,若此时尝试在修改该文件的名称,会弹窗警示我们”该文件已被打开,请先关闭“。这是出于安全考虑,不希望多个进程同时对一个资源进行修改,而要有顺序地获取控制权。

        另一方面,各个任务之间还存在依赖关系,比如一个简单的热水器,包含ADC采样计算和PID逻辑输出两个任务(实际可能一个任务就行,这里仅作说明需要),那么后者一定会依赖前者提供实时数据进行新的运算,否则只能延续之前的输出。

        再比如一些任务,需要外设完成工作后产生中断,从而告知任务的运行(不能在中断内大量处理应用逻辑),这也是一种事件。

        从上面的各种案例场景分析,就知道需要各种各样的事件来协调大家的运行,才能在多任务环境下有条不紊的先后执行,减少应用出错的概率。在μC/OSⅡ中提供了五种不同的事件(EVENT)供用户使用(我归类为广义事件。另有系统定时器类型,但不归为事件):

//ucos_ii.h
#define  OS_EVENT_TYPE_UNUSED           0u
#define  OS_EVENT_TYPE_MBOX             1u   //邮箱
#define  OS_EVENT_TYPE_Q                2u   //队列
#define  OS_EVENT_TYPE_SEM              3u   //信号量
#define  OS_EVENT_TYPE_MUTEX            4u   //互斥信号量
#define  OS_EVENT_TYPE_FLAG             5u   //事件标志组
#define  OS_TMR_TYPE                  100u   //定时器

        事件有专门的事件控制块记录信息,其中邮箱(MBOX)队列(Q)信号量(SEM)互斥信号量(MUTEX)为狭义事件,其事件控制块类型为OS_EVENT,队列还有额外的控制块OS_Q事件标志组(FLAG)则是一类特殊的事件,有自己的控制块类型OS_FLAG_GRP

        它们分别装载在下面的全局变量中:

//ucos_ii.h
#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0u)
OS_EXT  OS_EVENT     *OSEventFreeList;            /* 空白事件控制块链表 */
OS_EXT  OS_EVENT      OSEventTbl[OS_MAX_EVENTS];  /* 事件控制块数组 */
#endif#if (OS_Q_EN > 0u) && (OS_MAX_QS > 0u)
OS_EXT  OS_Q             *OSQFreeList;              /* 空白队列控制块链表 */
OS_EXT  OS_Q              OSQTbl[OS_MAX_QS];        /* 队列控制块数组 */
#endif#if (OS_FLAG_EN > 0u) && (OS_MAX_FLAGS > 0u)
OS_EXT  OS_FLAG_GRP      OSFlagTbl[OS_MAX_FLAGS];   /* 事件标志组数组 */
OS_EXT  OS_FLAG_GRP     *OSFlagFreeList;            /* 空白的事件标志组链表  */
#endif

        由OS_EVENT_EN的定义也可以对事件进行分类了:

#define   OS_EVENT_EN   (((OS_Q_EN > 0u) && (OS_MAX_QS > 0u)) || (OS_MBOX_EN > 0u) || (OS_SEM_EN > 0u) || (OS_MUTEX_EN > 0u))

事件控制块类型

        从上一节描述可知,μC/OSⅡ共有三种事件控制块,分别是OS_EVENTOS_QOS_FLAG_GRP,其中OS_EVENT是用的最多的,这里先以它为例解读,后续讲到对应事件时再解析其它两种。

//ucos_ii.h
typedef struct os_event {INT8U    OSEventType;      /* 事件类型,有六种(其中一种是UNUSED) */void    *OSEventPtr;       /* OSEventPtr是一个多用途的指针,当作为链表时,可以指向下一个控制块;当作为具体的事件控制块时,指向具体的事件结构,如OS_Q */  INT16U   OSEventCnt;       /* 信号量计数器,其它事件类型不使用该成员 */OS_PRIO  OSEventGrp;       /* 等待信号的任务优先级组 */OS_PRIO  OSEventTbl[OS_EVENT_TBL_SIZE];  /* 等待信号的组内优先级 */#if OS_EVENT_NAME_EN > 0uINT8U   *OSEventName;      //事件名称
#endif
} OS_EVENT;

        其中,成员OSEventGrpOSEventTbl[OS_EVENT_TBL_SIZE]和多任务的就绪优先级逻辑类似,都是为了快速定位到最高优先级的就绪任务,为了之后对比和区分,之前多任务的部分我们称为”优先级就绪表“,在这里我们可以为其取名为”事件等待表“。

事件的初始化

        在执行OSInit()时,会对事件链表进行初始化,与任务控制块不同的是,事件链表为单相链表,具体函数为OS_InitEventList()

//os_core.c
static  void  OS_InitEventList (void)
{
#if (OS_EVENT_EN) && (OS_MAX_EVENTS > 0u)
#if (OS_MAX_EVENTS > 1u)INT16U     ix;INT16U     ix_next;OS_EVENT  *pevent1;OS_EVENT  *pevent2;OS_MemClr((INT8U *)&OSEventTbl[0], sizeof(OSEventTbl));  /* 清空事件控制块数组 */for (ix = 0u; ix < (OS_MAX_EVENTS - 1u); ix++) {    /* 将OSEventTbl数组元素组成链表 */ix_next = ix + 1u;pevent1 = &OSEventTbl[ix];pevent2 = &OSEventTbl[ix_next];pevent1->OSEventType    = OS_EVENT_TYPE_UNUSED;    //初始化事件类型为UNUSEDpevent1->OSEventPtr     = pevent2;
#if OS_EVENT_NAME_EN > 0upevent1->OSEventName    = (INT8U *)(void *)"?";     /* 初始化事件名称"?" */
#endif}pevent1                         = &OSEventTbl[ix];pevent1->OSEventType            = OS_EVENT_TYPE_UNUSED;pevent1->OSEventPtr             = (OS_EVENT *)0;     //链表尾的下一个指针指向0
#if OS_EVENT_NAME_EN > 0upevent1->OSEventName            = (INT8U *)(void *)"?"; /* Unknown name                            */
#endifOSEventFreeList                 = &OSEventTbl[0];   //将空白链表头指向刚创建的链表
#elseOSEventFreeList                 = &OSEventTbl[0];       /* 只定义一个事件时,则链表也只有一个元素 */OSEventFreeList->OSEventType    = OS_EVENT_TYPE_UNUSED;OSEventFreeList->OSEventPtr     = (OS_EVENT *)0;
#if OS_EVENT_NAME_EN > 0uOSEventFreeList->OSEventName    = (INT8U *)"?";        /* 初始化事件名称"?" */
#endif
#endif
#endif
}

         还有事件标志组的初始化函数OS_FlagInit(),其内容和OS_InitEventList()基本一致,只是操作对象变了:

//os_flag.c
void  OS_FlagInit (void)
{
#if OS_MAX_FLAGS == 1u    /* 只设定一个事件标志组,则只需将OSFlagTbl首元素当作链表头 */OSFlagFreeList                 = (OS_FLAG_GRP *)&OSFlagTbl[0];OSFlagFreeList->OSFlagType     = OS_EVENT_TYPE_UNUSED;    //事件类型初始化为UNUSEDOSFlagFreeList->OSFlagWaitList = (void *)0;OSFlagFreeList->OSFlagFlags    = (OS_FLAGS)0;
#if OS_FLAG_NAME_EN > 0uOSFlagFreeList->OSFlagName     = (INT8U *)"?";
#endif
#endif#if OS_MAX_FLAGS >= 2uINT16U        ix;INT16U        ix_next;OS_FLAG_GRP  *pgrp1;OS_FLAG_GRP  *pgrp2;OS_MemClr((INT8U *)&OSFlagTbl[0], sizeof(OSFlagTbl));      /* 清空事件标志组控制块 */for (ix = 0u; ix < (OS_MAX_FLAGS - 1u); ix++) {        /* 初始化控制块并组成链表结构 */ix_next = ix + 1u;pgrp1 = &OSFlagTbl[ix];pgrp2 = &OSFlagTbl[ix_next];pgrp1->OSFlagType     = OS_EVENT_TYPE_UNUSED;    //事件类型初始化为UNUSEDpgrp1->OSFlagWaitList = (void *)pgrp2;
#if OS_FLAG_NAME_EN > 0upgrp1->OSFlagName     = (INT8U *)(void *)"?";     /* 事件标志组名称 */
#endif}pgrp1                 = &OSFlagTbl[ix]; pgrp1->OSFlagType     = OS_EVENT_TYPE_UNUSED;pgrp1->OSFlagWaitList = (void *)0;      //最后一个元素的下一个指针指向0
#if OS_FLAG_NAME_EN > 0upgrp1->OSFlagName     = (INT8U *)(void *)"?";             
#endifOSFlagFreeList        = &OSFlagTbl[0];
#endif

         除此之外,还有队列控制块的初始化OS_QInit()

//os_q.c
void  OS_QInit (void)
{
#if OS_MAX_QS == 1u      /* 只设定一个队列时 */OSQFreeList         = &OSQTbl[0];          OSQFreeList->OSQPtr = (OS_Q *)0;
#endif#if OS_MAX_QS >= 2uINT16U   ix;INT16U   ix_next;OS_Q    *pq1;OS_Q    *pq2;OS_MemClr((INT8U *)&OSQTbl[0], sizeof(OSQTbl));  /* 清空队列控制块 */for (ix = 0u; ix < (OS_MAX_QS - 1u); ix++) {     /* 初始化队列控制块,并组成链表 */ix_next = ix + 1u;pq1 = &OSQTbl[ix];pq2 = &OSQTbl[ix_next];pq1->OSQPtr = pq2;}pq1         = &OSQTbl[ix];pq1->OSQPtr = (OS_Q *)0;OSQFreeList = &OSQTbl[0];
#endif
}

         接下来将具体解析各种事件的生命周期函数源码。

http://www.yayakq.cn/news/233161/

相关文章:

  • 做汽车导航仪在什么网站找客户高端开发网站哪家专业
  • 成都哪里有做网站的公司利于seo的网站设计
  • 柏乡网站建设廊坊app网站制作
  • 江苏建设工程招标网官方网站网站 手机 微信 app
  • 设计师常用网站微信网站登录
  • 宁波建设工程学校网站北京seo多少钱
  • 做网站放广告收益网站开发转行进入衍生领域
  • 型云网站建设科技局网站建设方案
  • 苏州园科生态建设集团网站做网站点击率怎么收钱
  • 东莞ppt免费模板下载网站鹤壁河南网站建设
  • 知名广州网站建设专业做网站优化排名
  • 咨询聊城网站建设如何在国内做网站
  • 平面设计专业网站wordpress评论链接
  • 汕头企业建站系统seo信息是什么
  • 天猫网站设计亚马逊关键词搜索工具
  • 做pc端网站哪家好游戏音效设计师培训
  • 安徽圣力建设集团网站国外云服务器哪个好
  • 营销型和展示型网站的区别设计类的网站
  • 商务网站开发公司免费网站app使用排名
  • 长春火车站哪个区自己做网站卖什么名字
  • 梧州门户网站开发一个棋牌app需要多少钱
  • 北京网站建设公司兴田德润电话wordpress 多标签筛选
  • 做起点说网站的服务器多少钱连云港市城乡建设管理局网站
  • 百度站内搜索软件工程的八个步骤
  • 做网站爬闪上海网页制作设计
  • 个人网站备案备注写什么制作个人网站教程
  • 泰安电脑网站建设电话win7 网站建设
  • php电子商务网站建设东莞网页设计师培训班
  • 深圳制作网站的公司哪家好电商seo名词解释
  • 网站建设合同书 简易可以做思维导图的网站