Cortx-M 中断
优先级分组
Cortex-M3允许具有较少中断源时使用较少的寄存器位指定中断源的优先级,因此STM32把指定中断优先级的寄存器位减少到4位。抢占优先级的级别高于响应优先级。而数值越小所代表的优先级就越高。高的抢占式优先级可以打断低的抢占式优先级,故名抢占;而在抢占式优先级相同的情况下,响应优先级越高,同时发生则先响应它,但是不能打断低响应优先级,响应表达的是响应速度。
这4个寄存器位的分组方式如下:
第0组:所有4位用于指定响应优先级
第1组:最高1位用于指定抢占式优先级,最低3位用于指定响应优先级
第2组:最高2位用于指定抢占式优先级,最低2位用于指定响应优先级
第3组:最高3位用于指定抢占式优先级,最低1位用于指定响应优先级
第4组:所有4位用于指定抢占式优先级
NVIC_PriorityGroup_0=> 选择第0组
NVIC_PriorityGroup_1=> 选择第1组
NVIC_PriorityGroup_2=> 选择第2组
NVIC_PriorityGroup_3=> 选择第3组
NVIC_PriorityGroup_4=> 选择第4组
优先级:
// 选择使用优先级分组第1组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// 使能EXTI0中断
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 指定抢占式优先级别1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 指定响应优先级别0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能EXTI9_5中断
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 指定抢占式优先级别0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 指定响应优先级别1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
移植FreeROTS时选择组4,全部都是抢占优先级,一共16个优先级。
用于中断屏蔽的特殊寄存器
PRIMASK寄存器用于禁止除NMI和HardFalut外的所有异常和中断。
FAULTMASK寄存器禁止除NMI外的所有异常和中断。
BASEPRI寄存器屏蔽优先级低于某一个阈值的中断。
FreeRTOS中断配置
portENABLE_INTERRUPTS()是开中断。
portDISABLE_INTERRUPTS()的关中断。
vPortSetBASEPRI()时向寄存器BASEPRI写入一个值。
vPortRaiseBASEPRI()是屏蔽优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断
临界段代码
指那些必须完整运行,不能被打断的代码段。FreeRTOS在进入临界代码段的时候需要关闭中断,当处理完临界段代码以后再打开中断。
任务级的临界代码保护:
taskEATER_CRITICAL()进入临界段
taskEXIT_CRITICAL()退出临界段
中断级临界段代码保护: 用于中断程序,这个中断的优先级一定要低于configMAX_SYSCALL_INTERRUPT_PRIORITY
tsakENTER_CRITICAL_FROM_ISR()进入临界区
taskEXIT_CRITICAL_FROM_ISR()退出临界区
FreeRTOS中断测试实验
实验目的
使用两个定时器,一个优先级4,一个优先级5,两个定时器每隔1s通过串口输出一串字符串。然后在某个任务中关闭中断一段时间,查看两个定时器的输出情况。
实验设计
start_task():创建另外一个任务。
interrupt_task():中断测试任务,任务中会调用FreeRTOS的关中断函数portDISABLE_INTERRUPTS()来将中断关闭一段时间。
main
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "FreeRTOS.h"
#include "task.h"
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 256
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define INTERRUPT_TASK_PRIO 2
//任务堆栈大小
#define INTERRUPT_STK_SIZE 256
//任务句柄
TaskHandle_t INTERRUPTTask_Handler;
//任务函数
void interrupt_task(void *p_arg);
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
TIM3_Int_Init(10000-1,7200-1); //初始化定时器3,定时器周期1S
TIM5_Int_Init(10000-1,7200-1); //初始化定时器5,定时器周期1S
//创建开始任务
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(); //进入临界区
//创建中断测试任务
xTaskCreate((TaskFunction_t )interrupt_task, //任务函数
(const char* )"interrupt_task", //任务名称
(uint16_t )INTERRUPT_STK_SIZE, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )INTERRUPT_TASK_PRIO, //任务优先级
(TaskHandle_t* )&INTERRUPTTask_Handler); //任务句柄
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//中断测试任务函数
void interrupt_task(void *pvParameters)
{
static u32 total_num=0;
while(1)
{
total_num+=1;
if(total_num==5)
{
printf("关闭中断.............\r\n");
portDISABLE_INTERRUPTS(); //关闭中断
delay_xms(5000); //延时5s
printf("打开中断.............\r\n"); //打开中断
portENABLE_INTERRUPTS();
total_num=0;
}
LED0=~LED0;
vTaskDelay(1000);
}
}
运行结果
configMAX_SYSCALL_INTERRUPT_PRIORITY设置为5,TIM5的中断优先级为5,TIM3的中断优先级为4,所以当关闭中断时TIM5被关闭,TIM3没有被关闭。