0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Free RTOS的软件定时器

汽车电子技术 来源:玩转单片机 作者: Julian 2023-02-10 15:53 次阅读

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


硬件定时器


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


软件定时器


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


FreeRTOS 软件定时器功能

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

软件定时器创建。

软件定时器启动。

软件定时器停止。

软件定时器复位。

软件定时器删除。


软件定时器模式


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

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

poYBAGPl9zqAEXkAAAE78KsCOCE553.png


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);
}


实验现象

pYYBAGPl99KAejgvAABWsxgh4dQ062.png


--END--

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 软件定时器
    +关注

    关注

    0

    文章

    18

    浏览量

    6744
  • FreeRTOS
    +关注

    关注

    12

    文章

    484

    浏览量

    62157
收藏 人收藏

    评论

    相关推荐

    使用cola_os软件定时器实现时间片轮询框架

    如果使用RTOS显得太浪费,这时候可以尝试使用使用cola_os这类基于软件定时器实现的时间片轮询框架。
    的头像 发表于 09-22 09:03 1422次阅读
    使用cola_os<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>实现时间片轮询框架

    基于STM32的软件定时器设计

    软件定时器是用程序模拟出来的定时器,可以由一个硬件定时器模拟出成千上万个软件定时器,这样程序在需
    发表于 07-03 17:06 1058次阅读
    基于STM32的<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>设计

    Linux和RTOS的时钟和定时器怎么使用

    Linux发烧友1.RTOS篇1.1RT-Thread简介1.2时钟管理1.2.1时钟节拍1.3获取系统节拍1.4定时器分类1.5定时器源码分析1.6定时器相关函数1.61动态创建一个
    发表于 01-17 08:13

    定时器初值计算软件工具

    定时器初值计算软件工具
    发表于 03-20 10:23 239次下载

    555定时器电路设计软件

    555定时器电路设计软件
    发表于 03-02 11:29 287次下载

    555定时器应用设计软件免费下载

    本文档的主要内容详细介绍的是555定时器应用设计软件免费下载,本软件是一款555定时器设计软件,使用非常方便。
    发表于 12-17 08:00 51次下载
    555<b class='flag-5'>定时器</b>应用设计<b class='flag-5'>软件</b>免费下载

    ESP8266的管脚的控制和软件定时器的使用

    先说定时器,ESP8266内部的定时器分为软件定时器和硬件定时器。手册中指出硬件定时器其实就跟单
    的头像 发表于 07-29 14:57 9510次阅读
    ESP8266的管脚的控制和<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>的使用

    设计软件定时器

    软件定时器搬来使用2、自己设计软件定时器这里我只介绍第二种方法,我们知道,硬件定时器是通过对系统时钟周期进行计数实现的,那么
    发表于 11-05 18:35 2次下载
    设计<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>

    基于硬件定时器软件定时器

    概括硬件定时器很精确,软件定时器无论如何都有延迟,主要用在不需要精确定时的地方,而且软件定时比较
    发表于 11-25 09:51 8次下载
    基于硬件<b class='flag-5'>定时器</b>的<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>

    详细剖析Linux和RTOS(RT-Thread)的时钟和定时器的使用

    Linux发烧友1.RTOS篇1.1RT-Thread简介1.2时钟管理1.2.1时钟节拍1.3获取系统节拍1.4定时器分类1.5定时器源码分析1.6定时器相关函数1.61动态创建一个
    发表于 01-17 09:31 4次下载
    详细剖析Linux和<b class='flag-5'>RTOS</b>(RT-Thread)的时钟和<b class='flag-5'>定时器</b>的使用

    软件定时器简介及程序配置

      软件定时器就是允许函数设置一定的等待时间,然后执行。定时器执行的函数被称为定时器的回调函数。定时器从启动到执行回调函数之间的时间称为
    的头像 发表于 12-06 16:10 3909次阅读
    <b class='flag-5'>软件</b><b class='flag-5'>定时器</b>简介及程序配置

    freeRTOS软件定时器的使用

    freeRTOS中加入了软件定时器这个功能组件,是一个可选的、不属于freeRTOS内核的功能,由定时器服务(其实就是一个定时器任务)来提供。
    的头像 发表于 02-10 13:55 2159次阅读

    什么是软件定时器软件定时器的实现原理

    软件定时器是用程序模拟出来的定时器,可以由一个硬件定时器模拟出成千上万个软件定时器,这样程序在需
    的头像 发表于 05-23 17:05 2786次阅读

    关于软件定时器的一些讨论

    这就是简单的软件定时器,是的,这就是特别简洁版本的软件定时器。当然它是有缺点的,比如systick_ms每1ms加1,所以软件
    的头像 发表于 10-13 16:14 566次阅读
    关于<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>的一些讨论

    如何实现一个软件定时器

    在Linux,uC/OS,FreeRTOS等操作系统中,都带有软件定时器,原理大同小异。典型的实现方法是:通过一个硬件定时器产生固定的时钟节拍,每次硬件定时器中断到,就对一个全局的时间
    的头像 发表于 04-29 11:00 646次阅读