FreeRTOS-软件定时器
软件定时器
在FreeRTOS中可以设置无数个软件定时器,都是基于系统滴答中断。
使用软件定时器需要指定时间:启动定时器和运行回调函数。启动定时器和运行回调函数的间隔为定时器的周期。
使用软件定时器需要指定类型:一次性(回调函数只被调用一次,可手动再次启动)或自动加载(回调函数间歇调用)。
使用软件定时器需要指定事件:指定回调函数。
守护任务
FreeRTOS中有一个Tick中断,软件定时器基于Tick来运行。定时器函数一般在中断里执行,如在中断中判断定时器是否超时,如果超时就调用回调函数。
但FreeRTOS是RTOS,不允许在内核、中断中执行不确定的代码(如果定时器函数很耗时会影响整个系统)。所以FreeRTOS中,不在Tick中断中执行定时器函数。
而是在RTOS Damemon Task(RTOS守护任务)里执行。当FreeRTOS配置项configUSE_TIMERS被设置为1,在启动调度器时会自动创建RTOS守护任务。
我们编写的任务函数要使用定时器时,是通过定时器命令队列(timer command queue)和守护任务交互。
守护任务的优先级为:configTIMER_TASK_PRIORITY,定时器命令队列长度为configTIMER_QUEUE_LENGTH。
当守护任务是当前优先级最高的就绪态任务时,它就可以运行。它的工作有两类:
处理命令:从命令队列里取出命令、处理。
执行定时器的回调函数。
能否及时处理定时器的命令、能否及时执行定时器的回调函数,严重依赖于守护任务的优先级。
/* 定时器的回调函数 */ void ATimerCallback( TimerHandle_t xTimer );
定时器的回调函数是在守护任务中被调用的,守护任务不是专为某个定时器服务的,它还要处理其他定时器。所以,定时器的回调函数不能影响其他任务:
回调函数要尽快执行,不能进入阻塞状态。
不用调用会导致阻塞的API函数,如vTaskDelay()。
可以调用xQueueReceive()等函数,但是超时时间要设为0,不阻塞。
创建定时器
TimerHandle_t xTimerCreate( const char * const pcTimerName, // 定时器名字const TickType_t xTimerPeriodInTicks, // 定时器周期, 以Tick为单位const UBaseType_t uxAutoReload, // 定时器是否自动重装载, pdTRUE表示自动加载, pdFALSE表示一次性void * const pvTimerID, // 回调函数可以使用此参数, 比如分辨是哪个定时器TimerCallbackFunction_t pxCallbackFunction ); // 回调函数
/* 返回值: 成功则返回TimerHandle_t, 否则返回NULL */TimerHandle_t xTimerCreateStatic( const char * const pcTimerName, // 定时器名字TickType_t xTimerPeriodInTicks, // 定时器周期, 以Tick为单位UBaseType_t uxAutoReload, // 定时器是否自动重装载, pdTRUE表示自动加载, pdFALSE表示一次性void * pvTimerID, // 回调函数可以使用此参数, 比如分辨是哪个定时器TimerCallbackFunction_t pxCallbackFunction, // 回调函数StaticTimer_t *pxTimerBuffer ); // 传入一个StaticTimer_t结构体, 将在结构体构造定时器
/* 返回值: 成功则返回TimerHandle_t, 否则返回NULL */void ATimerCallback( TimerHandle_t xTimer );
typedef void (* TimerCallbackFunction_t)( TimerHandle_t xTimer );
删除定时器
动态分配的定时器,不再需要时可以删除以回收内存。
/* * xTimer: 要删除哪个定时器* xTicksToWait: 超时时间* 返回值: pdFAIL表示"删除命令"在指定超时时间内无法写入队列* pdPASS表示成功
*/
BaseType_t xTimerDelete( TimerHandle_t xTimer, TickType_t xTicksToWait );
定时器的很多API函数都是通过发送命令到命令队列,由守护任务来实现。如果队列满了,命令就无法立即写入队列,需要指定一个超时时间。
启动定时器
启动定时器就是设置它的状态为运行态。
xTicksToWait不是定时器超时时间,也不是定时器周期。
如果定时器已经被启动,但它的回调函数还没有被执行时,再次执行xTimerStart()函数相当于执行xTimerReset()函数,重新设定它的启动时间。
/* * xTimer: 哪个定时器* xTicksToWait: 超时时间* 返回值: pdFAIL表示"启动命令"在指定超时时间内无法写入队列* pdPASS表示成功*/
BaseType_t xTimerStart( TimerHandle_t xTimer, TickType_t xTicksToWait );/* * xTimer: 哪个定时器* pxHigherPriorityTaskWoken: 向队列发出命令使得守护任务被唤醒,如果守护任务的优先级比当前任务的高,则*pxHigherPriorityTaskWoken = pdTRUE,表示需要进行任务调度* 返回值: pdFAIL表示"启动命令"无法写入队列* pdPASS表示成功*/
BaseType_t xTimerStartFromISR( TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken );
停止定时器
启动定时器就是设置它的状态为睡眠态,让它无法运行。
/* * xTimer: 哪个定时器* xTicksToWait: 超时时间* 返回值: pdFAIL表示"停止命令"在指定超时时间内无法写入队列* pdPASS表示成功*/
BaseType_t xTimerStop( TimerHandle_t xTimer, TickType_t xTicksToWait );/* * xTimer: 哪个定时器* pxHigherPriorityTaskWoken: 向队列发出命令使得守护任务被唤醒,如果守护任务的优先级比当前任务的高,* 则*pxHigherPriorityTaskWoken = pdTRUE,表示需要进行任务调度* 返回值: pdFAIL表示"停止命令"无法写入队列* pdPASS表示成功*/
BaseType_t xTimerStopFromISR( TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken );
复位定时器
使用xTimerReset()函数可以让定时器的状态从睡眠态转换为运行态,相当于使用xTimerStart()函数。
如果定时器已经处于运行态,使用xTimerReset()函数相当于重新确定超时时间。
/* * xTimer: 哪个定时器* xTicksToWait: 超时时间* 返回值: pdFAIL表示"复位命令"在指定超时时间内无法写入队列* pdPASS表示成功*/
BaseType_t xTimerReset( TimerHandle_t xTimer, TickType_t xTicksToWait );/* * xTimer: 哪个定时器* pxHigherPriorityTaskWoken: 向队列发出命令使得守护任务被唤醒,如果守护任务的优先级比当前任务的高,* 则*pxHigherPriorityTaskWoken = pdTRUE,表示需要进行任务调度* 返回值: pdFAIL表示"停止命令"无法写入队列* pdPASS表示成功*/
BaseType_t xTimerResetFromISR( TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken );
修改定时器周期
使用xTimerChangePeriod()函数,除了能修改定时器周期外,还可以让定时器的状态从睡眠态转换为运行态。
修改定时器周期时,会使用新的周期重新计算它的超时时间。
/* 返回值: pdFAIL表示"修改周期命令"在指定超时时间内无法写入队列* pdPASS表示成功*/
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer, /* xTimer: 哪个定时器 */TickType_t xNewPeriod, /* xNewPeriod: 新周期 */TickType_t xTicksToWait ); /* xTicksToWait: 超时时间, 命令写入队列的超时时间 *//* pxHigherPriorityTaskWoken: 向队列发出命令使得守护任务被唤醒,如果守护任务的优先级比当前任务的高,* 则*pxHigherPriorityTaskWoken = pdTRUE,表示需要进行任务调度* 返回值: pdFAIL表示"修改周期命令"在指定超时时间内内无法写入队列* pdPASS表示成功*/
BaseType_t xTimerChangePeriodFromISR( TimerHandle_t xTimer, /* xTimer: 哪个定时器 */TickType_t xNewPeriod, /* xNewPeriod: 新周期 */BaseType_t *pxHigherPriorityTaskWoken );
定时器ID
typedef struct tmrTimerControl
{const char *pcTimerName;ListItem_t xTimerListItem;TickType_t xTimerPeriodInTicks;void *pvTimerID; // 定时器IDTimerCallbackFunction_t pxCallbackFunction;
#if ( configUSE_TRACE_FACILITY == 1 )UBaseType_t uxTimerNumber;
#endifuint8 t ucStatus;
} xTIMER;
怎么使用定时器ID,完全由程序来决定:
可以用来标记定时器,表示自己是什么定时器
可以用来保存参数,供回调函数使用
它的初始值在创建定时器时由xTimerCreate()函数传入,后续可以使用这些函数来操作:
更新ID:使用vTimerSetTimerID()函数
查询ID:使用pvTimerGetTimerID()函数
这两个函数不涉及命令队列,都是直接操作定时器结构体的。
/* * xTimer: 哪个定时器* 返回值: 定时器的ID*/
void *pvTimerGetTimerID( TimerHandle_t xTimer );/* * xTimer: 哪个定时器* pvNewID: 新ID*/
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID );
应用场景:一般使用
应用场景:消除抖动
相关文章:

FreeRTOS-软件定时器
软件定时器 在FreeRTOS中可以设置无数个软件定时器,都是基于系统滴答中断。 使用软件定时器需要指定时间:启动定时器和运行回调函数。启动定时器和运行回调函数的间隔为定时器的周期。 使用软件定时器需要指定类型:一次性(回调函数…...
Lab 3: Recursion, Tree Recursion(CS61A 2020)
在网上没有lab3相应的答案,作者也卡蛮久 (就此补充一下答案) Q2: WWPD: Journey to the Center of the Earth Use Ok to test your knowledge with the following "What Would Python Display?" questions: python3 ok -q sr-ww…...

GVIM 配置 for begin/end class/endclass 等配对
有时候我们的代码很长,或者结构比较复杂,多个if/else 或者begin/end 快嵌套,为了阅读方便,利用gvim插件实现块跳转还是很有实用性的,下面的.vimrc的配置,简单方便。 使用方式: 将光标定位到块头…...

2024不收费的数据恢复软件EasyRecovery16
EasyRecovery2024是一款操作安全、用户可自主操作的数据恢复方案,它支持从各种各样的存储介质恢复删除或者丢失的文件,其支持的媒体介质包括:硬盘驱动器、光驱、闪存、硬盘、光盘、U盘/移动硬盘、数码相机、手机以及其它多媒体移动设备。能恢…...

【每日一题】找出叠涂元素
文章目录 Tag题目来源题目解读解题思路方法一:哈希表 写在最后 Tag 【哈希表】【数组】【2023-12-01】 题目来源 2661. 找出叠涂元素 题目解读 从左往右遍历 arr 给矩阵 mat 上色,在上色的过程中矩阵的某一行或者某一列的全部被上色了,返回…...
Qt面试题
1.QT信号槽机制的优缺点 优点: 1.类型安全:需要关联的信号槽的签名必须是等同的,即信号的参数类型和参数个数和接受该信号的槽的参数类型和参数个数相同。(PS:信号函数的参数个数必须大于等于槽函数的参数个数) 2.松…...

LeetCode:1038. 从二叉搜索树到更大和树(反向中序遍历 C++、Java)
目录 1038. 从二叉搜索树到更大和树 题目描述: 实现代码与解析: dfs 原理思路: 1038. 从二叉搜索树到更大和树 题目描述: 给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所…...

【文末送书】Python OpenCV从入门到精通
文章目录 🍔简介opencv🌹内容简介🛸编辑推荐🎄导读🌺彩蛋 🍔简介opencv OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,提供了丰富的图像处理和…...

RabbitMQ 的七种消息传递形式
文章目录 一、RabbitMQ 架构简介二、准备工作 三、消息收发1. Hello World2. Work queues3. Publish/Subscrite3.1. Direct3.2. Fanout3.3. Topic3.4. Header 4. Routing5. Topics 大部分情况下,我们可能都是在 Spring Boot 或者 Spring Cloud 环境下使用 RabbitMQ&…...

开源免费跨平台数据同步工具-Syncthing
Syncthing是一款开源免费跨平台的文件同步工具,是基于P2P技术实现设备间的文件同步,所以它的同步是去中心化的,即你并不需要一个服务器,故不需要担心这个中心的服务器给你带来的种种限制,而且类似于torrent协议&#x…...
java语言中受检异常和非受检异常的区别是什么?
在Java语言中,异常可以分为两种类型:受检异常(Checked Exception)和非受检异常(Unchecked Exception)。 受检异常(Checked Exception):这是编译器要求必须进行处理的异常…...
vue3 element-plus el-table表头冻结,表头吸顶
一.使用方式 在main.ts页面创建 vue指令 import { createSticky } from /utils/stickyconst app createApp(App)createSticky(app)...app.mount(#app);在el-table标签上使用 v-sticky <div class"table-box"><!--此处的 .table-box 是会出现滚动条的DOM元…...

mysql中删除数据后,新增数据时id会跳跃,主键自增id不连续
引言: 在使用MySQL数据库时,有时候我们需要删除某些记录,但是删除记录后可能会导致表中的id不再连续排序。 如何实现删除记录后让id重新排序的功能。 如图: 删除数据后,中间的id不会自动连续。 下面有两种方法进行重…...

todesk连接ubuntu显示当前系统并无桌面环境,或无显示器,无法显示远程桌面,您需要自行安装X11桌面环境,或者使用终端文件功能
ToDesk远程遇到的问题如上图,换向日葵直接黑屏; 问题原因 截止发文时间,Todesk只支持X11协议,没有适配最新的Wayland协议,所以我们需要把窗口系统调整为X11才可以。 解决方法 修改配置文件,关闭wayland su…...

webpack学习-1.起步
webpack学习-1.起步 1.基础设置2.配置文件的引入3.总结 1.基础设置 首先 webpack是干嘛的呢,用官网的一张图 Webpack 是一个现代的静态模块打包工具。它主要用于将前端应用程序中的各种资源(例如 JavaScript、CSS、图片等)打包成一个或多个…...
GNU Radio 教程
初学者教程 GNU 无线电简介 什么是 GNU 无线电?安装 GNU 无线电你的第一个流程图 流程图基础知识 GRC 中的 Python 变量流程图中的变量运行时更新变量信号数据类型转换数据类型包装位流和向量层次块和参数 创建和修改 Python 块 创建你的第一个块带向量的 Pyt…...

Linux 下命令行启动与关闭WebLogic的相关服务
WebLogic 的服务器类型 WebLogic提供了三种类型的服务器: 管理服务器节点服务器托管服务器 示例和关系如下图: 对应三类服务器, 就有三种启动和关闭的方式。本篇介绍使用命令行脚本的方式启动和关闭这三种类型的服务器。 关于WebLogic 的…...
模型量化相关知识汇总
量化&反量化 量化操作可以将浮点数转换为低比特位数据表示,比如int8和 uint8. Q(x_fp32, scale, zero_point) round(x_fp32/scale) zero_point,量化后的数据可以经过反量化操作来获取浮点数 x_fp32 (Q - zero_point)* scale pytorch中 quantize_per_tensor的解释 py…...
yum 操作,出现Cannot retrieve metalink for repository: epel/x86_64
详细报错如下: Loaded plugins: fastestmirror Determining fastest mirrorsOne of the configured repositories failed (Unknown),and yum doesnt have enough cached data to continue. At this point the onlysafe thing yum can do is fail. There are a few…...

MySQL 8.2 Command Line Client闪退
原因一 服务没有打开 原因二 找不到my.ini文件 原因一的解决方法 操作1进入管理 操作2选择服务 1 2 3 操作3选择MySQL服务并打开 原因二的解决方法 查找目录中是否有my.ini文件 C:\Program Files\MySQL\MySQL Server 8.2(一般在这个目录下) 有时…...

从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...

大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...

循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
线程同步:确保多线程程序的安全与高效!
全文目录: 开篇语前序前言第一部分:线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分:synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分ÿ…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...

家政维修平台实战20:权限设计
目录 1 获取工人信息2 搭建工人入口3 权限判断总结 目前我们已经搭建好了基础的用户体系,主要是分成几个表,用户表我们是记录用户的基础信息,包括手机、昵称、头像。而工人和员工各有各的表。那么就有一个问题,不同的角色…...
将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?
Otsu 是一种自动阈值化方法,用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理,能够自动确定一个阈值,将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

(二)原型模式
原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...

ETLCloud可能遇到的问题有哪些?常见坑位解析
数据集成平台ETLCloud,主要用于支持数据的抽取(Extract)、转换(Transform)和加载(Load)过程。提供了一个简洁直观的界面,以便用户可以在不同的数据源之间轻松地进行数据迁移和转换。…...