FreeRTOS-软件定时器

FreeRTOS-软件定时器

  • 一般来说,每个MCU都会有定时器,这些都属于硬件定时器,但是有些时候硬件定时器可能会不够用,FreeRTOS提供了软件定时器,并且当内存足够的时候,软件定时器可以设置很多歌,当然,相比于硬件定时器,软件定时器精度和功能上都会稍差些,但是在一些对精度等条件要求不高的场合中足够了。
  • 在使用软件定时器时,可以设置一段时间,经过一段时间后,系统就会自动调用软件定时器所对应的回调函数,但是要注意的是,因为软件定时器回调函数是在定时器服务任务中执行的(当做任务主体的一部分),所以在软件定时器回调函数中一定不要调用任何会阻塞任务的API函数。

软件定时器配置

  • 实际上,软件定时器也是基于FreeRTOS中的队列来完成各项操作的,这个队列叫做定时器命令队列,定时器命令队列是提供给FreeRTOS的软件定时器使用的,用户不能直接访问。
  • 在使用软件定时器前,也需要做一些相应的配置,软件定时器的配置主要有四部分。
  1. configUSE_TIMERS 如果要使用软件定时器的话要设置该宏为1,在启动调度器的时候就会自动创建软件定时器任务
  2. configTIMER_TASK_PRIORITY 软件定时器优先级,这里决定了软件定时器回调函数的优先级
  3. configTIMER_QUEUE_LENGTH 软件定时器队列长度,决定了能够创建多少个软件定时器
  4. configTIMER_TASK_STACK_DEPTH 软件定时器任务堆栈大小
  • 此外,软件定时器还可以设置为单次定时器和周期定时器,当设置为单次定时器时,定时器启动后,当定时时间到达后,就会调用一次回调函数,调用完毕后定时器就会停止,当需要定时器再次启动时就需要复位定时器,然后定时器再经过定时周期后调用回调函数。周期定时器则当开启后就会周期性的调用回调函数。
  • 因为定时器回调函数是根据任务上下文切换来调用的,所以定时器的精度取决于系统的时钟节拍,当系统时钟节拍周期越小,则定时器精度越高,相应地,系统开销也就越大。

相关API

  • 在本章不会重点分析定时器相关API的源码。只是将定时器API函数的使用方法作一个讲述。

xTimerCreate()

  • 函数功能:动态创建定时器
  • 函数声明:TimerHandle_t xTimerCreate( const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction )
  • 输入参数pcTimerName:定时器名
  • 输入参数xTimerPeriodInTicks:定时器定时周期
  • 输入参数uxAutoReload:是否设置为周期定时器,pdTRUE为周期定时器,pdFALSE为单次定时器
  • 输入参数pvTimerID:设置定时器ID,不同ID定时器可能会有相同的定时器名,所以设置不同ID加以区分
  • 输入参数pxCallbackFunction:定时器回调函数,该函数需要用户自定义
  • 返回参数TimerHandle_t:定时器句柄

xTimerReset()

  • 函数功能:复位定时器,如果是单次定时器,当调用一次关闭后,调用该函数可以重新打开
  • 函数声明: xTimerReset(xTimer, xTicksToWait )
  • 输入参数xTimer: 复位定时器句柄
  • 输入参数xTicksToWait:定时器复位阻塞时间,因为复位定时器时本质是向队列发送消息,所以肯定会涉及到阻塞时间
  • 返回参数pdFAIL或pdTRUR,返回pdFAIL是说明定时器复位失败

xTimerStart()

  • 函数功能:开启定时器
  • 函数声明:xTimerStart( xTimer, xTicksToWait )
  • 输入参数xTimer: 开启定时器句柄
  • 输入参数xTicksToWait:定时器复位阻塞时间,因为开启定时器时本质是向队列发送消息,所以肯定会涉及到阻塞时间
  • 返回参数pdFAIL或pdTRUR,返回pdFAIL是说明定时器开启失败

xTimerStop()

  • 函数功能:停止定时器
  • 函数声明: xTimerStop(xTimer, xTicksToWait )
  • 输入参数xTimer: 停止定时器句柄
  • 输入参数xTicksToWait:定时器停止阻塞时间,因为停止定时器时本质是向队列发送消息,所以肯定会涉及到阻塞时间
  • 返回参数pdFAIL或pdTRUR,返回pdFAIL是说明定时器停止失败

  • 同样地,这些函数也有相应的中断级API,功能与上面任务级的类似,这里就不展开叙述了。下面给出一个用法示例。

用法示例

实验目的:通过按键控制软件定时器的开启与关闭,创建两个定时器,在回调函数中记录定时器调用次数
  • 定时器相关初始化代码如下

#define TIMER1_PERIOD   1000
#define TIMER1_ID       1
TimerHandle_t Timer1_Handler;


#define TIMER2_PERIOD   3000
#define TIMER2_ID       2
TimerHandle_t Timer2_Handler;
BaseType_t err;
	 
	 Timer1_Handler = xTimerCreate((char *)"Timer1",
																 (TickType_t )TIMER1_PERIOD,
								                 (UBaseType_t) pdTRUE,
																 (void *)TIMER1_ID,
																 (TimerCallbackFunction_t) Timer1_CallBack);
								
	 if (Timer1_Handler == NULL)
	 {
    
    
		 printf("Timer1 Creat Failed!!!\r\n");
	 }
	 else
	 {
    
    
		 err = xTimerStart(Timer1_Handler,10);
		 if (err != pdTRUE)
		 {
    
    
			 printf("Timer1 Start Failed!!!\r\n");
		 }
	 }
	 
	 Timer2_Handler = xTimerCreate((char *)"Timer2",
																 (TickType_t )TIMER2_PERIOD,
								                 (UBaseType_t)pdFALSE,
																 (void *)     TIMER2_ID,
																 (TimerCallbackFunction_t) Timer2_CallBack);
	 
   if (Timer2_Handler == NULL)
	 {
    
    
		 printf("Timer2 Creat Failed!!!\r\n");
	 }
   else
	 {
    
    
		 err = xTimerStart(Timer2_Handler,10);
		 if (err != pdTRUE)
		 {
    
    
			 printf("Timer1 Start Failed!!!\r\n");
		 }
	 }

  • 按键部分代码如下
u8 keyFlag=0;
void key_task(void* pvParameters)
{
    
    
	
	BaseType_t err;
	while(1)
	{
    
    
		
		if (Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON)
		{
    
    
			if ( (keyFlag&0x01) == 0x01)
				keyFlag &= ~(0x01<<0);
			else
			  keyFlag |= (0x01<<0);	
			if ((keyFlag&0x01) == 0x01)
			{
    
    
				err = xTimerStart(Timer1_Handler,0);
				if (err != pdTRUE )
				{
    
    
					printf("Timer1 Start Failed!!!\r\n");
				}
				else
				{
    
    
					printf("Timer1 Start!!\r\n");
			
			  }
			}
			else
			{
    
    
				err = xTimerStop(Timer1_Handler,0);
				if (err != pdTRUE )
				{
    
    
					printf("Timer1 Stop Failed!!!\r\n");
				}
				else
				{
    
    
					printf("Timer1 Stop!!\r\n");
			
			  }
			}
		}
		
		if (Key_Scan(KEY2_GPIO_PORT,KEY2_GPIO_PIN) == KEY_ON)
		{
    
    
			if ( (keyFlag&0x02) == 0x02)
				keyFlag &= ~(0x01<<1);
			else
				keyFlag |= (0x01<<1);
			if ( (keyFlag&0x02) == 0x02)
			{
    
    
				xTimerStart(Timer2_Handler,0);
				printf("Timer2 Start!!\r\n");
			}
			else
			{
    
    
				xTimerReset(Timer2_Handler,0);
				printf("Timer2 Reset!!\r\n");
			}				
			
		}
		vTaskDelay(10);
	}
}
  • 定时器回调函数代码如下
void Timer1_CallBack(TimerHandle_t xTimer)
{
    
    
	  static int count1 = 0;
		count1++;
		LED0 = ~LED0;
		printf("timer1 Call Back %d\r\n",count1);
	
}


void Timer2_CallBack(TimerHandle_t xTimer)
{
    
    
	static int count2 = 0;
	count2++;
	LED1 = ~LED1;
	printf("timer2 Call Back %d\r\n",count2);
}


猜你喜欢

转载自blog.csdn.net/dhejsb/article/details/120206507