目录
什么是中断
中断相关寄存器
源码实验
什么是中断
简介:让CPU打断正常运行的程序,转而去处理紧急的事件(程序) ,就叫中断。
举例:上课可以比做CPU正常运行的程序,上厕所可以比做中断程序。
中断执行机制,可简单概括为三步:
中断请求:外设产生中断请求(GPIO外部中断、定时器中断等)
响应中断:CPU停止执行当前程序,转而去执行中断处理程序(ISR)
退出中断:执行完毕,返回被打断的程序处,继续往下执行
中断优先级分组设置
ARM Cortex-M使用了8位宽的寄存器来配置中断的优先等级,这个寄存器就是中断优先级配置寄存器,但STM32,只用了中断优先级配置寄存器的高4位[7:4],所以STM32提供了最大16级的中断优先等级。
STM32 的中断优先级可以分为抢占优先级和子优先级
抢占优先级:抢占优先级高的中断可以打断正在执行但抢占优先级低的中断
子优先级:当同时发生具有相同抢占优先级的两个中断时,子优先级数值小的优先执行
注意:中断优先级数值越小越优先
一共有5种分配方式,对应着中断优先级分组的5个组
通过调用函数HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4)即可完成设置
特点:
1.低于configMAX_SYSCALL_INTERRUPT_PRIORITY优先级的中断里才允许调用FreeRTOS 的API函数。
2.建议将所有优先级位指定为抢占优先级位,方便FreeRTOS管理
3.中断优先级数值越小越优先,任务优先级数值越大越优先
中断相关寄存器
三个系统中断优先级配置寄存器,分别为SHPR1、SHPR2、SHPR3
SHPR1寄存器地址:0xE000ED18
SHPR2寄存器地址:0xE000ED1C
SHPR3寄存器地址:0xE000ED20
FreeRTOS如何配置PendSV和Systick中断优先级
所以: PendSV和SysTick设置最低优先级
设置最低:保证系统任务切换不会阻塞系统其他中断的响应
三个中断屏蔽寄存器,分别为PRIMASK、 FAULTMASK和BASEPRI
FreeRTOS所使用的中断管理就是利用的BASEPRI这个寄存器
BASEPRI:屏蔽优先级低于某一个阈值的中断
比如:BASEPRI设置为0x50,代表中断优先级在5~15内的均被屏蔽,0~4的中断优先级正常执行。
BASEPRI:屏蔽优先级低于某一个阈值的中断,当设置为0时,则不关闭任何中断。
关中断程序示例:
中断优先级在5~15的全部被关闭
当BASEPRI设置为0x50时:
在中断服务函数中调度FreeRTOS的API函数需注意:
1.中断服务函数的优先级需在FreeRTOS所管理的范围内
2.在中断服务函数里边需调用FreeRTOS的API函数,必须使用带“FromISR”后缀的函数
BASEPRI:屏蔽优先级低于某一个阈值的中断,当设置为0时,则不关闭任何中断
开中断程序示例:
FreeRTOS中断管理就是利用BASEPRI寄存器实现的
源码实验
/**
******************************************************************************
* @file : user_timer.c
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "user_timer.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
/*!
\brief 定时器初始化
\param[in] 装载值
\param[in] 分频系数
\retval none
*/
void Tim3_Init(uint16_t arr, uint16_t psc)
{
/*定时器结构体*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeDefstruct;
/*NVIC结构体*/
NVIC_InitTypeDef NVIC_InitTypeDefstruct;
TIM_TimeBaseInitTypeDefstruct.TIM_Period = arr; //自动装载值
TIM_TimeBaseInitTypeDefstruct.TIM_Prescaler = psc; //分频系数
TIM_TimeBaseInitTypeDefstruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInitTypeDefstruct.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频
/*写入定时器3*/
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitTypeDefstruct);
/*使能定时器更新中断配置*/
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
/*定时器中断优先级配置*/
NVIC_InitTypeDefstruct.NVIC_IRQChannel= TIM3_IRQn; //USART1中断通道
NVIC_InitTypeDefstruct.NVIC_IRQChannelCmd = ENABLE; //使能USART1中断
NVIC_InitTypeDefstruct.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级
NVIC_InitTypeDefstruct.NVIC_IRQChannelSubPriority = 0;//子优先级
/*写入NVIC中*/
NVIC_Init(&NVIC_InitTypeDefstruct);
/*使能定时器*/
TIM_Cmd(TIM3,ENABLE);
}
/*!
\brief TIM3_IRQHandler
\param[in] none
\param[in] none
\retval none
*/
void TIM3_IRQHandler(void)
{
/*判断是不是更新中断*/
if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)
{
printf("定时器3时间到任务优先级2********\r\n");
}
/*清除更新中断*/
TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
}
/*!
\brief 定时器初始化
\param[in] 装载值
\param[in] 分频系数
\retval none
*/
void Tim4_Init(uint16_t arr, uint16_t psc)
{
/*定时器结构体*/
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeDefstruct;
/*NVIC结构体*/
NVIC_InitTypeDef NVIC_InitTypeDefstruct;
TIM_TimeBaseInitTypeDefstruct.TIM_Period = arr; //自动装载值
TIM_TimeBaseInitTypeDefstruct.TIM_Prescaler = psc; //分频系数
TIM_TimeBaseInitTypeDefstruct.TIM_CounterMode = TIM_CounterMode_Up;//向上计数模式
TIM_TimeBaseInitTypeDefstruct.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频
/*写入定时器4*/
TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitTypeDefstruct);
/*使能定时器更新中断配置*/
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
/*定时器中断优先级配置*/
NVIC_InitTypeDefstruct.NVIC_IRQChannel= TIM4_IRQn; //USART1中断通道
NVIC_InitTypeDefstruct.NVIC_IRQChannelCmd = ENABLE; //使能USART1中断
NVIC_InitTypeDefstruct.NVIC_IRQChannelPreemptionPriority = 6; //抢占优先级
NVIC_InitTypeDefstruct.NVIC_IRQChannelSubPriority = 0;//子优先级
/*写入NVIC中*/
NVIC_Init(&NVIC_InitTypeDefstruct);
/*使能定时器*/
TIM_Cmd(TIM4,ENABLE);
}
/*!
\brief TIM4_IRQHandler
\param[in] none
\param[in] none
\retval none
*/
void TIM4_IRQHandler(void)
{
/*判断是不是更新中断*/
if(TIM_GetITStatus(TIM4,TIM_IT_Update) == SET)
{
printf("定时器4时间到任务优先级6!!!!\r\n");
}
/*清除更新中断*/
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
}
/************************************************************** END OF FILE ****/
/**
******************************************************************************
* @file : user_mian.h
* @brief : V1.00
******************************************************************************
* @attention
*
******************************************************************************
*/
/* Include 包含---------------------------------------------------------------*/
#include "stm32f10x.h"
#include <stdbool.h>
#include "user_gpio.h"
#include "user_delay.h"
#include "user_rcc_config.h"
#include "user_uart.h"
#include "user_timer.h"
#include "FreeRTOS.h"
#include "task.h"
/* Typedef 类型----------------------------------------------------------------*/
/* Define 定义----------------------------------------------------------------*/
/* Macro 宏------------------------------------------------------------------*/
/* Variables 变量--------------------------------------------------------------*/
/* Constants 常量--------------------------------------------------------------*/
/* Function 函数--------------------------------------------------------------*/
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define Interruption_TASK_PRIO 2
//任务堆栈大小
#define Interruption_STK_SIZE 50
//任务句柄
TaskHandle_t InterruptionTask_Handler;
//任务函数
void Interruption_task(void *pvParameters);
int main(void)
{
/*配置系统中断分组为4位抢占*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
/*延时函数初始化*/
delay_init();
/*RCC配置*/
Rcc_config();
/*GPIO初始化*/
Gpio_Init();
/*USART1初始化*/
Uart1_Init(9600);
/*初始化定时器3,1s中断*/
Tim3_Init(10000-1,7200-1);
/*初始化定时器4,1s中断*/
Tim4_Init(10000-1,7200-1);
/*创建开始任务*/
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 开始任务函数
\param[in] 传递形参,创建任务时用户自己传入
\param[out] none
\retval none
*/
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
//创建LED0任务
xTaskCreate((TaskFunction_t )Interruption_task,
(const char* )"Interruption_task",
(uint16_t )Interruption_STK_SIZE,
(void* )NULL,
(UBaseType_t )Interruption_TASK_PRIO,
(TaskHandle_t* )&InterruptionTask_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
/*!
\brief led0_task任务函数
\param[in] 传递形参,创建任务时用户自己传入
\param[out] none
\retval none
*/
void Interruption_task(void *pvParameters)
{
uint8_t i =0;
while(1)
{
if(++i == 5)
{
i=0;
printf("关闭中断*****\r\n");
/*关闭中断*/
portDISABLE_INTERRUPTS();
/*延时5秒*/
delay_us(5000000);
printf("开启中断*****\r\n");
/*开启中断*/
portENABLE_INTERRUPTS();
}
vTaskDelay(1000);
}
}
/************************************************************** END OF FILE ****/