Free RTOS的软件定时器

描述

软件定时器是FreeRTOS中的一个重要模块,使用软件定时器可以方便的实现一些与超时或周期性相关的功能。


 

硬件定时器


 

芯片本身提供的定时功能。一般是由外部晶振提供给芯片输入时钟,芯片向软件模块提供一组配置寄存器,接受控制输入,到达设定时间值后芯片中断控制器产生时钟中断。硬件定时器的精度一般很高,可以达到纳秒级别,并且是中断触发方式。


软件定时器
 


 

软件定时器是由操作系统提供的一类系统接口,它构建在硬件定时器基础之上,使系统能够提供不受硬件定时器资源限制的定时器服务,它实现的功能与硬件定时器也是类似的。


 

FreeRTOS 软件定时器功能

裁剪:能通过宏关闭软件定时器功能。

软件定时器创建。

软件定时器启动。

软件定时器停止。

软件定时器复位。

软件定时器删除。
 


 

软件定时器模式


 

单次模式:当用户创建了定时器并启动了定时器后,定时时间到了,只执行一次回调函数之后就将该定时器删除,不再重新执行。

周期模式:这个定时器会按照设置的定时时间循环执行回调函数,直到用户将定时器删除

 

软件定时器


 

FreeRTOS 通过一个 prvTimerTask 任务(也叫守护任务 Daemon)管理软定时器,它是在启动调度器时自动创建的,为了满足用户定时需求。prvTimerTask 任务会在其执行期间检查用户启动的时间周期溢出的定时器,并调用其回调函数。只有设置 FreeRTOSConfig.h中的宏定义 configUSE_TIMERS 设置为 1 ,将相关代码编译进来,才能正常使用软件定时器相关功能。

 

配置定时器

//启用软件定时器
#define configUSE_TIMERS                    1                              
//软件定时器优先级
#define configTIMER_TASK_PRIORITY            (configMAX_PRIORITIES-1)        
//软件定时器队列长度
#define configTIMER_QUEUE_LENGTH            10                               
//软件定时器任务堆栈大小
#define configTIMER_TASK_STACK_DEPTH        (configMINIMAL_STACK_SIZE*2) 


创建定时器

TimerHandle_t xTimerCreate( const char *pcTimerName, 
                            const TickType_t xTimerPeriod, 
                            const UBaseType_t uxAutoReload, 
                            void * const pvTimerID, 
                           TimerCallbackFunction_t pxCallbackFunction );

参数
 

pcTimerName:定时器名称

xTimerPeriod :定时周期

uxAutoReload : 如果将uxAutoReload设置为pdTRUE,则计时器将以xTimerPeriod参数设置的频率重复终止。如果将uxAutoReload设置为pdFALSE,则计时器将是一次触发,并在其到期后进入休眠状态。

pvTimerID分配给正在创建的计时器的标识符。

pxCallbackFunction计时器到期时要调用的函数

返回值
 

如果成功创建了计时器,则返回新创建的计时器的句柄。如果由于剩余的FreeRTOS堆不足而无法分配计时器结构而无法创建计时器,则返回NULL

 

启动定时器

BaseType_t xTimerStart( TimerHandle_t xTimer, 
                        TickType_t xTicksToWait );

参数
 

xTimer:计时器的句柄
 

xTicksToWait:指定在计时器命令队列已经满的情况下,任务应保持阻塞状态以等待空间可用的最大时间。

返回值
 

如果即使经过xBlockTime刻度后仍无法将启动命令发送到计时器命令队列,则将返回pdFAIL。如果命令已成功发送到计时器命令队列,则将返回pdPASS。

 

停止定时器

BaseType_t xTimerStop( TimerHandle_t xTimer, 
                       TickType_t xTicksToWait );

参数:同上

返回值:同上
 


 

复位定时器

BaseType_t xTimerReset( TimerHandle_t xTimer, 
                        TickType_t xTicksToWait );

 

参数:同上

返回值:同上


 

删除定时器

BaseType_t xTimerDelete( TimerHandle_t xTimer, 
                         TickType_t xTicksToWait );

 

参数:同上类似

返回值:同上类似


 

改变定时器周期

BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, 
                               TickType_txNewPeriod,
                               TickType_t xTicksToWait );

参数

xTimer:定时器的句柄
 

xNewPeriod:新的周期参数

xTicksToWait:指定在计时器命令队列已经满的情况下,任务应保持阻塞状态以等待空间可用的最大时间。

返回值
 

如果即使经过xBlockTime滴答声后仍无法将更改周期命令发送到计时器命令队列,则将返回pdFAIL。如果命令已成功发送到计时器命令队列,则将返回pdPASS。


 

还有中断启动定时器、停止、复位、改变周期的API函数,请查阅官方文档!


 

附上小例程

#include "stm32f10x.h"
#include 
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "timers.h"

//毫秒级的延时
void Delay_Ms(u16 time)
{    
   u16 i=0;  
   while(time--)
   {
      i=12000;  //自己定义
      while(i--) ;    
   }
}

void LED_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;        //定义结构体变量
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);  //开启时钟
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;            //选择你要设置的IO口
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;      //设置推挽输出模式
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;     //设置传输速率
  GPIO_Init(GPIOC,&GPIO_InitStructure);                //初始化GPIO
  
  GPIO_SetBits(GPIOC,GPIO_Pin_0);             //将LED端口拉高,熄灭LED
}

void KEY_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE,ENABLE);
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;     //选择你要设置的IO口
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//下拉输入  
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;     //设置传输速率
  GPIO_Init(GPIOA,&GPIO_InitStructure);      /* 初始化GPIO */
  
  GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_2|GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;  //上拉输入
  GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  GPIO_Init(GPIOE,&GPIO_InitStructure);
}


void USART_init(uint32_t bound)
{
  GPIO_InitTypeDef GPIO_InitStruct;   //定义GPIO结构体变量
  USART_InitTypeDef USART_InitStruct;   //定义串口结构体变量
  
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);   //使能GPIOC的时钟
  
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;   //配置TX引脚
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;   //配置PA9为复用推挽输出
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;   //配置PA9速率
  GPIO_Init(GPIOA,&GPIO_InitStruct);   //GPIO初始化函数
  
  GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;   //配置RX引脚
  GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;   //配置PA10为浮空输入
  GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;   //配置PA10速率
  GPIO_Init(GPIOA,&GPIO_InitStruct);   //GPIO初始化函数
  
  
  USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;   //发送接收模式
  USART_InitStruct.USART_Parity=USART_Parity_No;   //无奇偶校验
  USART_InitStruct.USART_BaudRate=bound;   //波特率
  USART_InitStruct.USART_StopBits=USART_StopBits_1;   //停止位1位
  USART_InitStruct.USART_WordLength=USART_WordLength_8b;   //字长8位
  USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;   //无硬件数据流控制
  USART_Init(USART1,&USART_InitStruct);   //串口初始化函数
  
  USART_Cmd(USART1,ENABLE);   //使能USART1
}

int fputc(int ch,FILE *f)   //printf重定向函数
{
  USART_SendData(USART1,(uint8_t)ch);   //发送一字节数据
  while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);   //等待发送完成
  return ch;
}


#define START_TASK_PRIO 5      //任务优先级
#define START_STK_SIZE 128      //任务堆栈大小
TaskHandle_t StartTask_Handler;   //任务句柄
void Start_Task(void *pvParameters);//任务函数

#define Low_TASK_PRIO 2       //任务优先级
#define Low_STK_SIZE 50       //任务堆栈大小
TaskHandle_t LowTask_Handler;     //任务句柄
void Low_Task(void *p_arg);     //任务函数

#define Med_TASK_PRIO 3       //任务优先级
#define Med_STK_SIZE 50       //任务堆栈大小
TaskHandle_t MedTask_Handler;     //任务句柄
void Med_Task(void *p_arg);     //任务函数

TimerHandle_t Time0Handler = NULL;  //软件定时器句柄
void Time0Callback( TimerHandle_t pxTimer );//回调函数

int main( void ) 
{
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4
  
  LED_Init(); //初始化 LED
  KEY_Init();
  USART_init(9600);
  
  //创建开始任务
  xTaskCreate(
    (TaskFunction_t )Start_Task,     //任务函数
    (const char* )"Start_Task",     //任务名称
    (uint16_t )START_STK_SIZE,       //任务堆栈大小
    (void* )NULL,             //传递给任务函数的参数
    (UBaseType_t )START_TASK_PRIO,     //任务优先级
    (TaskHandle_t* )&StartTask_Handler  //任务句柄 
  );
  vTaskStartScheduler();  //开启调度
}

//开始任务函数
void Start_Task(void *pvParameters)
{
  taskENTER_CRITICAL();   //进入临界区
  //创建软件定时器
  Time0Handler = xTimerCreate( ( char *                ) "Time0",     //定时器的名称
                 ( TickType_t              ) 1000,       //定时周期
                 ( UBaseType_t             ) pdTRUE,       //是否重装载 (pdTRUE or pdFAIL)
                 ( void *                  ) 0,         //ID号
                 ( TimerCallbackFunction_t ) Time0Callback ); //回调函数
  //开启定时器
  xTimerStart( Time0Handler, portMAX_DELAY );
  //创建 Low 任务
  xTaskCreate(
    (TaskFunction_t )Low_Task, 
    (const char* )"Low_Task", 
    (uint16_t )Low_STK_SIZE, 
    (void* )NULL,
    (UBaseType_t )Low_TASK_PRIO,
    (TaskHandle_t* )&LowTask_Handler
  );
  //创建 Med 任务
  xTaskCreate(
    (TaskFunction_t )Med_Task, 
    (const char* )"Med_Task", 
    (uint16_t )Med_STK_SIZE, 
    (void* )NULL,
    (UBaseType_t )Med_TASK_PRIO,
    (TaskHandle_t* )&MedTask_Handler
  );
  vTaskDelete(StartTask_Handler); //删除开始任务
  taskEXIT_CRITICAL();   //退出临界区
}


void Low_Task(void *pvParameters)
{
  while(1)
  {
    
    vTaskDelay(1000);
  }
}

void Med_Task(void *pvParameters)
{
  //BaseType_t xReturn = NULL;
  while(1)
  {
    printf("正在运行n");
    vTaskDelay(1000);
  }
}

void Time0Callback( TimerHandle_t pxTimer )
{
  static int count = 0;
  printf("%dn",++count);
}


 

实验现象

 

软件定时器


 

--END--
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分