600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > FreeRTOS软件定时器

FreeRTOS软件定时器

时间:2019-04-06 20:28:09

相关推荐

FreeRTOS软件定时器

1.硬件定时器与软件定时器

在MCU中有硬件定时器,由外部晶振提供时钟输入源,经过时钟模块寄存器的配置,得到中断时间,一般都是中断模式触发时间中断,在中断服务函数中设置中断操作。硬件中断时间很精准,最小能到ns级别。缺点是在MCU的外设中一般timer的数量是很少的,有限的。

而软件定时器事项功能和硬件定时器的功能是一样的,都是定时操作执行对应的服务,区别是软件定时器定时到了后执行的是回调函数,且在回调函数中不能执行阻塞任务的操作,如vTaskDelay()等。

2.软件定时器的任务

在FreeRTOS中,可以创建多个软件定时器,所有的软件定时器回调函数都执行在软件定时器任务上下文环境中。软件定时器任务在调度器启动时由内核自动创建,它是一个标准的FreeRTOS任务。当调用vTaskStartScheduler()来开启调度器后,这个函数内部使用xTimerCreateTimerTask()来创建软件定时器任务。

软件定时器任务的任务优先级和栈深度是在FreeRTOSConfig.h中通过configTIMER_TASK_PRIORITY和configTIMER_TASK_STACK_DEPTH这两个宏配置的。

3.软件定时器的属性

1)单次触发定时器:计数值到达后调用一次回调函数,然后定时器任务阻塞;

自动加载定时器:计数值到达后调用一次回调函数,然后循环计数触发回调函数。

2)定时器的精度:

定时器的时间精度是一系统时钟节拍为计时单位的,即心跳节拍,一般为systick,配置为configTICK_RATE_HZ,如1000,那么1s条1000次,即1次1ms.软件定时器设置的节拍数必须是这个sysTick的整数倍。系统节拍越小,精度越高,那么进入中断的次数就会越多,上下文切换就会很频繁,系统开销就会很大;系统节拍越大,时钟精度低,系统开销低。

3)软件定时器的状态:

休眠状态:休眠状态时,定时器是存在的,可以通过它的句柄来操作它,但是它没有运行,没有计时,所以它的回调函数不会执行运行状态:定时器正在计时,包括正在执行它的回调函数

如下图所示,单次触发定时器和自动重装定时器主要的区别在于,当定时到期后,自动重装定时器会执行回调函数并再次进入到运行态,而单次触发定时器则会执行回调函数并进入到休眠状态

4.软件定时器的应用场景

在实际中,需要用到定时器任务,硬件定时器受硬件资源数量的限制,无法提供更多的定时器,那么这时候可以用软件定时器任务来替代硬件定时器的任务。但需要注意的是软件定时器的精度是无法和硬件定时器的精度相比的,因为软件定时器的任务可能被中断以及优先级更高的任务所打断,因为软件定时器本质也是任务,既然是任务就会存在被中断打断的可能。所以软件定时器是用于对时间精度要求不高的任务,做一些辅助性的任务。

5.demo分析

#include "APPTaskDef.h"#include "led.h"#include "delay.h"#include "key.h"#include "timers.h"#define START_TASK_PRIO1#define START_STACK_SIZE128TaskHandle_t startTask_handler; //开始任务句柄static void start_task(void *param);#defineCONTROL_TIMER_TASK_PRIO2#defineCONTROL_TIMER_STACK_SIZE128TaskHandle_tcontrolTimerTask_handler; //控制timer任务句柄static void control_timer_task(void *param);void periodTimer(TimerHandle_t xTimer);void oneShotTimer(TimerHandle_t xTimer);TimerHandle_tperiodTimerHandle;TimerHandle_toneshotTimerHandle;void APP_task(void){xTaskCreate((TaskFunction_t)start_task,(const char *)"start_task",(uint16_t)START_STACK_SIZE,NULL,(UBaseType_t)START_TASK_PRIO,(TaskHandle_t *)&startTask_handler);vTaskStartScheduler();//开启任务调度}static void start_task(void *param){taskENTER_CRITICAL(); //进入临界区periodTimerHandle = xTimerCreate((const char *)"periodTimer",(TickType_t)1000,(UBaseType_t)pdTRUE,(void *)1,(TimerCallbackFunction_t)periodTimer);oneshotTimerHandle = xTimerCreate((const char*)"oneshortTimer",(TickType_t)1,(UBaseType_t)pdFALSE,(void *)2,(TimerCallbackFunction_t)oneShotTimer);//创建获取event的任务xTaskCreate((TaskFunction_t )control_timer_task,(const char* )"control_timer", (uint16_t )CONTROL_TIMER_STACK_SIZE, (void*)NULL,(UBaseType_t )CONTROL_TIMER_TASK_PRIO,(TaskHandle_t* )&controlTimerTask_handler); vTaskDelete(startTask_handler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区}/*timer control task*/static void control_timer_task(void *param){u8 key_pressed = 0;while(1){if(periodTimerHandle && oneshotTimerHandle){key_pressed = KEY_Scan(1);switch(key_pressed){case KEY0_PRESS:xTimerStart(periodTimerHandle, 0);printf("timer1 is running!\r\n");printf("timer ID is %d\r\n", (int)pvTimerGetTimerID(periodTimerHandle));break;case KEY1_PRESS:xTimerStart(oneshotTimerHandle, 0);printf("timer2 is running!\r\n");break;case KEY_UP_PRESS:xTimerStop(periodTimerHandle, 0);xTimerStop(oneshotTimerHandle, 0);printf("timer1, timer2 stop!\r\n");break;default:break;}}vTaskDelay(100);}}void periodTimer(TimerHandle_t xTimer){static u8 cur_cnt1 = 0;cur_cnt1++;printf("period Timer cur_cnt1 = %d\r\n", cur_cnt1);}void oneShotTimer(TimerHandle_t xTimer){static u8 cur_cnt2 = 0;cur_cnt2++;printf("oneshot Timer stop, cur_cnt2 = %d\r\n", cur_cnt2);LED1 = !LED1;}

6.总结

1、软件定时器的最小定时周期等于一个tick周期。如果你需要更短的定时周期则考虑使用硬件定时器。

2、软件定时器的精度一般没有硬件定时器的高,但基本可以满足一般定时需求。提高软件定时器任务的优先级为最高可以提高软件定时器的精度。

3、软件定时器一般用于处理一些逻辑不复杂的,简短的定时任务,它的优点是简单方便,占用的系统资源低,缺点是不够灵活,扩展性不强,当业务逻辑复杂时,考虑使用单独的任务去做。

4、不能在软件定时器回调函数中执行让软件定时器任务阻塞的代码。要尽量保持回调函数简短高效执行。

5、软件定时器可以开多个,理论上只要FreeRTOS的堆内存足够,就可以继续创建新的软件定时器。

6、软件定时器的相关API同样有两个版本,普通版本和中断安全版本(FromISR),使用时需要注意在中断函数中只能使用中断安全版本的。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。