19_FreeRTOS软件定时器

news2024/11/19 5:37:18

目录

软件定时器介绍

FreeRTOS软件定时器特点

软件定时器的命令队列

软件定时器的相关配置

单次定时器和周期定时器

软件定时器结构体成员

FreeRTOS软件定时器相关API函数

实验源码


软件定时器介绍

定时器描述:从指定的时刻开始,经过一个指定时间,然后触发一个超时事件,用户可自定义定时器的周期

硬件定时器描述:芯片本身自带的定时器模块,硬件定时器的精度一般很高,每次在定时时间到达之后就会自动触发一个中断,用户在中断服务函数中处理信息。

软件定时器:是指具有定时功能的软件,可设置定时周期,当指定时间到达后要调用回调函数(也称超时函数),用户在回调函数中处理信息。

软件定时器优点:

1.硬件定时器数量有限,而软件定时器理论上只需有足够内存,就可以创建多个

2.使用简单、成本低

软件定时器缺点:

1.软件定时器相对硬件定时器来说,精度没有那么高(因为它以系统时钟为基准,系统时钟中断优先级又是最低,容易被打断)。对于需要高精度要求的场合,不建议使用软件定时器。

FreeRTOS软件定时器特点

可裁剪:软件定时器是可裁剪可配置的功能,如果要使能软件定时器,需将configUSE_TIMERS配置项配置成 1

单次和周期:软件定时器支持设置成:单次定时器或周期定时器

注意:软件定时器的超时回调函数是由软件定时器服务任务调用的,软件定时器的超时回调函数本身不是任务,因此不能在该回调函数中使用可能会导致任务阻塞的API函数。

软件定时器服务任务作用:

1.负责软件定时器超时的逻辑判断

2.调用超时软件定时器的超时回调函数

3.处理软件定时器命令队列

软件定时器的命令队列

FreeRTOS提供了许多软件定时器相关的API函数,这些API函数大多都是往定时器的队列中写入消息(发送命令) ,这个队列叫做软件定时器命令队列,是提供给FreeRTOS中的软件定时器使用的,用户是不能直接访问的。

软件定时器的相关配置

当FreeRTOS的配置项configUSE_TIMERS设置为1,在启动任务调度器时,会自动创建软件定时器的服务/守护任务prvTimerTask();

软件定时器服务任务的优先级为configTIMER_TASK_PRIORITY =31;

定时器的命令队列长度为 configTIMER_QUEUE_LENGTH =5 ;

注意:软件定时器的超时回调函数是在软件定时器服务任务中被调用的,服务任务不是专为某个定时器服务的,它还要处理其他定时器。所以,定时器的回调函数不要影响其他定时器。

1.回调函数要尽快实行,不能进入阻塞状态,即不能调用那些会阻塞任务的API 函数,如:vTaskDelay();

2.访问队列或者信号量的非零阻塞时间的API函数也不能调用。

软件定时器的状态

软件定时器共有两种状态

休眠态:软件定时器可以通过其句柄被引用,但因为没有运行,所以其定时超时回调函数不会被执行

运行态:运行态的定时器,当指定时间到达之后,它的超时回调函数会被调用

注意:新创建的软件定时器处于休眠状态,也就是未运行的!发送命令队列软件定时器从休眠态转变为运行态

单次定时器和周期定时器

单次定时器:单次定时器的一旦定时超时,只会执行一次其软件定时器超时回调函数,不会自动重新开启定时,不过可以被手动重新开启。

周期定时器:周期定时器的一旦启动以后就会在执行完回调函数以后自动的重新启动,从而周期地执行其软件定时器回调函数。

Timer1:周期定时器,定时超时时间为2个单位时间,开启后,一直以2个时间单位间隔重复执行;

Timer2:单次定时器,定时超时时间为1个单位时间,开启后,则在第一个超时后就不在执行了。

单次定时器状态转换图

 周期定时器状态转换图

软件定时器结构体成员

typedef struc
{
tconst char*   pcTimerName	/* 软件定时器名字*/
Listltem_t     xTimerListltem	/* 软件定时器列表项*/
TickType_t    xTimerPeriodInTicks;/*软件定时器的周期*/
void *        pvTimerID			/*软件定时器的ID*/
TimerCallbackFunction_t  pxCallbackFunction;/*软件定时器的回调函数*/
#if (configUSE_TRACE_FACILITY ==1)
UBaseType_t  uxTimerNumber		/*软件定时器的编号,调试用*/
#endif
uint8_t	ucStatus;					/*软件定时器的状态*/
}xTIMER;

FreeRTOS软件定时器相关API函数

 创建软件定时器API函数

TimerHandle_t xTimerCreate( const char* constpcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t  constuxAutoReload,
void* pvTimerlD,
TimerCallbackFunction_t  pxCallbackFunction );

开启软件定时器API函数

BaseType_t xTimerStart(TimerHandle_txTimer,const TickType_t xTicksToWait);

停止软件定时器API函数 

BaseType_t xTimerStop( TimerHandle_txTimer,const TickType_txTicksToWait);

复位软件定时器API函数

该功能将使软件定时器的重新开启定时,复位后的软件定时器以复位时的时刻作为开启时刻重新定时

BaseType_t xTimerReset( TimerHandle_txTimer,const TickType_txTicksToWait);

更改软件定时器超时时间API函数

BaseType_t xTimerChangePeriod(TimerHandle_txTimer,
const TickType_txNewPeriod,
const TickType_txTicksToWait);

实验源码

设计两个任务:start_task、task1

start_task:用来创建task1任务,并创建两个定时器(单次和周期)

task1:用于按键扫描,并对软件定时器进行开启、停止操作

/**
  ******************************************************************************
  * @file           : user_mian.h
  * @brief          : V1.00
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "user_key.h"
#include "queue.h"
#include "event_groups.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define  定义----------------------------------------------------------------*/
/* Macro   宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/ 
/* Constants 常量--------------------------------------------------------------*/
/* Function  函数--------------------------------------------------------------*/
void Timer1_Callback(TimerHandle_t pxTimer);
void Timer2_Callback(TimerHandle_t pxTimer);

TimerHandle_t Timer1 = 0;/*单次定时器*/
TimerHandle_t Timer2 = 0;/*周期定时器*/

uint32_t Timer1_;
uint32_t Timer2_;

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


//任务优先级
#define TASK1_PRIO			4
//任务堆栈大小	
#define TASK1_STK_SIZE 		100  
//任务句柄
TaskHandle_t TASK1_Handler;
//任务函数
void task1(void *pvParameters);



 int main(void)
 {	

	/*配置系统中断分组为4位抢占*/
	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	 /*延时函数初始化*/
	 delay_init();
	/*RCC配置*/
	 Rcc_config();
	/*GPIO初始化*/ 
	 Gpio_Init();
	/*USART1初始化*/
	 Uart1_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();          //开启任务调度
		

}
 

/*!
	\brief		开始任务函数
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void start_task(void *pvParameters)
{
	
    taskENTER_CRITICAL();           //进入临界区
	/*创建单次软件定时器*/
	/*名字,延时时间,pdFALSE单次,编号1,回调函数*/
	Timer1 = xTimerCreate("Tiner1",1000,pdFALSE,(void *)1,Timer1_Callback);
	
	/*创建周期软件定时器*/
	/*名字,延时时间,pdTRUE周期,编号2,回调函数*/
	Timer2 = xTimerCreate("Tiner2",1000,pdTRUE,(void *)2,Timer2_Callback);
    //创建任务
    xTaskCreate((TaskFunction_t )task1,     	
                (const char*    )"task1",   	
                (uint16_t       )TASK1_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )TASK1_PRIO,	
                (TaskHandle_t*  )&TASK1_Handler);   

				
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}


/*!
	\brief		任务1扫描控制软件定时器
	\param[in]	传递形参,创建任务时用户自己传入
	\param[out]	none
	\retval 	none
*/
void task1(void *pvParameters)
{
	uint8_t key = 0;
	
    while(1)
    {	
		key = Key_Scan(0);
		
		if(key == KEY0_PRES)
		{
			/*开启定时器*/
			xTimerStart(Timer1,portMAX_DELAY);
			xTimerStart(Timer2,portMAX_DELAY);
			
			taskENTER_CRITICAL();           //进入临界区		
			printf("开启2个定时器\r\n\r\n");
			taskEXIT_CRITICAL();            //退出临界区
		}else if(key == KEY1_PRES)
		{
			/*关闭定时器*/
			xTimerStop(Timer1,portMAX_DELAY);
			xTimerStop(Timer2,portMAX_DELAY);
			
			Timer1_ = 0;
			Timer2_ = 0;
			
			taskENTER_CRITICAL();           //进入临界区		
			printf("停止2个定时器\r\n\r\n");
			taskEXIT_CRITICAL();            //退出临界区
		
		}
		
		vTaskDelay(10);
    }
} 


/*!
	\brief		单次定时器回调函数
	\param[in]	none
	\param[out]	none
	\retval 	none
*/
void Timer1_Callback(TimerHandle_t pxTimer)
{
	
    taskENTER_CRITICAL();           //进入临界区		
	printf("单次定时器运行次数:%d次数\r\n\r\n",++Timer1_);
	taskEXIT_CRITICAL();            //退出临界区

}


/*!
	\brief		周期定时器回调函数
	\param[in]	none
	\param[out]	none
	\retval 	none
*/
void Timer2_Callback(TimerHandle_t pxTimer)
{
	
    taskENTER_CRITICAL();           //进入临界区		
	printf("周期定时器运行次数:%d次数\r\n\r\n",++Timer2_);
	taskEXIT_CRITICAL();            //退出临界区	
}

 /************************************************************** END OF FILE ****/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/371462.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作系统权限提升(十三)之绕过UAC提权-MSF和CS绕过UAC提权

系列文章 操作系统权限提升(十二)之绕过UAC提权-Windows UAC概述 注&#xff1a;阅读本编文章前&#xff0c;请先阅读系列文章&#xff0c;以免造成看不懂的情况&#xff01;&#xff01; MSF和CS绕过UAC提权 CS绕过UAC提权 拿到一个普通管理员的SHELL,在CS中没有*号代表有…

样式冲突太多,记一次前端CSS升级

目前平台前端使用的是原生CSSBEM命名&#xff0c;在多人协作的模式下&#xff0c;容易出现样式冲突。为了减少这一类的问题&#xff0c;提升研效&#xff0c;我调研了业界上主流的7种CSS解决方案&#xff0c;并将最终升级方案落地到了工程中。 样式冲突的原因 目前遇到的样式…

数组:二分查找、移除数组等经典数组题

二分查找&#xff1a;相关题目链接&#xff1a;https://leetcode.cn/problems/binary-search/题目重现&#xff1a;给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜索 nums 中的 target&#xff0c;如果目标值…

【c++】文件操作(文本文件、二进制文件)

文章目录文件操作文本文件写文件读文件二进制文件写文件读文件文件操作 程序运行时产生的数据都属于临时数据&#xff0c;程序一旦运行结束都会被释放&#xff1b; 通过文件可以将数据持久化&#xff1b; c中对文件操作需要包含头文件 文件类型分为两种&#xff1a; 1、文本文…

Playbook的用法

目录 Playbook Playbook 与 Ad-Hoc 对比 YAML 语言特性 YAML语法简介 支持的数据类型 写法格式 1 scalar 标量 建议缩进两个空格&#xff0c;可多 2 Dictionary 字典 3 List 列表 三种常见的数据格式 Playbook 核心组件 不要用 tab 可以#注释 hosts remote_us…

【编程入门】应用市场(Python版)

背景 前面已输出多个系列&#xff1a; 《十余种编程语言做个计算器》 《十余种编程语言写2048小游戏》 《17种编程语言10种排序算法》 《十余种编程语言写博客系统》 《十余种编程语言写云笔记》 《N种编程语言做个记事本》 目标 为编程初学者打造入门学习项目&#xff0c;使…

【Linux】进程间通信(匿名管道和命名管道通信、共享内存通信)

文章目录1、进程间通信1.1 进程的通信1.2 如何让进程间通信&#xff1f;1.3 进程间通信的本质2、管道通信2.1 匿名管道2.2 匿名管道通信2.3 命名管道2.4 命名管道的通信3、SystemV中的共享内存通信3.1 共享内存3.2 共享内存的通信3.3 共享内存的缺点以及数据保护3.4 共享内存的…

13.STM32超声波模块讲解与实战

目录 1.超声波模块讲解 2.超声波时序图 3.超声波测距步骤 4.项目实战 1.超声波模块讲解 超声波传感器模块上面通常有两个超声波元器件&#xff0c;一个用于发射&#xff0c;一个用于接收。电路板上有4个引脚&#xff1a;VCC GND Trig&#xff08;触发&#xff09;&#xff…

gcc的使用,调试工具gdb的使用

gcc编译 gcc编译可以分为四个步骤&#xff0c;预处理、编译、汇编、链接。 预处理命令&#xff1a;gcc -E hello.c -o hello.i编译命令&#xff1a;gcc -S hello.i -o hello.s汇编命令&#xff1a; gcc -c hello.s -o hello.o链接命令&#xff1a;gcc hello.o -o hello gcc…

一个.Net Core开发的,撑起月6亿PV开源监控解决方案

更多开源项目请查看&#xff1a;一个专注推荐.Net开源项目的榜单 项目发布后&#xff0c;对于我们程序员来说&#xff0c;项目还不是真正的结束&#xff0c;保证项目的稳定运行也是非常重要的&#xff0c;而对于服务器的监控&#xff0c;就是保证稳定运行的手段之一。对数据库、…

Navicat16实用小技巧

数据库管理工具是一种用于管理数据库的软件工具&#xff0c;它可以帮助用户创建、修改、维护和查询数据库。数据库管理工具可以为用户提供可视化界面&#xff0c;使得管理数据库变得更加容易。最为一款数据库管理工具&#xff0c;需要具备一下功能&#xff1a; 数据库创建和配…

OAK相机如何将yoloV6模型转换成blob格式?(2.0 及之后版本)

编辑&#xff1a;OAK中国 首发&#xff1a;oakchina.cn 喜欢的话&#xff0c;请多多&#x1f44d;⭐️✍ 内容可能会不定期更新&#xff0c;官网内容都是最新的&#xff0c;请查看首发地址链接。 ▌前言 Hello&#xff0c;大家好&#xff0c;这里是OAK中国&#xff0c;我是助手…

【对比学习论文】SimCLR 视觉表征对比学习的简单框架

文章题目&#xff1a;A Simple Framework for Contrastive Learning of Visual Representations时间&#xff1a;2020 摘要 本文提出了SimCLR:一种用于视觉表征对比学习的简单框架。我们简化了最近提出的对比自监督学习算法&#xff0c;而不需要专门的架构或内存库。为了了解…

websocket报错集锦-不断更新中

问题1&#xff1a;Failed to construct ‘WebSocket’: An insecure WebSocket connection may not be initiated from a page loaded over HTTPS. 问题描述 Mixed Content: The page at https://AAAAAA.com was loaded over HTTPS, but attempted to connect to the insecur…

Linux系统下命令行安装MySQL5.7+详细步骤

一起学编程&#xff0c;让生活更随和&#xff01; 如果你觉得是个同道中人&#xff0c;欢迎关注博主 gzh &#xff1a;【随和的皮蛋桑】。 专注于Java基础、进阶、面试以及计算机基础知识分享&#x1f433;。偶尔认知思考、日常水文&#x1f40c;。 目录1、下载安装包2、检查…

STM32 使用microros与ROS2通信

本文主要介绍如何在STM32中使用microros与ROS2进行通信&#xff0c;在ROS1中标准的库是rosserial,在ROS2中则是microros,目前网上的资料也有一部分了&#xff0c;但是都没有提供完整可验证的demo&#xff0c;本文将根据提供的demo一步步给大家进行演示。1、首先如果你用的不是S…

JUC 之 线程局部变量 ThreadLocal

—— ThreadLocal 基本概念 ThreadLocal 提供线程局部变量。这些变量与正常的变量不同&#xff0c;因为每一个线程在访问 ThreadLocal 实例的时候&#xff08;通过其get 或者 set 方法&#xff09;都有自己的、独立初始化的变副本。ThreadLocal实例通常是类中的私有静态字段&…

104-JVM优化

JVM优化为什么要学习JVM优化&#xff1a; 1&#xff1a;深入地理解 Java 这门语言 我们常用的布尔型 Boolean&#xff0c;我们都知道它有两个值&#xff0c;true 和 false&#xff0c;但你们知道其实在运行时&#xff0c;Java 虚拟机是 没有布尔型 Boolean 这种类型的&#x…

@Autowired和@Resource的区别

文章目录1. Autowired和Resource的区别2. 一个接口多个实现类的处理2.1 注入时候报错情况2.2 使用Primary注解处理2.3 使用Qualifer注解处理2.4 根据业务情况动态的决定注入哪个serviceImpl1. Autowired和Resource的区别 Aurowired是根据type来匹配&#xff1b;Resource可以根…

数据结构栈的经典OJ题【leetcode最小栈问题大剖析】【leetcode有效的括号问题大剖析】

目录 0.前言 1.最小栈 1.1 原题展示 1.2 思路分析 1.2.1 场景引入 1.2.2 思路 1.3 代码实现 1.3.1 最小栈的删除 1.3.2 最小栈的插入 1.3.3 获取栈顶元素 1.3.4 获取当前栈的最小值 2. 有效的括号 0.前言 本篇博客已经把两个关于栈的OJ题分块&#xff0c;可以根据目…