6 FreeRTOS中断管理

1 中断

1.1中断简介

让CPU打断正常运行的程序,转而去处理紧急的事件(程序)。

中断执行机制,可简单概括为三步:

1)中断请求,外设产生中断请求(GPIO外部中断、定时器中断等)。

2)响应中断,CPU停止执行当前程序,转而去执行中断处理程序(ISR)。

3)退出中断,执行完毕,返回被打断的程序处,继续往下执行。

1.2中断优先级分组设置

ARM Cortex-M使用了8位宽的寄存器来配置中断的优先等级,这个寄存器就是中断优先级配置寄存器,但STM32只用了中断优先级配置寄存器的高4位[ 7 : 4 ],所以STM32提供了最大16级的中断优先等级。

STM32的中断优先级可以分为抢占优先级和子优先级。

抢占优先级:抢占优先级高的中断可以打断正在执行但抢占优先级低的中断。

子优先级:当同时发生具有相同抢占优先级的两个中断时,子优先级数值小的优先执行。

注意:中断优先级数值越小越优先。

中断优先级分组设置:

优先级分组抢占优先级子优先级优先级配置寄存器高四位

NVIC_PriorityGroup_0

0 级抢占优先级

0-15 级子优先级

0bit 用于抢占优先级
4bit 用于子优先级

NVIC_PriorityGroup_1

0-1 级抢占优先级

0-7 级子优先级

1bit 用于抢占优先级
3bit 用于子优先级

NVIC_PriorityGroup_2

0-3 级抢占优先级

0-3级子优先级

2bit 用于抢占优先级
2bit 用于子优先级

NVIC_PriorityGroup_3

0-7 级抢占优先级

0-1级子优先级

3bit 用于抢占优先级
1bit 用于子优先级

NVIC_PriorityGroup_4

0-15 级抢占优先级

0级子优先级

4bit 用于抢占优先级
0bit 用于子优先级

通过调用函数HAL_NVIC_SetPriorityGrouping(NVIC_PriorityGroup_4)即可完成设置(在HAL_Init中设置)

特点:

1)低于configMAX_SYSCALL_INTERRUPT_PRIORIT优先级(数值为5)的中断里才允许调用FreeRTOS的API函数,即优先级数值>5.

2)建议将所有中断优先级位指定为抢占优先级位,方便FreeRTOS管理                                        (调用函数HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4))

3)中断优先级数值越小越优先,任务优先级数值越大越优先

1.3 中断相关寄存器

三个系统中断优先级配置寄存器,分别为SHPR1、SHPR2、SHPR3、

SHPR1寄存器地址:0xE000ED18

SHPR2寄存器地址:0xE000ED1C

SHPR3寄存器地址:0xE000ED20

1.4 FreeRTOS配置PendSV和Systick中断优先权

指的是SHPR3 的首地址

由于上述的管理中断的寄存器中只有高4位配置优先级,因此就是将中断最低优先级配置给Systick和PendSV。

即PendSV和SysTick设置最低优先级,设置最低保证系统任务切换不会阻塞系统其他中断的响应,即中断可以打断任务,但任务不可以打断中断,PendSV的作用就是用来切换任务的。

1.5 中断屏蔽寄存器

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

名字功能描述
PRIMASK这是个只有1个位的寄存器。当他置1时,就关掉所有可屏蔽的异常,只剩下NMI和硬fault可以响应,它的缺省值是0,表示没有关中断,即开中断
FAULTMASK这是 个只有1个位的寄存器。当它置1时,只有NMI才能响应,包括中断和fault,通通关闭。它的缺省值也是0,表示没有关中断
BASEPRI这个寄存器最多有9位(由表达优先级的位数决定)。他定义了被屏蔽优先级的阈值,当它被设成某个值后,所有优先级号大于等于此值的中断都被关(优先级号越大,优先级越低)。但若被设置成0,则不关闭任何中断。

FreeRTOS所使用的中断管理就是利用的BASEPRI寄存器。

BASEPRI:屏蔽优先级低于某一个阈值的中断,比如BASEPRI设置为0X50,代表中断优先级在5~15内的均被屏蔽,0~4的中断优先级正常执行

在中断服务函数中调度FreeRTOS的API函数需注意:

1)中断服务函数的优先级需在FreeRTOS所管理的范围内

2)在中断服务函数里需调用FreeRTOS的API函数,必须使用带“FromISR”后缀的函数,并且优先级分组必须设置成组四。

2 FreeRTOS中断管理实验

2.1 实验内容

本实验会使用两个定时器,一个优先级为4,一个优先级为6,注意:系统管理的优先级范围:5~15。

现象:两个定时器每1s,打印一段字符串,当中断关闭时,停止打印,开中断时持续打印。

2.2 实验设计

将设计2个任务:start_task、task1

2个任务功能如下:

start_task 用来创建task1任务

task1 中断测试任务,任务中将调用关中断

#include "./BSP/LED/led.h"
#include "./BSP/TIMER/btim.h"
#include "./SYSTEM/usart/usart.h"


TIM_HandleTypeDef g_timx_handler;         /* 定时器参数句柄 */
TIM_HandleTypeDef g_tim7_handler;         /* 定时器参数句柄 */

/**
 * @brief       基本定时器TIMX定时中断初始化函数
 * @note
 *              基本定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
 *              基本定时器的时钟为APB1时钟的2倍, 而APB1为42M, 所以定时器时钟 = 84Mhz
 *              定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
 *              Ft=定时器工作频率,单位:Mhz
 *
 * @param       arr : 自动重装值。
 * @param       psc : 时钟预分频数
 * @retval      无
 */
 /*TIM6初始化*/
void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
    g_timx_handler.Instance = BTIM_TIMX_INT;                      /* 定时器x */
    g_timx_handler.Init.Prescaler = psc;                          /* 分频 */
    g_timx_handler.Init.CounterMode = TIM_COUNTERMODE_UP;         /* 递增计数模式 */
    g_timx_handler.Init.Period = arr;                             /* 自动装载值 */
    HAL_TIM_Base_Init(&g_timx_handler);
    
    HAL_TIM_Base_Start_IT(&g_timx_handler);                       /* 使能定时器x和定时器更新中断 */
}

/*TIM7初始化*/
void btim_tim7_int_init(uint16_t arr, uint16_t psc)
{
    g_tim7_handler.Instance = BTIM_TIM7_INT;                      /* 定时器x */
    g_tim7_handler.Init.Prescaler = psc;                          /* 分频 */
    g_tim7_handler.Init.CounterMode = TIM_COUNTERMODE_UP;         /* 递增计数模式 */
    g_tim7_handler.Init.Period = arr;                             /* 自动装载值 */
    HAL_TIM_Base_Init(&g_tim7_handler);
    
    HAL_TIM_Base_Start_IT(&g_tim7_handler);                       /* 使能定时器x和定时器更新中断 */
}


/**
 * @brief       定时器底层驱动,开启时钟,设置中断优先级
                此函数会被HAL_TIM_Base_Init()函数调用
 * @param       无
 * @retval      无
 */
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        BTIM_TIMX_INT_CLK_ENABLE();                     /* 使能TIMx时钟 */
        HAL_NVIC_SetPriority(BTIM_TIMX_INT_IRQn, 6, 0); /* 抢占1,子优先级3 */
        HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn);         /* 开启ITMx中断 */
    }
		if (htim->Instance == BTIM_TIM7_INT)
		{
        BTIM_TIM7_INT_CLK_ENABLE();                     /* 使能TIMx时钟 */
        HAL_NVIC_SetPriority(BTIM_TIM7_INT_IRQn, 4, 0); /* 抢占4,子优先级0 */
        HAL_NVIC_EnableIRQ(BTIM_TIM7_INT_IRQn);         /* 开启ITMx中断 */
			
		}
}

/*TIM6中断服务函数*/
void BTIM_TIMX_INT_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_timx_handler);  /* 定时器回调函数 */
}

/*TIM7中断服务函数*/
void BTIM_TIM7_INT_IRQHandler(void)
{
	  HAL_TIM_IRQHandler(&g_tim7_handler);  /* 定时器回调函数 */

}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        printf("TIM6优先级为6的正在运行!!!\r\n");
    }
		else if(htim->Instance == BTIM_TIM7_INT)
		{
				printf("TIM7优先级为4的正在运行!!!!!!\r\n");
		}
}

定时器.c文件中主要用来创建定时器的任务,每1s打印一次的任务。

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.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      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 */

/******************************************************************************************************/

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();
}

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);
    				
    vTaskDelete(StartTask_Handler); /* 删除开始任务 */
								
    taskEXIT_CRITICAL();            /* 退出临界区 */
}


void task1(void *pvParameters)
{
	  uint8_t task1_num = 0;
    while(1)
    {
			if(++task1_num == 5)
			{
				task1_num = 0;
				printf("关中断!!\r\n");
				portDISABLE_INTERRUPTS();
				delay_ms(5000);
				printf("开中断!!\r\n");
				portENABLE_INTERRUPTS();
			}
			  LED0_TOGGLE();                                                  /* LED0闪烁 */
        vTaskDelay(500);                                               /* 延时500ms */
    }
}

FreeRTOS的.c文件主要用来创建任务用来开中断和关中断。、

运行结果:

  • 17
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS是一个实时操作系统,它的中断管理是其核心功能之一。在FreeRTOS中,中断管理主要是围绕中断服务例程(ISR)和任务调度来实现的。以下是一些关于FreeRTOS中断管理的关键概念和特性: 1. 中断服务例程(ISR):在FreeRTOS中,当硬件中断发生时,中断服务例程会被调用。ISR应该尽可能简短和快速地执行,因为在其执行期间,中断通常是被禁用的。在ISR中,通常只做必要的硬件状态的保存和恢复,以及设置一个任务通知或信号量等,来通知一个或多个任务中断已经发生。 2. 任务通知:ISR通过FreeRTOS提供的API(例如xSemaphoreGiveFromISR(), xQueueSendFromISR())来通知任务。这些函数允许ISR将事件传递给任务,而不需要任务处于阻塞状态。 3. 中断优先级和FreeRTOS优先级:FreeRTOS可以运行在具有多种中断优先级的硬件上。通常,FreeRTOS会为自己的任务分配高于或等于最低硬件中断优先级的优先级,以确保中断不会被低优先级的任务阻塞。 4. 响应中断:当中断发生时,FreeRTOS的任务调度器会根据当前的中断处理和系统状态来决定是否进行任务切换。如果有必要,调度器会在ISR完成后切换到适当的高优先级任务。 5. 中断和上下文切换:FreeRTOS的上下文切换是由中断触发的,特别是由系统时钟中断触发,它允许调度器周期性地检查是否有更高优先级的任务准备运行。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值