08:软件定时器+中断管理

软件定时器+中断管理

  • 1、软件定时器
  • 2、中断管理
    • 2.1、中断屏蔽
    • 2.2、临界区

1、软件定时器

   软件定时器是基于 FreeRTOS 内核提供的时间管理功能实现的,允许开发者创建、启动、停止、删除和管理定时器,从而实现在任务中对时间的灵活控制。

软件定时器硬件定时器
FreeRTOS提供的功能来模拟定时器,依赖系统的任务调度器来进行计时和任务调度由芯片或微控制器提供,独立于 CPU,可以在后台运行,不受任务调度器的影响
精度和分辨率可能受到任务调度的影响具有更高的精度和分辨率
不需要额外的硬件资源,但可能会增加系统的负载占用硬件资源,不会增加 CPU 的负载

  软件定时器服务任务是任务调度器中的一个特殊任务,专门用于管理和维护软件定时器的正常运行。如果configUSE_TIMERS 设置为1,在创建软件定时器时,会自动创建一个软件定时器的服务任务,它主要负责调用超时软件定时器的超时回调函数、处理软件定时器命令队列。既然是任务,那么就需要配置优先级,任务栈大小,和命令队列(用于传递处理软件定时器命令)

使用软件定时器需要添加如下代码

/* 软件定时器相关定义 */
#include "timers.h"				//添加定时器头文件
#define configUSE_TIMERS 1                                          /* 1: 使能软件定时器, 默认: 0。使能后需指定下面3个 */
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1)        /* 定义软件定时器任务的优先级 */
#define configTIMER_QUEUE_LENGTH 5                                  /* 定义软件定时器命令队列的长度*/
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE * 2) /* 定义软件定时器任务的栈空间大小*/

创建软件定时器

/**
 * 函数:创建软件定时器
 * pcTimerName:定时器名字
 * xTimerPeriodInTicks:定时器周期Tick
 * xAutoReload:pdTrue(周期性定时器),pdFalse(一次性)
 * pvTimerID: 定时器ID
 * pxCallbackFunction:定时器回调函数
 * 返回值:TimerHandle_t类型变量,Timer句柄
 */
xTimerCreate(const char * const pcTimerName, 
             const TickType_t xTimerPeriodInTicks,
             const BaseType_t xAutoReload,
             void * const pvTimerID,
             TimerCallbackFunction_t pxCallbackFunction) 	动态方式创建软件定时器
xTimerCreateStatic() 	静态方式创建软件定时器

开启定时器(启动定时器服务任务)

/**
 * 函数:启动软件定时器
 * xTimer:定时器句柄
 * xTicksToWait:等待Tick
 */
xTimerStart(xTimer, xTicksToWait) 	开启软件定时器定时
xTimerStartFromISR() 	在中断中开启软件定时器定时

启动定时器/停止定时器/复位定时器/更改超时时机的这些API函数其实是软件定时器命令,任务函数中调用这些API函数本质上是在给软件定时器的命令队列写入数据。而通过之前的学习就知道,写入队列需要等待Tick,因此这些对软件定时器配置API需要等待Tick。

停止定时器(将定时器任务挂起)

/**
 * 函数:停止软件定时器定时
 * xTimer:定时器句柄
 * xTicksToWait:等待Tick
 */
xTimerStop(xTimer, xTicksToWait) 	停止软件定时器定时
xTimerStopFromISR() 	在中断中停止软件定时器定时

复位定时器

/**
 * 函数:复位软件定时器定时
 * xTimer:定时器句柄
 * xTicksToWait:等待Tick
 */
xTimerReset() 	复位软件定时器定时
xTimerResetFromISR() 	在中断中复位软件定时器定时

更改超时时间

/**
 * 函数:更改软件定时器的定时超时时间
 * xTimer:定时器句柄
 * xNewPeriod:超时Tick
 * xTicksToWait:等待Tick
 */
xTimerChangePeriod(xTimer, xNewPeriod, xTicksToWait) 	更改软件定时器的定时超时时间
xTimerChangePeriodFromISR() 	在中断中更改定时超时时间时

实验
Task1:使用KEY1开启软件定时器,使用KEY2停止软件定时器
定时器超时函数:每隔500ms打印一次
FreeRTOSConfig.h文件添加的代码如下

/* 软件定时器相关定义 */
#define configUSE_TIMERS 1 /* 1: 使能软件定时器, 默认: 0。使能后需指定下面3个 */
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES - 1) /* 定义软件定时器任务的优先级 */
#define configTIMER_QUEUE_LENGTH 5 /* 定义软件定时器命令队列的长度*/
#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE /* 定义软件定时器任务的栈空间大小*/

freertos_demo.c文件添加的代码如下

#include "freertos_demo.h"

void Task1(void * pvParameters);
void TimerCallback(TimerHandle_t xTimer);
/**
 * 入口函数:创建启动任务,启动调度器
 */
TaskHandle_t Task1_Handler,Task2_Handler;   //任务控制块指针
TimerHandle_t Timer_Handle;                 //软件定时器句柄
void FreeRTOS_Start(void)
{   
    Timer_Handle = xTimerCreate("SoftTimer",500,pdTRUE,NULL,TimerCallback);//动态方式创建软件定时器
   
    /* 进入临界区:防止中断打断 */
    vPortEnterCritical();
    
    /* 1、创建任务1 */
    xTaskCreate((TaskFunction_t)Task1,"Task1",128,NULL,1,&Task1_Handler);//优先级为1

    /* 退出临界区 */
    vPortExitCritical();
    
    /* 2、启动调度器 */
    vTaskStartScheduler();//启动了任务调度器,任务就开始运行了,且创建空闲任务。
}

/**
 * 任务函数1:使用KEY定时器的开关
 */
void Task1(void * pvParameters)
{
    while (1)
    {
        if(Key_Scan() == 1)//按键按下
        {
            printf("启动定时器\r\n");
            xTimerStart(Timer_Handle, 0);//启动定时器服务函数
        }
        else if(Key_Scan() == 2)
        {
            printf("关闭定时器\r\n");
            xTimerStop(Timer_Handle, 0);//关闭定时器服务函数
        }
    }
}

/**
 * 定时器超时服务函数
 */
void TimerCallback(TimerHandle_t xTimer)
{
    printf("定时到了!\r\n");
}

在这里插入图片描述

综上:创建出Task1,和软件定时器服务任务后,虽然软件定时器的服务任务优先级大于Task1,但是由于还没有启动定时器服务任务,所以一直执行Task1。当启动后,定时设置的是500Tick,则启动后先将服务任务阻塞500Tick,然后500Tick后恢复,然后去抢占Tick1,执行软件定时器服务任务。大概的软件定时器服务任务函数如下:

void TimerControl(void)
{
    vTaskDelay(TickType_t Ticks);//先阻塞Tick
    ...
    ...
    pxCallbackFunction(TimerHandle_t xTimer);//然后去执行回调函数
}

2、中断管理

2.1、中断屏蔽

   在STM32中,中断优先级是通过中断优先级配置寄存器的高4位 [7:4] 来配置的。因此STM32支持最多16级中断优先级,其中数值越小表示优先级越高,即更紧急的中断。
  FreeRTOS中,将PendSV和SysTick设置最低中断优先级(数值最大,15),保证系统任务切换不会阻塞系统其他中断的响应。
  FreeRTOS利用BASEPRI寄存器实现中断管理,屏蔽优先级低于某一个阈值的中断。比如: BASEPRI设置为0x50(只看高四位,也就是5),代表中断优先级在5 ~ 15内的均可被屏蔽,0~4的中断优先级正常执行。
  而BASEPRI寄存器通过configMAX_SYSCALL_INTERRUPT_PRIORITY宏来设置的,当设置为5时,则0~4中断正常执行,不会被FreeRTOS管理。而5 ~ 15的中断会被FreeRTOS管理。因此可以调用API函数来屏蔽5 ~ 15的中断。
【注】使用configMAX_SYSCALL_INTERRUPT_PRIORITY将BASEPRI配置为0x50后,也只有5~15优先级的中断调用xxxFromISR函数才能执行。
在这里插入图片描述中断屏蔽API

在 portmacro.h 中有定义,如下:
#define portDISABLE_INTERRUPTS()                  vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS()                   vPortSetBASEPRI( 0 )

调用portDISABLE_INTERRUPTS() ,FreeRTOS会关闭管理的所有中断。
调用portENABLE_INTERRUPTS() ,FreeRTOS会打开管理的所有中断。

Q

2.2、临界区

临界段代码,又称为临界区,指的是那些必须在不被打断的情况下完整运行的代码段。例如,某些外设的初始化可能要求严格的时序,因此在初始化过程中不允许被中断打断。
进入/退出临界区API

taskENTER_CRITICAL() :进入临界段。
taskEXIT_CRITICAL() :退出临界段。
taskENTER_CRITICAL_FROM_ISR() :进入临界段(中断级)。
taskEXIT_CRITICAL_FROM_ISR():退出临界段(中断级)。

taskENTER_CRITICAL() :进入临界段。本质是去调用portDISABLE_INTERRUPTS() 。因此使用configMAX_SYSCALL_INTERRUPT_PRIORITY将BASEPRI配置为0x50后。然后进入临界区后5~15的中断都不会打断之后代码的执行(PendSV和SysTick也会停止,任务调度也会停止),直到退出临界区。
【注意】调用多少次进入临界区,就要调用多少次退出临界区。这样才能真正的退出临界区。
实验
设置管理的优先级范围:5~15。
使用两个定时器,一个优先级为4,一个优先级为6。
两个定时器每1s,打印一段字符串,当关中断时,停止打印,开中断时持续打印。

FreeRTOSConfig.h文件中添加如下的代码

/*3. 中断嵌套行为相关配置 cm3内核:我们要求4个优先级位全部为抢占优先级位
     最高优先级是 0
     最低优先级是 15
*/
/* 设置 RTOS 内核自身使用的中断优先级。 一般设置为最低优先级, 不至于屏蔽其他优先级程序*/
#define configKERNEL_INTERRUPT_PRIORITY 0xF0		//优先级15
/* 设置了调用中断安全的 FreeRTOS API 函数的最高中断优先级。 FreeRTOS 的管理的最高优先级 */ 
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 0x50	//5~15
/* 同上. 仅用于新版移植。 这两者是等效的。 */ 
#define configMAX_API_CALL_INTERRUPT_PRIORITY  configMAX_SYSCALL_INTERRUPT_PRIORITY

freertos_demo.c文件的代码如下

#include "freertos_demo.h"

void Task1(void);

TaskHandle_t Task1_Handler;
void FreeRTOS_Start(void)
{
    /* 进入临界区:防止中断打断 */
    vPortEnterCritical();
    /* 1、创建任务1 */
    xTaskCreate((TaskFunction_t)Task1,"Task1",128,NULL,1,&Task1_Handler);
    
    /* 退出临界区 */
	vPortExitCritical();

	/* 2、启动调度器 */
    vTaskStartScheduler();

}

/**
 * 任务1函数:开关中断
 */
void Task1(void)
{
    uint8_t Key = 0;
    while (1)
    {
        Key = Key_Scan();
        /*关闭中断*/
        if(Key == 1)
        {
            printf("关闭中断!\r\n");
            //taskENTER_CRITICAL();
            portDISABLE_INTERRUPTS(); //进入临界区,关闭优先级5~15的所有中断
        }else if(Key == 2)
        {
            printf("开启中断!\r\n");
            //taskEXIT_CRITICAL();
            portENABLE_INTERRUPTS();//退出临界区,开启优先级5~15的所有中断

        }  
			//vTaskDelay(500); //这里不能有延时,因为代码底层有关闭中断和开启中断
    }
}

stm32f1xx_it.c文件的代码如下:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  /* USER CODE BEGIN Callback 0 */

  /* USER CODE END Callback 0 */
  if (htim->Instance == TIM4) {
    HAL_IncTick();
  }
  /* USER CODE BEGIN Callback 1 */
  else if(htim->Instance == TIM2)//是定时器2
  {
       printf("TIM2的优先级为4!\r\n");
  }
  else if(htim->Instance == TIM3)//是定时器3
  {
       printf("TIM3的优先级为6!\r\n");
   }
  /* USER CODE END Callback 1 */
}

在这里插入图片描述

【注意】此实验将SysTick中断的优先级配置 < 5。不然在进入临界区后想退出临界区就不可能了。因为若Tick中断依然是15,进入临界区就会关闭Tick中断,即FreeRTOS代码就停止运行了,按下KEY2将无任何反应。

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

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

相关文章

数据结构《MapSet哈希表》

文章目录 一、搜索树1.1 定义1.2 模拟实现搜索 二、Map2.1 定义2.2 Map.Entry2.3 TreeMap的使用2.4 Map的常用方法 三、Set3.1 定义3.2 TreeSet的使用3.3 Set的常用方法 四、哈希表4.1 哈希表的概念4.2 冲突4.2.1 冲突的概念4.2.2 冲突的避免1. 选择合适的哈希函数2. 负载因子调…

蓝桥与力扣刷题(709 转换成小写字母)

题目&#xff1a;给你一个字符串 s &#xff0c;将该字符串中的大写字母转换成相同的小写字母&#xff0c;返回新的字符串。 示例 1&#xff1a; 输入&#xff1a;s "Hello" 输出&#xff1a;"hello"示例 2&#xff1a; 输入&#xff1a;s "here…

unity学习16:unity里向量的计算,一些方法等

目录 1 unity里的向量&#xff1a; 2 向量加法 2.1 向量加法的几何意义 2.2向量加法的标量算法 3 向量减法 3.1 向量减法的几何意义 3.2 向量减法的标量算法 4 向量的标量乘法 5 向量之间的乘法要注意是左乘 还是右乘 5.1 注意区别 5.2 向量&#xff0c;矩阵&#x…

算法3(力扣83)-删除链表中的重复元素

1、题目&#xff1a;给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 2、实现&#xff08; 因为已排序&#xff0c;所以元素若重复&#xff0c;必然在其下一位&#xff09;&#xff08;这里为在vscod…

深度学习基础知识

深度学习是人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09;领域的一个重要分支&#xff0c;以下是对深度学习基础知识的归纳&#xff1a; 一、定义与原理 定义&#xff1a;深度学习是一种使计算机能够从经验中学习并以概念层次结构的方式理解世界的机…

基于mediapipe的手势游戏控制

基于mediapipe的手势游戏控制 ​ 玩游戏&#xff0c;那不是有手就行!!! mediapipe介绍 ​ Mediapipe是Google在2019年开发并提出的一款开源的跨平台多媒体处理框架&#xff0c;用于构建基于机器学习的应用程序&#xff0c;特别是涉及到计算机视觉、音频处理、姿势估计等领域。…

015: 深度学习之正向传播和反向传播

本文为合集收录&#xff0c;欢迎查看合集/专栏链接进行全部合集的系统学习。 合集完整版请参考这里。 上一节介绍了训练和推理的概念&#xff0c;这一节接着训练和推理的概念讲一下&#xff0c;神经网络的正向传播和反向传播。 正反向传播 其实单看正向传播和反向传播这两个…

2025.1.15——二、字符型注入

一、基本操作&#xff1a;整理已知信息&#xff0c;本题为字符型注入 二、解题步骤 step 1&#xff1a;确认为字符型注入 键入&#xff1a; 1 键入&#xff1a;1 and 12 # 发现报错 键入&#xff1a;1 and 11 # 未发现报错 所以确认为字符型注入 step 2&#xff1a;查询…

UML系列之Rational Rose笔记四:时序图(顺序图_序列图)

时序图有很多画法&#xff0c;这基本上能算rose里面要求最乱的一种图了&#xff1b;有些人的需求是BCE模式&#xff0c;这是正常规范点的&#xff0c;有些人就不需要&#xff0c;有些需要用数据库交互&#xff0c;有些不需要&#xff1b;没有一个较为统一的需求&#xff1b;在此…

LabVIEW水位监控系统

LabVIEW开发智能水位监控系统通过集成先进的传感技术与控制算法&#xff0c;为工业液体存储提供精确的水位调控&#xff0c;保证了生产过程的连续性与安全性。 项目背景 在化工和饮料生产等行业中&#xff0c;水位控制的准确性对保证生产安全和提高产品质量至关重要。传统的水…

STC的51单片机LED点灯基于KEIL

前言&#xff1a; 该文源于回答一个朋友的问题&#xff0c;代码为该朋友上传&#xff0c;略作修改&#xff0c;在此说明问题以及解决问题的思路&#xff0c;以减少新手错误。 电路图&#xff1a; 该位朋友未上传电路图&#xff0c;说明如下&#xff1a; stc8g1k08a-sop8控制…

基于YOLOv8的卫星图像中船只检测系统

基于YOLOv8的卫星图像中船只检测系统 (价格90) 使用的是 MASATI-V2 数据集 训练集 3617张 验证集 452张 测试集 453张 包含 [boat] [船只] 1个类 通过PYQT构建UI界面&#xff0c;包含图片检测&#xff0c;视频检测&#xff0c;摄像头实时检测。 &#xff08;该系…

用 Python 自动化处理日常任务

&#x1f496; 欢迎来到我的博客&#xff01; 非常高兴能在这里与您相遇。在这里&#xff0c;您不仅能获得有趣的技术分享&#xff0c;还能感受到轻松愉快的氛围。无论您是编程新手&#xff0c;还是资深开发者&#xff0c;都能在这里找到属于您的知识宝藏&#xff0c;学习和成长…

mac intel芯片下载安卓模拟器

一、调研 目前主流两个模拟器&#xff1a; 雷神模拟器 不支持macosmumu模拟器pro版 不支持macos intel芯片 搜索到mumu的Q&A中有 “Intel芯片Mac如何安装MuMu&#xff1f;” q&a&#x1f517;&#xff1a;https://mumu.163.com/mac/faq/install-on-intel-mac.html 提…

python中的RPA->playwright自动化录制脚本实战案例笔记

playwright录制功能使用绕过登录操作 1、首先安装playwright pip install playwright2、 安装支持的浏览器 playwright install # 安装支持的浏览器&#xff1a;cr, chromium, ff, firefox, wk 和 webkit3、接着在自己的项目下运行录制命令&#xff1a; playwright codegen…

【原创】大数据治理入门(2)《提升数据质量:质量评估与改进策略》入门必看 高赞实用

提升数据质量&#xff1a;质量评估与改进策略 引言&#xff1a;数据质量的概念 在大数据时代&#xff0c;数据的质量直接影响到数据分析的准确性和可靠性。数据质量是指数据在多大程度上能够满足其预定用途&#xff0c;确保数据的准确性、完整性、一致性和及时性是数据质量的…

数据结构(Java版)第八期:LinkedList与链表(三)

专栏&#xff1a;数据结构(Java版) 个人主页&#xff1a;手握风云 目录 一、链表中的经典面试题 1.1. 链表分割 1.2. 链表的回文结构 1.3. 相交链表 1.4. 环形链表 一、链表中的经典面试题 1.1. 链表分割 题目中要求不能改变原来的数据顺序&#xff0c;也就是如上图所示。…

ASP.NET Core - 配置系统之自定义配置提供程序

ASP.NET Core - 配置系统之自定义配置提供程序 4. 自定义配置提供程序IConfigurationSourceIConfigurationProvider 4. 自定义配置提供程序 在 .NET Core 配置系统中封装一个配置提供程序关键在于提供相应的 IconfigurationSource 实现和 IConfigurationProvider 接口实现&…

MPLS原理及配置

赶时间可以只看实验部分 由来&#xff1a;90年代中期&#xff0c;互联网流量的快速增长。传统IP报文依赖路由器查询路由表转发&#xff0c;但由于硬件技术存在限制导致转发性能低&#xff0c;查表转发成为了网络数据转发的瓶颈。 因此&#xff0c;旨在提高路由器转发速度的MPL…

【韩顺平Java笔记】第8章:面向对象编程(中级部分)【327-337】

327. 断点调试&#xff08;Debug&#xff09; 一个实际需求 在开发中&#xff0c;程序员在查找错误时&#xff0c;可用断点模式在断点调试过程中&#xff0c;是运行状态&#xff0c;是以对象的运行类型来执行的。 A extends B; B b new A(); b.xx();//按照运行类型来执行的 …