【嵌入式——FreeRTOS】软件定时器

【嵌入式——FreeRTOS】软件定时器

  • 定时器简介
  • 软件定时器优缺点
  • 软件定时器特点
  • 软件定时器的命令队列
  • 软件定时器相关配置
  • 软件定时器的状态
  • 工作模式
    • 单次定时器
    • 周期定时器
  • 软件定时器结构体成员介绍
  • 相关API
  • 代码示例

定时器简介

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

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

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

软件定时器优缺点

优点

  • 理论是只需要足够内存,就可以创建多个
  • 使用简单、成本低

缺点

  • 精度没那么高

软件定时器特点

  1. 可裁剪:软件定时器是可裁剪可配置的功能,如果要使能软件定时器,需将configUSE_TIMERS宏配置为1
  2. 单次和周期:软件定时器支持设置成单次定时器周期定时器

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

软件定时器服务任务:在调用函数vTaskStartScheduler()开启任务调度器的时候,会创建一个用于管理软件定时器的任务,这个任务就叫做软件定时器服务任务。

软件定时器服务任务作用

  1. 负责软件定时器超时的逻辑判断
  2. 调用超时软件定时器的超时回调函数
  3. 处理软件定时器的命令队列

软件定时器的命令队列

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

软件定时器相关配置

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

软件定时器服务任务的优先级为configTIMER_TASK_PRIORITY(31)。

定时器的命令队列长度为 configTIMER_QUEUE_LENGTH(5)。

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

回调函数要尽快执行,不能进入阻塞状态,即不能调用那些会让任务阻塞的API函数,如vTaskDelay()。

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

软件定时器的状态

  1. 休眠态:软件定时器可以通过其句柄被引用,但因为没有运行,所以其定时超时回调函数不能被执行。
  2. 运行态:运行态的定时器,当指定时间到达之后,它的超时回调函数会被调用。

休眠态转变为运行态:发送命令队列。

工作模式

单次定时器

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

周期定时器

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

软件定时器结构体成员介绍

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

相关API

函数描述
xTimerCreate()动态方式创建软件定时器
xTimerCreateStatic()静态方式创建软件定时器
xTimerStart()开启软件定时器定时器
xTimerStartFromISR()在中断中开启软件定时器定时器
xTimerStop()停止软件定时器定时
xTimerStopFromISR()在中断中停止软件定时器定时
xTimerReset()复位软件定时器定时
xTimerResetFromISR()在中断中复位软件定时器定时
xTimerChangePeriod()更改软件定时器的定时超时时间
xTimerChangePeriodFromISR()在中断中更改软件定时器的定时超时时间
//返回值 NULL 创建失败 其他值 创建成功 返回定时器句柄
TimerHandle_t xTimerCreate( 
	const char * const pcTimerName, 		//软件定时器名
	const TickType_t xTimerPeriodInTicks,	//定时超时时间
	const BaseType_t xAutoReload,			//定时器模式 pdTRUE:周期定时器,pdFALSE:单次定时器
	void * const pvTimerID,					//定时器ID
	TimerCallbackFunction_t pxCallbackFunction //回调函数
)

//xTimer 待开启的软件定时器句柄
//xTicksToWait  发送命令到软件定时器命令队列的最大等待时间
//返回值 pdPASS开启成功 pdFAIL 开启失败
#define xTimerStart( xTimer, xTicksToWait ) \
    xTimerGenericCommand( ( xTimer ), tmrCOMMAND_START, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )

//xTimer 待停止的软件定时器句柄
//xTicksToWait  发送命令到软件定时器命令队列的最大等待时间
//返回值 pdPASS停止成功 pdFAIL 停止失败
#define xTimerStop( xTimer, xTicksToWait ) \
    xTimerGenericCommand( ( xTimer ), tmrCOMMAND_STOP, 0U, NULL, ( xTicksToWait ) )

//xTimer 待复位的软件定时器句柄
//xTicksToWait  发送命令到软件定时器命令队列的最大等待时间
//返回值 pdPASS复位成功 pdFAIL 复位失败
#define xTimerReset( xTimer, xTicksToWait ) \
    xTimerGenericCommand( ( xTimer ), tmrCOMMAND_RESET, ( xTaskGetTickCount() ), NULL, ( xTicksToWait ) )


//xTimer 待更新的软件定时器句柄
//xNewPeriod 新的定时超时时间 单位1ms
//xTicksToWait  发送命令到软件定时器命令队列的最大等待时间
//返回值 pdPASS更改成功 pdFAIL 更改失败
#define xTimerChangePeriodFromISR( xTimer, xNewPeriod, pxHigherPriorityTaskWoken ) \
    xTimerGenericCommand( ( xTimer ), tmrCOMMAND_CHANGE_PERIOD_FROM_ISR, ( xNewPeriod ), ( pxHigherPriorityTaskWoken ), 0U )


代码示例

#include "queue.h"
#inculde "sempht.h"

TimerHandle_t timer1_handle = 0; //单次定时器句柄
TimerHandle_t timer2_handle = 0; //周期定时器句柄

static TaskHandle_t		start_tid;

void timer1Callback( TimerHandle_t pxTimer );
void timer2Callback( TimerHandle_t pxTimer );

void init(){
	//创建
    xTaskCreate((TaskFunction_t)task_start,
                (const char *)"Initialize all task",
                (uint16_t)START_THREAD_STKSZ,
                (void *)NULL,
                (UBaseType_t)(START_THREAD_PRIO),
                (TaskHandle_t *)&start_tid);
	//这个方法会创建两个定时器任务 
	vTaskStartScheduler();
}

//发送任务通知值
void task_start(){
	timer1_handle = xTimerCreate("time1",1000,pdFALSE,(void *)1,timer1Callback);
		timer2_handle = xTimerCreate("time1",1000,pdTRUE,(void *)1,timer2Callback);

    xTaskCreate((TaskFunction_t)task1,
                (const char *)"Initialize all task",
                (uint16_t)START_THREAD_STKSZ,
                (void *)NULL,
                (UBaseType_t)(START_THREAD_PRIO),
                (TaskHandle_t *)&start_tid);
}

//timer1超时回调函数
void timer1Callback( TimerHandle_t pxTimer )
{
	static uint32_t timer = 0;
	printf("timer1执行次数\n",++timer);
}

//timer2超时回调函数
void timer2Callback( TimerHandle_t pxTimer )
{
	static uint32_t timer = 0;
	printf("timer2执行次数\n",++timer);

}

void task1(void * pvParameters){
	uint8_t key=0;
	while(1){

		key = key_scan();
		if(key == KEY0_PRES){
			//开启定时器
			xTimerStart(timer1_handle , portMAX_DELAY);
			xTimerStart(timer2_handle , portMAX_DELAY);
		} else if(key == KEY1_PRES){
			//停止定时器
			xTimerStop(timer1_handle , portMAX_DELAY);
			xTimerStop(timer2_handle , portMAX_DELAY);
		}
	}

}


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java的垃圾回收机制解说

Java 内存运行时区域中的程序计数器、虚拟机栈、本地方法栈随线程而生灭;栈中的栈帧随着方法的进入和退出而有条不紊地执行着出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的(尽管在运行期会由 JIT 编译器进行一些优化&…

微服务的分布式事务解决方案

微服务的分布式事务解决方案 1、分布式事务的理论模型1.1、X/Open 分布式事务模型1.2、两阶段提交协议1.3、三阶段提交协议 2、分布式事务常见解决方案2.1、TCC补偿型方案2.2、基于可靠性消息的最终一致性方案2.3、最大努力通知型方案 3、分布式事务中间件 Seata3.1、AT 模式3.…

LabVIEW的JKI State Machine

JKI State Machine是一种广泛使用的LabVIEW架构,由JKI公司开发。这种状态机架构在LabVIEW中提供了灵活、可扩展和高效的编程模式,适用于各种复杂的应用场景。JKI State Machine通过状态的定义和切换,实现了程序逻辑的清晰组织和管理&#xff…

C语言 -- 深入理解指针(二)

C语言 -- 深入理解指针(二) 1. 数组名的理解2. 使用指针访问数组3. 一维数组传参的本质4. 冒泡排序5. 二级指针6. 指针数组7. 指针数组模拟二维数组8. 字符指针变量9. 数组指针变量2.1数组指针变量是什么?2.2 数组指针变量怎么初始化 10. 二维…

选择适合的220V转5V电源芯片,220V转5V非隔离降压电源ic

#### 问题: 在设计一个需要将220V交流电转换为5V直流电的电路时,我应该选择哪种型号的电源芯片?我需要输出电流在200mA以内,有没有推荐的型号? #### 答案: 在220V交流电转换为5V直流电的应用中&#xff0c…

经典的layui框架,还有人用吗?令人惋惜。

自从layui官网宣布关闭之后,layui框架的用户飞速下滑,以至于到现在贝格前端工场承接的项目中,鲜有要求使用layui框架的,那么个框架还有人用吗? 一、layui没落是不是jquery惹的祸 layui的没落与jQuery无关。layui框架…

基于springboot+vue+uniapp的贵工程寝室快修小程序

开发语言:Java框架:springbootuniappJDK版本:JDK1.8服务器:tomcat7数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:eclipse/myeclipse/ideaMaven包&#…

(二)、python程序--基金看板

一、绪论 获取基金数据并展示。 已实现功能: 1、获取基金名称以列表的方式展示,可按照类型筛选,也可以直接搜索; 2、点击左侧基金名称展示日线,移动鼠标竖线跟着移动,并且显示对应日期的基金数据&#…

[数仓]三、离线数仓(Hive数仓系统)

第1章 数仓分层 1.1 为什么要分层 DIM:dimensionality 维度 1.2 数据集市与数据仓库概念 1.3 数仓命名规范 1.3.1 表命名 ODS层命名为ods_表名DIM层命名为dim_表名DWD层命名为dwd_表名DWS层命名为dws_表名 DWT层命名为dwt_表名ADS层命名为ads_表名临时表命名为…

植物大战僵尸融合嫁接版 MAC 版本下载安装详细教程

继植物大战僵尸杂交版火了之后,PVZ改版可谓是百花齐放,最近又有一个非常好玩的模式被开发出来了,他们称为《植物大战僵尸融合嫁接版》 该版本并没有对植物卡牌做改动,而是可以将任意两种植物叠放到一起进行融合,产生新…

(附源码)springboot共享单车管理系统-计算机毕设 65154

springboot共享单车管理系统 摘 要 随着科学技术的飞速发展,各行各业都在努力与现代先进技术接轨,通过科技手段提高自身的优势;对于共享单车管理系统当然也不能排除在外,随着网络技术的不断成熟,带动了共享单车管理系…

ES7210高性能四通道音频ADC转换模拟麦克风为IIS数字咪头

特征 高性能多位 Delta-Σ 音频 ADC 102 dB 信噪比 -85 分贝 THDN 24 位,8 至 100 kHz 采样频率 I2S/PCM 主串行数据端口或从串行数据端口 支持TDM 256/384Fs、USB 12/24 MHz 和其他非标准音频系统时钟 低功耗待机模式 应用 麦克风阵列 智能音箱 远场语音捕获 订购…

桑基气泡图 – 5个维度展示KEGG通路富集结果

2022年发表在《Nature communication》上的文章Kir2.1-mediated membrane potential promotes nutrient acquisition and inflammation through regulation of nutrient transporters fig1i使用微生信平台绘制了一张图,我们将其命名为“桑基气泡图”。从此&#xff…

低代码和制造企业数字化转型成功的关系是什么

针对制造企业特别繁多的应用场景、特别大量的数据以及特别复杂的业务流程等特性,低代码能够更贴合制造企业的应用需求,更符合低代码平台为企业带来的价值,即(低代码平台)即服务。 用低代码与平台的融合力量搭建起企业敏捷的数字底座&#xff…

14-22 剑和远方2 - 深度神经网络中的学习机制

概论 在第一部分中,我们深入探讨了人工智能的兴衰简史以及推动人工智能发展的努力。我们研究了一个简单的感知器,以了解其组件以及简单的 ANN 如何处理数据和权重层。在简单的 ANN 中,不会对数据执行特定操作。ANN 中的激活函数是一个线性函…

Node.js_fs模块

文件删除 文件重命名和移动(本质都是修改路径) 文件夹操作 创建文件夹(mkdir) 读取文件夹(readdir) (打印出来是该文件夹下名称的数组形式) 读取当前的文件夹(readdir) 删除文件夹 (rmdir) 查看资源状态…

一家虚拟电厂繁忙的一天

早晨:准备与监控 7:00 AM - 起床与检查 虚拟电厂(VPP)团队的成员早起,开始检查电力系统的状态和最新的市场动态。使用专用的监控软件,查看分布式能源资源(DERs)的实时数据,包括太阳…

【Linux】网络新手村

欢迎来到 破晓的历程的 博客 ⛺️不负时光,不负己✈️ 引言 今天,我们就开始学习Linux网络相关的内容。这篇博客作为Linux网络板块的第一篇博客看,我们首先要带着大家明白Linux网络的一些名词的概念,为之后的学习扫清障碍。然后我…

MMM(Master-Master replication manager for MySQL,MySQL主主复制管理器)

概述 MMM(Master-Master replication manager for MySQL,MySQL主主复制管理器) MMM是一套支持双主故障切换和双主日常管理的脚本程序。MMM 使用 Perl 语言开发,主要用来监控和管理 MySQL Master-Master (双主&#xf…

opencv实现目标检测功能----20240704

早在 2017 年 8 月,OpenCV 3.3 正式发布,带来了高度改进的“深度神经网络”(dnn)模块。 该模块支持多种深度学习框架,包括 Caffe、TensorFlow 和 Torch/PyTorch。这次我们使用Opencv深度学习的功能实现目标检测的功能,模型选用MobileNetSSD_deploy.caffemodel。 模型加载…