tag 标签: 软件定时器

相关博文
  • 热度 29
    2013-5-3 23:02
    3544 次阅读|
    0 个评论
       第六十章 UCOSII实验3-消息队列、信号量集和软件定时器   上一章,我们学习了UCOSII的信号量和邮箱的使用,本章,我们将学习消息队列、信号量集和软件定时器的使用。本章分为如下几个部分: 60.1 UCOSII消息队列、信号量集和软件定时器简介 60.2 硬件设计 60.3 软件设计 60.4 下载验证   60.1 UCOSII消息队列、信号量集和软件定时器简介 上一章,我们介绍了信号量和邮箱的使用,本章我们介绍比较复杂消息队列、信号量集以及软件定时器的使用。 消息队列 使用消息队列可以在任务之间传递多条消息。消息队列由三个部分组成:事件控制块、消息队列和消息。当把事件控制块成员OSEventType的值置为OS_EVENT_TYPE_Q时,该事件控制块描述的就是一个消息队列。 消息队列的数据结构如图60.1.1所示。从图中可以看到,消息队列相当于一个共用一个任务等待列表的消息邮箱数组,事件控制块成员OSEventPtr指向了一个叫做队列控制块(OS_Q)的结构,该结构管理了一个数组MsgTbl ;   //定时器控制块数组 OS_EXT OS_TMR *OSTmrFreeList;                             //空闲定时器控制块链表指针 OS_EXT OS_TMR_WHEEL OSTmrWheelTbl ;//定时器轮 其中OS_TMR为定时器控制块,定时器控制块是软件定时器管理的基本单元,包含软件定时器的名称、定时时间、在链表中的位置、使用状态、使用方式,以及到时回调函数及其参数等基本信息。 OSTmrTbl ;:以数组的形式静态分配定时器控制块所需的RAM空间,并存储所有已建立的定时器控制块,OS_TMR_CFG_MAX为最大软件定时器的个数。 OSTmrFreeLiSt:为空闲定时器控制块链表头指针。空闲态的定时器控制块(OS_TMR)中,OSTmrnext和OSTmrPrev两个指针分别指向空闲控制块的前一个和后一个,组织了空闲控制块双向链表。建立定时器时,从这个链表中搜索空闲定时器控制块。 OSTmrWheelTbl :该数组的每个元素都是已开启定时器的一个分组,元素中记录了指向该分组中第一个定时器控制块的指针,以及定时器控制块的个数。运行态的定时器控制块(OS_TMR)中,OSTmrnext和OSTmrPrev两个指针同样也组织了所在分组中定时器控制块的双向链表。软件定时器管理所需的数据结构示意图如图60.1.5所示:   图60.1.5 软件定时器管理所需的数据结构示意图 OS_TMR_CFG_WHEEL_SIZE定义了OSTmrWheelTbl的大小,同时这个值也是定时器分组的依据。按照定时器到时值与OS_TMR_CFG_WHEEL_SIZE相除的余数进行分组:不同余数的定时器放在不同分组中;相同余数的定时器处在同一组中,由双向链表连接。这样,余数值为0~OS_TMR_CFG_WHEEL_SIZE-1的不同定时器控制块,正好分别对应了数组元素OSTmr-WheelTbl ~OSTmrWheelTbl 的不同分组。每次时钟节拍到来时,时钟数OSTmrTime值加1,然后也进行求余操作,只有余数相同的那组定时器才有可能到时,所以只对该组定时器进行判断。这种方法比循环判断所有定时器更高效。随着时钟数的累加,处理的分组也由0~OS_TMR_CFG_WHE EL_SIZE-1循环。这里,我们推荐OS_TMR_CFG_WHEEL_SIZE的取值为2的N次方,以便采用移位操作计算余数,缩短处理时间。 信号量唤醒定时器管理任务,计算出当前所要处理的分组后,程序遍历该分组中的所有控制块,将当前OSTmrTime值与定时器控制块中的到时值(OSTmrMatch)相比较。若相等(即到时),则调用该定时器到时回调函数;若不相等,则判断该组中下一个定时器控制块。如此操作,直到该分组链表的结尾。软件定时器管理任务的流程如图60.1.6所示。   图60.1.6 软件定时器管理任务流程 当运行完软件定时器的到时处理函数之后,需要进行该定时器控制块在链表中的移除和再插入操作。插入前需要重新计算定时器下次到时时所处的分组。计算公式如下: 定时器下次到时的OSTmrTime值(OSTmrMatch)=定时器定时值+当前OSTmrTime值 新分组=定时器下次到时的OSTmrTime值(OSTmrMatch)%OS_TMR_CFG_WHEEL_SIZE 接下来我们看看在UCOSII中,与软件定时器相关的几个函数。 1)  创建软件定时器函数 创建软件定时器通过函数OSTmrCreate实现,该函数原型为:OS_TMR *OSTmrCreate (INT32U dly, INT32U period, INT8U opt, OS_TMR_CALLBACK callback,void  *callback_arg, INT8U *pname, INT8U *perr)。 dly,用于初始化定时时间,对单次定时(ONE-SHOT模式)的软件定时器来说,这就是该定时器的定时时间,而对于周期定时(PERIODIC模式)的软件定时器来说,这是该定时器第一次定时的时间,从第二次开始定时时间变为period。 period,在周期定时(PERIODIC模式),该值为软件定时器的周期溢出时间。 opt,用于设置软件定时器工作模式。可以设置的值为:OS_TMR_OPT_ONE_SHOT或OS_TMR_OPT_PERIODIC,如果设置为前者,说明是一个单次定时器;设置为后者则表示是周期定时器。 callback,为软件定时器的回调函数,当软件定时器的定时时间到达时,会调用该函数。 callback_arg,回调函数的参数。 pname,为软件定时器的名字。 perr,为错误信息。 软件定时器的回调函数有固定的格式,我们必须按照这个格式编写,软件定时器的回调函数格式为:void (*OS_TMR_CALLBACK)(void *ptmr, void *parg)。其中,函数名我们可以自己随意设置,而ptmr这个参数,软件定时器用来传递当前定时器的控制块指针,所以我们一般设置其类型为OS_TMR*类型,第二个参数(parg)为回调函数的参数,这个就可以根据自己需要设置了,你也可以不用,但是必须有这个参数。 2)  开启软件定时器函数 任务可以通过调用函数OSTmrStart开启某个软件定时器,该函数的原型为:BOOLEAN  OSTmrStart (OS_TMR *ptmr, INT8U *perr)。其中ptmr为要开启的软件定时器指针,perr为错误信息。 3)  停止软件定时器函数 任务可以通过调用函数OSTmrStop停止某个软件定时器,该函数的原型为:BOOLEAN  OSTmrStop (OS_TMR *ptmr,INT8U opt,void *callback_arg,INT8U *perr)。 其中ptmr为要停止的软件定时器指针。 opt为停止选项,可以设置的值及其对应的意义为:        OS_TMR_OPT_NONE,直接停止,不做任何其他处理        OS_TMR_OPT_CALLBACK,停止,用初始化的参数执行一次回调函数        OS_TMR_OPT_CALLBACK_ARG,停止,用新的参数执行一次回调函数            callback_arg,新的回调函数参数。            perr,错误信息。 软件定时器我们就介绍到这。 60.2 硬件设计 本节实验功能简介:本章我们在UCOSII里面创建7个任务:开始任务、LED任务、触摸屏任务、队列消息显示任务、信号量集任务、按键扫描任务和主任务,开始任务用于创建邮箱、消息队列、信号量集以及其他任务,之后挂起;触摸屏任务用于在屏幕上画图,测试CPU使用率;队列消息显示任务请求消息队列,在得到消息后显示收到的消息数据;信号量集任务用于测试信号量集,采用OS_FLAG_WAIT_SET_ANY的方法,任何按键按下(包括TPAD),该任务都会控制蜂鸣器发出“滴”的一声;按键扫描任务用于按键扫描,优先级最高,将得到的键值通过消息邮箱发送出去;主任务创建3个软件定时器(定时器1,100ms溢出一次,显示CPU和内存使用率;定时2,200ms溢出一次,在固定区域不停的显示不同颜色;定时3,,100ms溢出一次,用于自动发送消息到消息队列),并通过查询消息邮箱获得键值,根据键值执行DS1控制、控制软件定时器3的开关、触摸区域清屏、触摸屏校和软件定时器2的开关控制等。 所要用到的硬件资源如下: 1)  指示灯DS0 、DS1  2)  4个机械按键(KEY0/KEY1/KEY2/WK_UP) 3)  TPAD触摸按键 4)  蜂鸣器 5)  TFTLCD模块 这些,我们在前面的学习中都已经介绍过了。 60.3 软件设计 本章,我们在第四十三章实验 (实验38 )的基础上修改,首先,是UCOSII代码的添加,具体方法同第五十九章一模一样,本章就不再详细介绍了。本章OS_TICKS_PER_SEC的设置还是为500,即UCOSII的时钟节拍为2ms。另外由于我们创建了7个任务,加上统计任务、空闲任务和软件定时器任务,总共10个任务,如果你还想添加其他任务,请把OS_MAX_TASKS的值适当改大。 另外,我们还需要在os_cfg.h里面修改软件定时器管理部分的宏定义,修改如下: #define OS_TMR_EN                           1u         //使能软件定时器功能 #define OS_TMR_CFG_MAX                  16u       //最大软件定时器个数 #define OS_TMR_CFG_NAME_EN              1u        //使能软件定时器命名 #define OS_TMR_CFG_WHEEL_SIZE          8u        //软件定时器轮大小 #define OS_TMR_CFG_TICKS_PER_SEC       100u      //软件定时器的时钟节拍(10ms) #define OS_TASK_TMR_PRIO                        0u        //软件定时器的优先级,设置为最高     这样我们就使能UCOSII的软件定时器功能了,并且设置最大软件定时器个数为16,定时器轮大小为8,软件定时器时钟节拍为10ms(即定时器的最少溢出时间为10ms)。 最后,我们只需要修改test.c函数了,打开test.c,输入如下代码:  //省略部分内容!!!见附件。    
相关资源
  • 所需E币: 3
    时间: 2019-12-25 11:32
    大小: 205.99KB
    上传者: 二不过三
    在嵌入式前后台系统中,外部的异步事件通过中断来捕获,运行在后台。而其它的任务则运行于前台。提高系统中的任务处理能力,是嵌入式前后台系统设计的重点。本文描述了利用状态机来提高嵌入式前后台系统的任务处理能力的实现方法。……