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

news2024/11/18 16:42:45

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.coloradmin.cn/o/1896724.html

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

相关文章

利用谷歌云serverless代码托管服务Cloud Functions构建Gemini Pro API

谷歌在2024年4月发布了全新一代的多模态模型Gemini 1.5 Pro&#xff0c;Gemini 1.5 Pro不仅能够生成创意文本和代码&#xff0c;还能理解、总结上传的图片、视频和音频内容&#xff0c;并且支持高达100万tokens的上下文。在多个基准测试中表现优异&#xff0c;性能超越了ChatGP…

竞赛选题 协同过滤电影推荐系统

文章目录 1 简介1 设计概要2 课题背景和目的3 协同过滤算法原理3.1 基于用户的协同过滤推荐算法实现原理3.1.1 步骤13.1.2 步骤23.1.3 步骤33.1.4 步骤4 4 系统实现4.1 开发环境4.2 系统功能描述4.3 系统数据流程4.3.1 用户端数据流程4.3.2 管理员端数据流程 4.4 系统功能设计 …

【Proteus】按键的实现『⒉种』

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

13-错误-ERROR: duplicate key value violates unique constraint “ux_xxx“

13-错误-ERROR: duplicate key value violates unique constraint “ux_xxx” 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯…

Vite: Bundler实现JavaScript的AST解析器—词法分析、语义分析

概述 基于前文&#xff0c;我们写了一个迷你版的 no-bundle 开发服务&#xff0c;也就是 Vite 开发阶段的 Dev Server&#xff0c;而在生产环境下面&#xff0c;处于页面性能的考虑&#xff0c;Vite 还是选择进行打包(bundle)&#xff0c;并且在底层使用 Rollup 来完成打包的过…

liunx清理服务器内存和日志

1、查看服务器磁盘占用情况 # 查看磁盘占用大小 df -h 2、删除data文件夹下面的日志 3、查看每个服务下面的日志输出文件&#xff0c;过大就先停掉服务再删除out文件再重启服务 4、先进入想删除输入日志的服务文件夹下&#xff0c;查看服务进程&#xff0c;杀掉进程&#xff…

【算法】(C语言):二分查找

二分查找&#xff1a; 获取查找区域的中间位置。若中间位置的数据就是要找的值&#xff0c;则返回true。若要找的值 小于 中间位置的数据&#xff0c;则往左边查找。若要找的值 大于 中间位置的数据&#xff0c;则往右边查找。重复1和2&#xff0c;若没有要找的值&#xff0c;…

Mall,正在和年轻人重新对话

【潮汐商业评论/原创】 结束了一下午的苦闷培训&#xff0c;当Cindy赶到重庆十字大道时&#xff0c;才发现十字路口上的巨大“飞行棋”在前两天就已经撤展了。 “来了又错过&#xff0c;就会觉得遗憾&#xff0c;毕竟这样的路口不多&#xff0c;展陈又不可能会返场。” 飞行棋…

【机器学习】机器学习在AI Agent中的影响与作用

文章目录 &#x1f680;Al Agent是什么&#x1f4d5;Al Agent的工作原理与技术&#x1f4aa;Al Agent应用领域&#x1f680;智能家居应用&#x1f308;医疗健康领域⭐金融服务行业&#x1f302;交通运输管理&#x1f3ac;教育培训应用 &#x1f512;Al Agent优势与挑战✊Al Age…

苹果获得OpenAI董事会观察员职位、Runway最新估值40亿美元

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 据知情人士透露&#xff0c;苹果应用商店&#xff08;App Store&#xff09;负责人、前营销主管Phil Schiller被选中担任这一职位。这位知情人士说&#xff0c;作为董事会观察员&#xff0c;他不会以正…

【综合能源】计及碳捕集电厂低碳特性及需求响应的综合能源系统多时间尺度调度模型

目录 1 主要内容 2 部分程序 3 实现效果 4 下载链接 1 主要内容 本程序是对《计及碳捕集电厂低碳特性的含风电电力系统源-荷多时间尺度调度方法》方法复现&#xff0c;非完全复现&#xff0c;只做了日前日内部分&#xff0c;并在上述基础上改进升级为电热综合电源微网系统&…

【uni-app】基础

一、官网 网址&#xff1a;https://zh.uniapp.dcloud.io/tutorial/其他辅助网页讲解&#xff1a;https://www.wenjiangs.com/doc/7y94pldun2插件下载free&#xff1a;https://ext.dcloud.net.cn/ 二、提示框 用uni.showToast提醒的次数超过7个字的时候就会导致文字显示不全&…

SSL证书遇到问题时的解决方案

当SSL证书遇到问题时&#xff0c;可能会影响到网站的安全性和用户体验&#xff0c;常见的问题包括证书过期、域名不匹配、证书链不完整、证书颁发机构不受信任、私钥丢失或损坏等。 一、证书过期 解决方法&#xff1a;更新或续订证书。这通常涉及联系你的SSL证书提供商&#…

ACL 2024 | CoCA:自注意力的缺陷与改进

近年来&#xff0c;在大语言模型&#xff08;LLM&#xff09;的反复刷屏过程中&#xff0c;作为其内核的 Transformer 始终是绝对的主角。然而&#xff0c;随着业务落地的诉求逐渐强烈&#xff0c;有些原本不被过多关注的特性&#xff0c;也开始成为焦点。例如&#xff1a;在 T…

Shopee Live的订单量在泰国猛增超40倍!然鹅,泰国站佣金费率上调,还有得做吗?

Shopee&#xff0c;作为东南亚地区电子商务领域的佼佼者&#xff0c;不仅在区域内树立了行业标杆&#xff0c;更在泰国这一充满活力的市场中占据了举足轻重的地位。其创新的商业模式与不断优化的服务体验&#xff0c;赢得了广大消费者的青睐与信赖。近日&#xff0c;Shopee官方…

合成孔径雷达原理与应用(四)

合成孔径雷达原理与应用&#xff08;四&#xff09; 2. 应用2.7. 沉降形变滑坡2.7.1. 地面沉降2.7.2. 铁路沉降2.7.3. 大坝形变2.7.4. 机场形变2.7.5. 桥梁形变2.7.6. 滑坡监测 2. 应用 2.7. 沉降形变滑坡 2.7.1. 地面沉降 由图2-17可知&#xff0c;从整体的区域分布上来看&a…

iPad手写笔哪款比较好?2024五款爆火iPad电容笔推荐!新手必看!

在iPad等触控设备日益普及的今天&#xff0c;手写笔作为提升生产力和创意表达的重要工具&#xff0c;正受到越来越多用户的青睐。然而&#xff0c;随着市场需求的激增&#xff0c;市面上电容笔品牌与型号繁多&#xff0c;跟风购买往往容易遭遇“踩雷”情况。因此&#xff0c;作…

认识不-物联网“六域模型”有哪些有什么作用

如下参考源于苏州稳联授权可见认知域-感知域-网络域-应用域-管理域-安全域-物联网六域模型 苏州稳联 (iotrouter.cn) 认识物联网“六域模型”&#xff1a;构成与作用 “六域模型”是一个有效的框架。这个模型通过将物联网划分为六个相互关联的域&#xff0c;帮助我们更好地理…

docker介绍与详细安装

1 docker 介绍 1.1 虚拟化 在计算机中&#xff0c;虚拟化&#xff08;英语&#xff1a;Virtualization&#xff09;是一种资源管理技术&#xff0c;是将计算机的各种实体资源&#xff0c;如服务器、网络、内存及存储等&#xff0c;予以抽象、转换后呈现出来&#xff0c;打破实…

关键帧功能怎么使用 关键帧控制视频特效怎么用 会声会影视频剪辑软件教程

一篇文章&#xff0c;轻松掌握关键帧的用法&#xff0c;小白也能将关键帧玩得出神入化。在专业级的视频剪辑软件中&#xff0c;滤镜、转场、调色、遮罩等功能都离不开关键帧。可以毫不夸张地说&#xff0c;学会了关键帧的用法&#xff0c;就等于掌握了视频特效的基本逻辑 一、…