STM32F1+HAL库+FreeTOTS学习5——内核中断管理及中断控制函数

STM32F1+HAL库+FreeTOTS学习5——中断管理和临界段代码保护

  • 中断简介
  • 中断优先级寄存器拓展
  • FreeRTOS中PendSV和Systick中断优先级配置
  • 三个中断屏蔽寄存器
  • FreeRTOS中断管理函数
  • 代码验证

上一期我们学习了FreeRTOS中任务挂起与恢复,在中断服务程序中恢复任务过程中,尤其强调了中断必须设置优先级在5-15之间,且中断优先级分组为4,这是为什么呢,让我们一起来探索一些吧。

中断简介

关于STM32中中断的基本概念,我这里就不做赘述了,可以参考 :夜深人静学32系列10——GPIO中断/NVIC/EXTI/SYSCFG详解,外部中断控制LED ,这里只介绍几个重要的内容。

中断优先级寄存器拓展

  1. 中断优先级

在CreteX-M3/4/7的内核中,一个支持16(内核中断)和最多240和外部中断输入,每个中断都有八个位来控制其优先级,理论上最大优先级可以达到256,但是其具体值都是由芯片厂商根据需求裁剪提供给用户的。
在这里插入图片描述

我们本次使用的STM32F103RCT6的芯片,它的中断控制器(NVIC)一共支持68种外部中断,不包含Cretex-M3自带的16个内核中断,同时支持16个可编程中断优先级(使用4为中断优先级)

在这里插入图片描述

  • 这里需要注意:中断优先级和FreeRTOS中任务优先级概念不同
  • 中断优先级数字越小,优先级越高
  • FreeRTOS任务优先级数字越大,优先级越高。
    在这里插入图片描述
  1. 系统异常优先级寄存器
    在Cretex-M3内核中,除了240个外部中断优先级寄存器(实际上是八个32位寄存器,最后一个没用完),还有三个系统内核中断优先级寄存器:SHPR1、SHPR2、SHPR3
    在这里插入图片描述

FreeRTOS中PendSV和Systick中断优先级配置

前面我们有讲过FreeRTOS的一个重要作用就是实现多任务运行,但其实同一时刻只有一个任务在运行,只不过任务之间切换速度很快,给人一种多任务同时运行的假象。那么这里面有两个很重要的东西,一个时心跳节拍和任务调度。分别由Systick中断和PendSV中断来控制。

  1. SysTick中断:FreeRTOS中有自己独立的时钟,同时我们之前学习过一个时间片的概念,即每个任务执行的时间,当时间片用完,就会产生一个Systick中断,里面会重新开启任务调度,执行优先级最高的任务,像这样,每经过一个时间片,系统就会重新选择需要运行的任务,我们把它叫做心跳节拍,心跳节拍的频率由宏:configTICK_RATE_HZ 决定,单位为HZ,比如设置为1000,则表示一个时间片长度为1ms。
  2. PendSV中断:PendSV则是用来完成任务切换功能,所需要的中断。
  3. 在FreeRTOS中,PendSV和Systick的中断优先级都被设置位15,即最低优先级,避免任务切换阻塞系统其他的中断相应。其原理就是操作了SHPR3寄存器。

三个中断屏蔽寄存器

三个中断屏蔽寄存器,分别为 PRIMASK、 FAULTMASK 和BASEPRI

在这里插入图片描述

  • FreeRTOS所使用的中断管理就是利用的BASEPRI这个寄存器
  • BASEPRI:屏蔽优先级低于某一个阈值的中断
  • BASEPRI设置为0x50,代表中断优先级在5 - 15内的均被屏蔽,0 - 4的中断优先级正常执行
  • 这里设置0x50,屏蔽优先级在5以上的任务是因为BASEPRI寄存器只使用了位【7:4】,其中【3:0】是没有使用的。

FreeRTOS中断管理函数

  1. 关中断函数
	portDISABLE_INTERRUPTS();printf("屏蔽中断5-15\r\n");
/*
屏蔽优先级为5 - 15的中断
*/
  1. 开中断服务函数
	portENABLE_INTERRUPTS();printf("开启中断5-15\r\n");/*
开启所有中断相应。
*/

在这里插入图片描述

代码验证

下面是任务要求

在这里插入图片描述

定时器配置,其他配置和代码参考上一期内容: STM32F1+HAL库+FreeTOTS学习4——任务挂起与恢复

在这里插入图片描述

下面是代码实现部分,只展示逻辑部分,和定时器中断相关代码

  1. main.c

/*
这里开启了定时器中断和进入FreeRTOS系统
*/int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();MX_TIM5_Init();MX_TIM6_Init();/* USER CODE BEGIN 2 */HAL_TIM_Base_Start_IT(&htim5);	//开启定时10中断HAL_TIM_Base_Start_IT(&htim6);	//开启定时器11中断freertos_demo();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}/*
这里负责定时器打印
*//*** @brief  Period elapsed callback in non blocking mode* @note   This function is called  when TIM4 interrupt took place, inside* HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment* a global variable "uwTick" used as application time base.* @param  htim : TIM handle* @retval None*/
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 */if(htim->Instance == TIM5){printf("TIM5优先级4打印\r\n");}if(htim->Instance == TIM6){printf("TIM6优先级6打印\r\n");}/* USER CODE END Callback 1 */
}
  1. key.c
/* USER CODE BEGIN 2 */#include "freertos_demo.h"
#include "key.h"
#include "usart.h"
void Key0_Down_Task(void)
{portDISABLE_INTERRUPTS();printf("屏蔽中断5-15\r\n");
}
void Key0_Up_Task(void)
{}
void Key1_Down_Task(void)
{portENABLE_INTERRUPTS();printf("开启中断5-15\r\n");
}
void Key1_Up_Task(void)
{vTaskResume(Task1Task_Handler);  
}
void Key2_Down_Task(void)
{}
void Key2_Up_Task(void)
{}
void WKUP_Down_Task(void)
{}
void WWKUP_Up_Task(void)
{}void Key_One_Scan(uint8_t KeyName ,void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void))
{static uint8_t Key_Val[Key_Name_Max];    //按键值的存放位置static uint8_t Key_Flag[Key_Name_Max];   //KEY0~2为0时表示按下,为1表示松开,WKUP反之Key_Val[KeyName] = Key_Val[KeyName] <<1;  //每次扫描完,将上一次扫描的结果左移保存switch(KeyName){case Key_Name_Key0:  Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin));    //读取Key0按键值break;case Key_Name_Key1:  Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin));   //读取Key1按键值break;case Key_Name_Key2:  Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin));   //读取Key2按键值break;
//        case Key_Name_WKUP:  Key_Val[KeyName] = Key_Val[KeyName] | (HAL_GPIO_ReadPin(WKUP_GPIO_Port, WKUP_Pin));   //读取WKUP按键值
//            break; default:break;}
//    if(KeyName == Key_Name_WKUP)     //WKUP的电路图与其他按键不同,所以需要特殊处理
//    {
//        //WKUP特殊情况
//        //当按键标志为1(松开)是,判断是否按下,WKUP按下时为0xff
//        if(Key_Val[KeyName] == 0xff && Key_Flag[KeyName] == 1)
//        {
//            (*OnKeyOneDown)();
//           Key_Flag[KeyName] = 0;
//        }
//        //当按键标志位为0(按下),判断按键是否松开,WKUP松开时为0x00
//        if(Key_Val[KeyName] == 0x00 && Key_Flag[KeyName] == 0)
//        {
//            (*OnKeyOneUp)();
//           Key_Flag[KeyName] = 1;
//        } 
//    }
//    else                               //Key0~2按键逻辑判断
//    {//Key0~2常规判断//当按键标志为1(松开)是,判断是否按下if(Key_Val[KeyName] == 0x00 && Key_Flag[KeyName] == 1){(*OnKeyOneDown)();Key_Flag[KeyName] = 0;}//当按键标志位为0(按下),判断按键是否松开if(Key_Val[KeyName] == 0xff && Key_Flag[KeyName] == 0){(*OnKeyOneUp)();Key_Flag[KeyName] = 1;}  }//}
/* USER CODE END 2 */
  1. key.h
/* Includes ------------------------------------------------------------------*/
#include "main.h"/* USER CODE BEGIN Includes *//* USER CODE END Includes *//* USER CODE BEGIN Private defines */
typedef enum{Key_Name_Key0 = 0,Key_Name_Key1,Key_Name_Key2,Key_Name_WKUP,Key_Name_Max}EnumKeyOneName;/* USER CODE END Private defines */void MX_GPIO_Init(void);/* USER CODE BEGIN Prototypes */
void Key0_Down_Task(void);void Key0_Up_Task(void);void Key1_Down_Task(void);void Key1_Up_Task(void);void Key2_Down_Task(void);void Key2_Up_Task(void);void WKUP_Down_Task(void);void WWKUP_Up_Task(void);void Key_One_Scan(uint8_t KeyName ,void(*OnKeyOneUp)(void), void(*OnKeyOneDown)(void)); 
/* USER CODE END Prototypes */#ifdef __cplusplus
}
#endif /*__ GPIO_H__ */
  1. freertso_demo.c
#include "freertos_demo.h"
#include "main.h"
/*FreeRTOS*********************************************************************************************/#include "key.h"
/******************************************************************************************************/
/*FreeRTOS配置*//* START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 *//* TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO      1                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 *//* TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO      1                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
void task2(void *pvParameters);             /* 任务函数 *//******************************************************************************************************//* LCD刷屏时使用的颜色 *//*** @brief       FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{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       start_task* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           /* 进入临界区,关闭中断,此时停止任务调度*//* 创建任务1 */xTaskCreate((TaskFunction_t )task1,(const char*    )"task1",(uint16_t       )TASK1_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK1_PRIO,(TaskHandle_t*  )&Task1Task_Handler);/* 创建任务2 */xTaskCreate((TaskFunction_t )task2,(const char*    )"task2",(uint16_t       )TASK2_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK2_PRIO,(TaskHandle_t*  )&Task2Task_Handler);vTaskDelete(StartTask_Handler); /* 删除开始任务 */taskEXIT_CRITICAL();            /* 退出临界区,重新开启中断,开启任务调度 */
}/*** @brief       task1* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void task1(void *pvParameters)
{while(1){HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);  /* LED0闪烁 */vTaskDelay(1000);                                               /* 延时1000ticks */}
}/*** @brief       task2* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void task2(void *pvParameters)
{while(1){		Key_One_Scan(Key_Name_Key0,Key0_Up_Task,Key0_Down_Task);         //扫描Key0状态Key_One_Scan(Key_Name_Key1,Key1_Up_Task,Key1_Down_Task);         //扫描Key1状态Key_One_Scan(Key_Name_Key2,Key2_Up_Task,Key2_Down_Task);         //扫描Key2状态}
}

总结下来代码基本上和上一期内容没有变化,只是在按键扫描到后的功能上发生了改变。运行结果如下:

在这里插入图片描述

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

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

相关文章

[Redis]哨兵机制

哨兵机制概念 在传统主从复制机制中&#xff0c;会存在一些问题&#xff1a; 1. 主节点发生故障时&#xff0c;进行主备切换的过程是复杂的&#xff0c;需要人工参与&#xff0c;导致故障恢复时间无法保障。 2. 主节点可以将读压力分散出去&#xff0c;但写压力/存储压力是无法…

印章谁在管、谁用了、用在哪?契约锁让您打开手机一看便知

“印章都交给谁在管”、“哪些人能用”、“都有哪些业务在用”…这些既是管理者最关心的印章问题也是影响印章安全的关键要素。但是公司旗下分子公司那么多&#xff0c;各类公章、法人章、财务章、合同章一大堆&#xff0c;想“问”明白很难。 契约锁电子签及印控平台推出“印章…

14-11 2024 年的 13 个 AI 趋势

2024 年的 13 个 AI 趋势 人工智能对环境的影响和平人工智能人工智能支持的问题解决和决策针对人工智能公司的诉讼2024 年美国总统大选与人工智能威胁人工智能、网络犯罪和社会工程威胁人工智能治疗孤独与对人工智能的情感依赖人工智能影响者中国争夺人工智能霸主地位人工智能…

YOLOv10全网最新创新点改进系列:融合GSConv+Slim Neck,双改进、双增强,替换特征融合层实现, 轻量化涨点改进策略,有效涨点神器!

YOLOv10全网最新创新点改进系列&#xff1a;融合GSConvSlim Neck&#xff0c;双改进、双增强&#xff0c;替换特征融合层实现&#xff0c; 轻量化涨点改进策略&#xff0c;有效涨点神器&#xff01; 所有改进代码均经过实验测试跑通&#xff01;截止发稿时YOLOv10已改进40&…

【数据结构】06.栈队列

一、栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。栈中的数据元素遵守后进先出LIFO&#xff08;Last In First Out)的原则。 压栈&#…

LangChain终极内幕指南,学会langchain就看它了

1.概述 在人工智能迅速演进的时代&#xff0c;诸如Open AI的ChatGPT和Google的Bard等大型语言模型(LLMs)正彻底改变我们与技术互动的方式。这些技术巨头和SaaS公司正在竞相利用LLMs的威力&#xff0c;创造更为智能和实用的应用程序。 然而&#xff0c;真正的变革并非仅仅停留…

Finding and exploting an unused API endpoint

Using 0$ account buy a piece of lether priced at $133 1、尝试访问api接口 大概率可能访问不到,但是可以尝试访问下 /api/swagger/v1 /openapi.json 2、页面功能点寻找 api send to Repeter 3、Find Supported HTTP请求 POST方法测试 通过测试得知支持GET方法和PATC…

系统管理(System Keeping):全新迭代,优化您的开发体验

随着科技的不断进步和用户需求的日益增长&#xff0c;系统管理&#xff08;System Keeping&#xff09;不断进行迭代更新&#xff0c;致力于为用户带来更加高效、便捷的开发体验。本次全新迭代&#xff0c;不仅在界面与交互上进行了革新&#xff0c;更在功能整合、个性化与安全…

Android --- Service

出自于此&#xff0c;写得很清楚。关于Android Service真正的完全详解&#xff0c;你需要知道的一切_android service-CSDN博客 出自【zejian的博客】 什么是Service? Service(服务)是一个一种可以在后台执行长时间运行操作而没有用户界面的应用组件。 服务可由其他应用组件…

万字长文|关于 OpenAI 接口开发你应该知道的一切

这篇文章中个人结合自己的实践经验把 OpenAI 官方文档解读一遍。但是原文档涉及内容众多&#xff0c;包括微调&#xff0c;嵌入&#xff08;Embeddings&#xff09;等众多主题&#xff0c;我这里重点挑选自己开发高频使用到的&#xff0c;需要详细了解的可以自行前往官网阅读。…

2024科技文化节程序设计竞赛

补题链接 https://www.luogu.com.cn/contest/178895#problems A. 签到题 忽略掉大小为1的环&#xff0c;答案是剩下环的大小和减环的数量 #include<bits/stdc.h> #include<iostream> #include<cstdio> #include<vector> #include<map> #incl…

c进阶篇(四):内存函数

内存函数以字节为单位更改 1.memcpy memcpy 是 C/C 中的一个标准库函数&#xff0c;用于内存拷贝操作。它的原型通常定义在 <cstring> 头文件中&#xff0c;其作用是将一块内存中的数据复制到另一块内存中。 函数原型&#xff1a;void *memcpy(void *dest, const void…

多模态融合算法应用:CT + 临床文本数据 + pyradiomics提取到的图像特征

多模态融合算法应用 CT 临床文本数据 pyradiomics提取图像特征 单模态建模临床数据建模pyradiomics提取图像特征建模CT建模 多模态建模前融合为什么能直接合并在一起&#xff1f; 后融合Med-CLIP&#xff1a;深度学习 可解释性 单模态建模 临床数据建模 临床文本数据&…

WPF Menu实现快捷键操作

很多小伙伴说&#xff0c;在Menu中&#xff0c;实现单个快捷键操作很简单&#xff0c;怎么实现多个快捷键操作和&#xff0c;组合快捷键呢&#xff0c;今天他来了。 上代码和效果图 一、Ctrl Shift 任意子母键实现快捷键组合 <Window x:Class"XH.TemplateLesson.M…

【测试开发】【postman】按顺序循环执行接口

postman按顺序循环执行接口 新建接口接口排序执行请求集合 新建接口 Request 001 Request 002 Request 003 接口排序 在Request 001的Tests中添加代码 postman.setNextRequest("Request 002");在Request 002的Tests中添加代码 postman.setNextRequest("Requ…

Redis 7.x 系列【17】四种持久化策略

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 概述2. 案例演示2.1 无持久化2.2 RDB2.3 AOF2.4 混合模式2.4.1 方式一&#xff1a;…

线性代数|机器学习-P21概率定义和Markov不等式

文章目录 1. 样本期望和方差1.1 样本期望 E ( X ) \mathrm{E}(X) E(X)1.2 样本期望 D ( X ) \mathrm{D}(X) D(X) 2. Markov 不等式&Chebyshev不等式2.1 Markov不等式公式 概述2.2 Markov不等式公式 证明&#xff1a;2.3 Markov不等式公式 举例&#xff1a;2.4 Chebyshev不…

AI绘画 Stable Diffusion图像的脸部细节控制——采样器全解析

大家好&#xff0c;我是画画的小强 我们在运用AI绘画 Stable Diffusion 这一功能强大的AI绘图工具时&#xff0c;我们往往会发现自己对提示词的使用还不够充分。在这种情形下&#xff0c;我们应当如何调整自己的策略&#xff0c;以便更加精确、全面地塑造出理想的人物形象呢&a…

域环境提权

域内提权漏洞(1) Netlogon域权限提升 1.查看域控主机名称 net group "domain controllers" /domain 2.检测漏洞是否存在 https://github.com/SecuraBV/CVE-2020-1472.git python zerologon_tester.py OWA 192.168.52.138 3.漏洞利用&#xff0c;对域账号重置 ht…

《简历宝典》01 - 一文带你学会如何写一份糟糕透顶的简历

我们每个人几乎都会面对找工作这件事&#xff0c;而找工作或者说求职首先就是要写一份简历。今天狗哥将以一个不同的视角带你写一份无与伦比&#xff0c;糟糕透顶的求职简历&#xff0c;说实话&#xff0c;其实几年前&#xff0c;我就是这么写的。 目录 1. 文件名 2. 基本信…