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

    文章

    17

    浏览量

    6703
  • FreeRTOS
    +关注

    关注

    12

    文章

    473

    浏览量

    61349
收藏 人收藏

    评论

    相关推荐

    基于STM32的软件定时器设计

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

    ucos ii , RTOS, 定时器

    请教一下,有谁知道,UCOS II 里面 使用软件定时器时,OS_TASK_TMR_STK_SIZE 该怎么设置?和软件定时器的数目是否有关?(比如使用OSTmrCreate创建1个
    发表于 10-22 11:06

    软件定时器的特点和原理

    本文介绍了软件定时器的特点和原理,并从时钟节拍,数据结构,定时器操作等角度分析,实现了基于STM32的软件定时器,该
    发表于 08-19 08:29

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

    什么是软件定时器软件定时器的实现原理是什么?
    发表于 11-24 06:43

    基于硬件定时器软件定时器的设计资料分享

    概括硬件定时器很精确,软件定时器无论如何都有延迟,主要用在不需要精确定时的地方,而且软件定时比较
    发表于 12-08 06:42

    什么是软件定时器?基于STM32的软件定时器该怎样去实现呢

    目录1.什么是软件定时器2.软件定时器的实现原理3.基于STM32的软件定时器3.1 时钟节拍3
    发表于 12-22 07:47

    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

    μC/OSII中的软件定时器改进

    μC/OSII是一种基于优先级的抢占式操作系统,实时性很强。而系统中软件定时器没有优先级,回调函数顺序执行,这样就降低了系统的实时性。因此,本文对软件定时器进行改进,
    发表于 04-25 11:52 2432次阅读
    μC/OSII中的<b class='flag-5'>软件</b><b class='flag-5'>定时器</b>改进

    台达plc定时器软件中如何找?

    定时器T有线圈和触点,下面我们以三菱和台达来写定时器进行对比如上图所示,我们发现三菱软件定时器T0线圈是可以直接驱动的也就是说能够在线圈中写入定时
    发表于 10-01 18:01 1.5w次阅读
    台达plc<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>

    UCOSIII- 软件定时器的使用

    首先打开宏(使能所有软件定时器)os_cfg.h文件: #define OS_CFG_TMR_EN 11.创建定时器+绑定回调函数
    发表于 12-23 19:55 0次下载
    UCOSIII- <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>的使用

    freeRTOS软件定时器的使用

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

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

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