FreeRTOS学习笔记7(定时器)

1、软件定时器的基本知识

        首先介绍一下软件定时任务创建函数,代码如下所示所示的函数:

 TimerHandle_t xTimerCreateStatic(        const char * const pcTimerName, 
                                          const TickType_t xTimerPeriodInTicks,
                                          const UBaseType_t uxAutoReload,
                                          void * const pvTimerID,
                                          TimerCallbackFunction_t pxCallbackFunction,
                                          StaticTimer_t * pxTimerBuffer )
/*  使用动态分配内存的方法创建定时器 
    * pcTimerName:定时器名字, 用处不大, 尽在调试时用到 
    * xTimerPeriodInTicks: 周期, 以Tick为单位 
    * uxAutoReload: 类型, pdTRUE表示自动加载, pdFALSE表示一次性
    * pvTimerID: 回调函数可以使用此参数, 比如分辨是哪个定时器
    * pxCallbackFunction: 回调函数 
    * 返回值: 成功则返回TimerHandle_t, 否则返回NULL */

        函数需要的入口参数中,最后一个入口参数就是回调函数,在定时时间到的时候,FreeRTOS内部创建的处理任务函数会调用这个回调函数。

        FreeRTOS中有一个Tick中断,软件定时器基于Tick来运行。在哪里执行定时器函数?第一印象就是在Tick中断里执行:      在Tick中断中判断定时器是否超时

                                                 如果超时了,调用它的回调函数

但是上面的运行思想是错的,FreeRTOS是RTOS,它不允许在内核、在中断中执行不确定的代码:如果定时器函数很耗时,会影响整 个系统。所以,FreeRTOS中,不在Tick中断中执行定时器函数。

        所以FreeRTOS中的Tick中断,在某个任务里执行,这个任务就是:RTOS Damemon Task RTOS 守护任务。以前被称 为"Timer server" ,但是这个任务要做并不仅仅是定时器相关,所以改名为: RTOS Damemon Task 。 当FreeRTOS 的配置项 configUSE_TIMERS 被设置为 1 时,在启动调度器时,会自动创建 RTOS Damemon Task。我们自己编写的任务函数要使用定时器时,是通过" 定时器命令队列 "(timer command queue) 和守护任 务交互,如下图所示:

        也就是用户对定时器函数的配置,都是通过队列传输给系统定义的prvTimerTask()任务函数,prvTimerTask()任务函数接收到队列中的数据之后,对应的做出相应的处理。

        这里需要注意的是,打开宏configUSE_TIMERS之后,创建的prvTimerTask()任务函数必必须指定其相应的优先级和队列大小、堆栈的大小。

        守护任务的优先级为:         confifigTIMER_TASK_PRIORITY
        定时器命令队列的长度为:  confifigTIMER_QUEUE_LENGTH。
用户程序调用、设置定时器函数的入口参数是有等待延时时间参数的,所以这个函数也是具有失败的可能的。

 2、守护任务函数

        守护任务的调度,跟普通的任务并无差别。当守护任务是当前优先级最高的就绪态任务时,它就可以运行。它的工作有两类: 处理命令:从命令队列里取出命令、处理执行定时器的回调函数,能否及时处理定时器的命令、能否及时执行定时器的回调函数,严重依赖于守护任务的优先级。

3、回调函数

定时器的回调函数的原型如下:

void ATimerCallback( TimerHandle_t xTimer );
        定时器的回调函数是在守护任务中被调用的,守护任务不是专为某个定时器服务的,它还要处理其他定 时器。 所以,定时器的回调函数不要影响其他人:
        1、回调函数要尽快实行,不能进入阻塞状态
        2、不要调用会导致阻塞的API函数,比如 vTaskDelay()
        3、可以调用 xQueueReceive() 之类的函数,但是超时时间要设为0:即刻返回,不可阻塞

 4、软件定时器的设置与使用

        设置主要是:创建、删除、启动、停止、复位、修改周期、设置定时器ID等。

        使用定时器之前,需要做一些配置,主要是头文件中宏定义的配置,如下图所示:

        配置使用定时器的时候出现xTimerTask()函数没有定义的情况,可能是以下几种原因:

1:相应的头文件没有引用,如果引用头文件的时候,发现有红色波浪线的报错,有可能是都应头文件的路径没有给。

2:xTimerTask()函数的裁剪宏定义没有开启,将这个部分裁剪了。

3:定时器的使能宏没有开启,导致的。

4:开启定时器的使能宏之后,会出现如下图所示的报错,这三个报错的意思就是:使能定时器之后,必须配置守护任务的优先级、命令队列的长度、守护任务栈的大小。

 

         软件定时器配置好之后,需要使用xTimerStart(TimerHandle1,0);函数开启定时器,不然是不能运行的。

        下面是软件定时器的使用demo,timer1是不循环的定时器,timer2是循环的定时器。

TimerHandle_t TimerHandle1;
TimerHandle_t TimerHandle2;


static void timer1Intterp(TimerHandle_t timer1)
{
	printf("timer1 is doing\r\n");
}


static void timer2Intterp(TimerHandle_t timer2)
{
	printf("timer2 is doing\r\n");
}


int main( void )
{
	prvSetupHardware();
	QueueUsart1=xQueueCreate(2,sizeof(int));
	QueueUsart2=xQueueCreate(2,sizeof(int));
	TimerHandle1=xTimerCreate("timer1",100,pdFALSE,0,timer1Intterp);
	TimerHandle2=xTimerCreate("timer2",100,pdTRUE,0,timer2Intterp);
	xTimerStart(TimerHandle1,0);
	xTimerStart(TimerHandle2,0);
	vTaskStartScheduler();
	return 0;
}

        下图是debug的调试结果:

 5、软件定时器消除抖动

        按键消除抖动多采用的方式有两种:

        ·       1、 连续读很多次,知道数值稳定:浪费CPU资源。
                2、使用定时器:要结合中断来使用。
大部分资源允许的情况下还是采用定时器的方式,节省cpu的资源。
这里给出软件定时器消除抖动的思想和操作:
        下面图是实现软件定时的流程图,主要就是利用按键的中断触发定时器的复位函数,使软件定时器不能计数结束引发定时器的中断。
        1:首先创建一个定时器20ms的不带重装计数初值的软件定时器。
        2:在外部中断函数中调用软件定时器的复位函数。
        3:在软件定时器的回调函数中读取按键的电平。

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值