datasheet

VxWorks几种常用的延时方法

2008-05-16来源: 单片机及嵌入式系统应用 关键字:taskDelay  函数  VxWorks  基准频率  实时嵌入式系统  sysTim

  嵌入式系统中,一个任务往往需要在特定的延时之后执行一个指定的动作,比如等待外设以确保数据可靠,控制扬声器发声时间以及串口通信超时重发等。这就需要利用定时器机制来计量特定长度的时间段。VnWorks作为实时嵌入式系统,提供多样的定时接口函数。下面列举一些常用的定时方式,并说明其注意事项。

  1 taskDelav

  taskDelay(n)使调用该函数的任务延时n个tick(内核时钟周期)。该任务在指定的时间内主动放弃CPU,除了taskDelay(0)专用于任务调度(将CPU交给同一优先级的其他任务)外,任务延时也常用于等待某一外部事件,作为一种定时/延时机制。在没有中断触发时,taskDelay能很方便地实现,且不影响系统整体性能。例如写数据至EEPROM,EEPROM需要一个内部擦除时间(最大擦除时间为lOms)。以下所提及的一个tick都假设为16.67 ms(1/60 s)。可以简单地调用taskDelay(2)来保证数据擦写完成。按理说taskDelay(1)就足以保证,为什么需要taskDelay(2)呢?

  这正是taskDelay使用的一个缺陷,使用时需要注意。taskDelay(n)表示任务延时至第n个系统时钟到来的时刻,如图1所示。如果在A时刻调用taskDelay(1)仅延时5 ms,则在B时刻taskDelay(1)就刚好是一个tick周期。可见需要10 ms的延时就必须调用taskDelay(2)才能实现。taskDelay有接近一1个tick的误差存在,taskDelay(n)实际上是延时(n-1)tick~n tick的时间。延时精度为l/n,延时1s就是taskDelay(60)的误差极限为1.6%,而taskDelay(1)的误差极限将是100%。

  使用taskDelay需注意的另外一点是:即使经过n个tick,调用延时的任务也不保证返回执行状态,可能有更高或相同优先级的任务占用了CPU。

  2 WatchDog

  VxWorks提供了一种通用的看门狗定时器机制。利用提供的函数,任何任务都可以创建一个看门狗定时器,经过指定的延时后,实现在系统时钟ISR的上下文中运行指定的程序。需要注意的是,看门狗定时触发的程序是在中断级别上执行,而不是在任务的上下文中。因此,看门狗定时挂接的程序编写有一定的限制,这个限制条件与中断服务程序的约束是一样的。比如,不能使用获取信号量的语句,以及像printf()这样的I/O系统函数。

  通过wdCreate()可以创建一个看门狗定时器。调用wdStart()启动定时器,延时参数同taskDelay一样以tick为单位,同时还须指定定时完成后要调用的程序。如果应用程序同时需要多个看门狗函数,则应使用wdCreate()产生多个独立的看门狗ID。因为对于给定的看门狗ID,通过wdStart()只能关联一个看门狗函数。在指定的tick计数到达之前,要取消一个看门狗计时器,可以通过调用wdCancel()实现。每调用一次wdStart(),看门狗定时器只执行一次,因此对于一些要求周期性执行的应用程序,要获得该效果,则定时器函数本身必须通过递归调用wdStart()来重新启动定时器。

  如果利用看门狗定时器实现延时,则存在与taskDelay一样的精度上的缺陷,以tick为基准.并且看门狗关联的函数所受的限制很大,这也是使用不便的一个方面。不过启动看门狗的任务不会被阻塞,因为wdStart()调用立即返回并继续执行。

  3 sleep/nanosleep

  sleep()和nanosleep()是VxWorks提供的延时函数接口。sleep以s为单位,nanosleep可以提供更精确的延时;传参是时钟的结构体,参数可以精确到ns,但实际上只能做到大于或等于这个时问。因为skep或nanosleep函数延时的时间基准仍是tick,调用此函数的任务处于任务延时状态,这点与taskDelay()一致。不同的地方是,taskDelay()是用于任务调度,taskDelay(O)有其自身的含义,而sleep(O)则是没有意义的。前面提过,taskDelay(n)延时时间为(n-1)tick~ntick,而sleep/nanosleep则保证实际延时时间大于或等于设定的时间参数。这一点可以通过编写一个测试程序试验证明。代码如下:

  

  4 高精度时钟sysTimeStamp

  sysTimeStamp()也称“时间戳”。是通过系统时钟实现的。刚开始也觉得费解,系统时钟的定时周期就是tick,怎么实现高精度时钟呢?通过读BSP底层代码发现,sysTimeStamp其实是通过读取该定时器的当前计数值来获取高精度定时的。通过sysTimestampFreq()函数可以得到系统时间戳的频率,它往往反映的是CPU定时器的基准频率。当然,如此高的分辨率只能是一个理想值,不同的系统不一定都能实现。毕竟该时间戳的实现方式有一个致命的弱点:通过查询方式。系统时钟定时中断是以ticb:为单位的,进一步提高分辨率读取定时器计数值(CPU的一个特殊功能寄存器),只能是查询方式实现。代码示例如下:

  

  这种定时方式比较占用系统资源,且只适用于短时间的定时,但是实现方便。为确保定时准确,应在锁定中断情况下调用sysTimestamp;否则,应考虑使用sysTimes-tampLock函数。

  5 辅助时钟

  辅助时钟是利用目标板上CPU的另一个定时器(除了系统时钟之外)中断实现的。它可以灵活配置实现高分辨率的定时,而且容易实现ms级甚至μs级定时。VxWorks提供了一系列与系统时钟相同的操作接口,用户可以方便地挂接自己的中断处理函数,时钟分辨率的高低取决于硬件定时器的精度和用户中断函数的长短。要将辅助时钟作为精确的延时机制(如ms级延时),可以通过这种方式实现。初始化程序先调用SysAuxClkRateSet()函数设置辅助时钟中断周期为1ms(一般在contig.h文件中AUX_CLK_RATE_MIN和AUX_CLK_RATE_MAX之间,对中断频率作了限定,如果需要可以对此宏定义修改),再通过ysAuxClkConneet()?将用户处理函数连接到辅助时钟中断上,用户处理函数可以为SemGive(semTimer)释放一个同步信号量。编写一个msDelay(intms)作为其他任务调用接口,函数代码如下:

  

  这种方式能实现十分精确的定时,调用延时的任务处于任务阻塞状态。但是使用上仍存在缺陷,不能实现多个任务同时调用,且需要CPU的一个时钟资源,如果没有多余的时钟,那么这一方法就不能实现。

  另外还需要注意一点:Tornado的调试工具Browser一>SpyChart的实现原理是利用辅助定时器产生中断,并记录当前被中断的任务,由抽样数据反映各任务CPU占用率的情况。因此如果调试程序中使用了辅助定时器,那么使用Spy Chart时定时处理函数会被重新挂接,原有定时挂接的程序将得不到进行。反之,如果在Spy Chart运行之后挂接辅助定时处理函数,那么Spy Chart的运行将出现问题。实验发现,运行Spy Chart后重新挂接辅助定时处理函数,Spy Chart即使选中自动刷新,各任务状态也不会更新,如图2所示。

  

  VxWorks提供的定时接口(不一定专门用于定时,也可间接实现)远不只这些。具体使用哪种方式,应根据其精度、资源状态和优先级要求而定。

关键字:taskDelay  函数  VxWorks  基准频率  实时嵌入式系统  sysTim

编辑:孙树宾 引用地址:http://www.eeworld.com.cn/afdz/2008/0516/article_658.html
本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:USB闪存盘驱动器与PIC微控制器的接口设计
下一篇:基于ZigBee的无线串口集线器的研究与设计

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

VxWorks几种常用的延时方法

做到大于或等于这个时问。因为skep或nanosleep函数延时的时间基准仍是tick,调用此函数的任务处于任务延时状态,这点与taskDelay()一致。不同的地方是,taskDelay()是用于任务调度,taskDelay(O)有其自身的含义,而sleep(O)则是没有意义的。前面提过,taskDelay(n)延时时间为(n-1)tick~ntick,而sleep/nanosleep则保证实际延时时间大于或等于设定的时间参数。这一点可以通过编写一个测试程序试验证明。代码如下:      4 高精度时钟sysTimeStamp   sysTimeStamp()也称“时间戳”。是通过系统时钟实现的。刚开始也觉得费解
发表于 2008-05-16

stm32外部中断常用库函数

void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource); //确定端口与中断线映射关系 void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct); //初始化中断线,触发方式typedef struct{  uint32_t EXTI_Line; //指定要配置的中断线     EXTIMode_TypeDef EXTI_Mode; //模式:事件or中断          EXTITrigg
发表于 2018-12-03

STM32共用中断和共用中断函数的判断

STM32外部中断查询: 15-10线的外部中断共用一个中断函数,怎么在该函数里查询是哪个中断线产生了中断呢?使用 EXTI_GetITStatus()来查询哪根线产生了中断。 比如EXTI_GetITStatus(EXTI_Line13)就是查询13线是否产生了中断的。 还有 :当初你在设置中断引脚的时候都是不能把PB1和PD1同时设置为中断源的。如果非要设置,后面设置的会把前面的覆盖掉的。编写中断服务函数经常需要使用两个函数。 第一个是判断某个中断线上的中断是否发生(即标志位是否置位): ITStatus EXTI_GetITStatus(uint32_t EXTI_line
发表于 2018-12-03

STM32中断函数名

和普通的ARm裸板开发不同。使用stm32库函数编程时,中断函数名是固定死的。 具体函数名可以在启动文件startup_stm32fxxx_xd.s的Vector Table Mapped(中断函数向量表)中查看。 启动文件 startup_stm32fxxx_xd.s里面都是汇编代码 ; Vector Table Mapped to Address 0 at Reset                AREA    RESET, DATA, READONLY     
发表于 2018-12-03

STM32F429之中断服务函数名

以下内容在startup_stm32f429_439xx.s文件内;******************** (C) COPYRIGHT 2015 STMicroelectronics ********************;* File Name          : startup_stm32f429_439xx.s;* Author             : MCD Application Team;* @version           :
发表于 2018-12-03

STM32 关于外部中断线、中断源和中断服务函数的问题

中断线问题:上图可以看出,PA0、PB0...PG0共用的EXTI0中断线,PA1、PB2...PG1共用的EXTI1中断线,也就是 编程里面的(如下图库文件),对应16个中断线,后面三个是专用的中断线,不做讨论。 有人要问,假设:我设置的引脚是PB9和PE9都开启外部中断怎么办?小编告诉你,这还真办不了,我实测过。配置函数的时候后覆盖之前的函数的(如下图所示)如果这样配置的话,会出现出货光电1的初始化覆盖掉编码盘的初始化,说白了就是编码盘的设置被覆盖掉了,结果是外部中断  出货光电1管脚会触发而编码盘就不起作用了,这也是STM32其中一个问题所在吧! 反过来,结果是外部中断  编码盘 管脚会触发
发表于 2018-12-03
STM32 关于外部中断线、中断源和中断服务函数的问题

小广播

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 视频监控 智能卡 防盗报警 智能管理 处理器 传感器 其他技术 综合资讯 安防论坛

北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2018 EEWORLD.com.cn, Inc. All rights reserved
pt type="text/javascript" src="//v3.jiathis.com/code/jia.js?uid=2113614" charset="utf-8">