FreeRtos学习笔记 12 中断管理
12 中断管理
参考教程:
12-1 临界段保护
临界段就是一段执行时不能被打断的代码段。不过系统调度和外部中断可能打断临界段。在FreeRTOS中,系统调度本质上是产生PendSV中断,也是一种中断,所以FreeRTOS对临界段的保护本质上就是对中断的开关控制。
12-1-1 Cortex-M内核快速开关中断指令
Cortex-M内核专门设置了一条CPS指令。在FreeRTOS中,对中断的开关时通过操作BASEPRI寄存器实现的,大于等于BASEPRI的值的中断会被临界段屏蔽,反之不会屏蔽,不受FreeRTOS管理。可以通过设置BASEPRI的值来为一些中断设置“特权”。
12-1-2 关中断
不带返回值:portDISABLE_INTERRUPTS(),带返回值:portSET_INTERRUPT_MASK_FROM_ISR()。
-
FreeRTOS关中断的函数在portmacro.h中定义。实际上都是改变
BASEPRI寄存器的值。 -
分带返回值和不带返回值两种。
-
- 带返回值的关中断函数可以在中断中使用,反之不可。
12-1-3 临界区
临界段代码就是临界区。比如有的外设启动初始化的时候需要严格的时序,不能被打断。
FreeRTOS在进入临界区的时候需要关闭中断,处理完临界区后再打开中断。 FreeRTOS本身就有很多临界区,且都加了临界区保护。有时用户程序也需要且可以添加临界区保护。
FreeRTOS共有两个任务级、两个中断级的临界区保护函数。
12-1-3-1 任务级临界段代码保护
进入临界区:taskENTER_CRITICAL(),退出临界区:taskEXIT_CRITICAL()。
成对调用,其中间的代码就是临界段代码,临界段代码需要精简!
void taskCritical_test(void) {
while(1)
{
taskENTER_CRITICAL();
total_num++;
printf("total_num 的值为: %.4f\r\n",total_num);
taskEXIT_CRITICAL();
vTaskDelay(1000);
}
}
12-1-3-2 中断级临界段代码保护
进入临界区:taskENTER_CRITICAL_FROM_ISR(),退出临界区:taskEXIT_CRITICAL_FROM_ISR()。
用法与任务级一致。
12-2 中断管理
- 在FreeRTOS中,可以通过更改FreeRTOSConfig.h中的宏
configLIBRARY_LOWEST_INTERRUPT_PRIORITY来更改寄存器BASEPRI的。
12-3 示例
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "key.h"
#include "timer.h"
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 128
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
// LED1任务
#define LED1_TASK_PRIO 2
#define LED1_STK_SIZE 50
TaskHandle_t LED1Task_Handler;
void led1_task(void *pvParameters);
// 中断管理任务
#define InterruptCtrl_TASK_PRIO 4
#define InterruptCtrl_STK_SIZE 50
TaskHandle_t InterruptCtrl_Task_Handler;
void InterruptCtrl_task(void *pvParameters);
int main()
{
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
LED_Init();
USART1_Init(115200);
TIM3_Init(10000-1, 7200-1);
TIM4_Init(10000-1, 7200-1);
printf("Program starting!\n");
//创建开始任务
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(); //进入临界区
//创建LED1任务
xTaskCreate((TaskFunction_t )led1_task,
(const char* )"led1_task",
(uint16_t )LED1_STK_SIZE,
(void* )NULL,
(UBaseType_t )LED1_TASK_PRIO,
(TaskHandle_t* )&LED1Task_Handler);
// 创建中断管理任务
xTaskCreate((TaskFunction_t )InterruptCtrl_task,
(const char* )"InterruptCtrl_task",
(uint16_t )InterruptCtrl_STK_SIZE,
(void* )NULL,
(UBaseType_t )InterruptCtrl_TASK_PRIO,
(TaskHandle_t* )&InterruptCtrl_Task_Handler);
vTaskDelete(StartTask_Handler); //删除开始任务
taskEXIT_CRITICAL(); //退出临界区
}
//LED1任务函数
void led1_task(void *pvParameters)
{
while(1)
{
LED_Ctrl(1, LIGHT_ON);
LED_Ctrl(2, LIGHT_ON);
vTaskDelay(800);
LED_Ctrl(1, LIGHT_OFF);
LED_Ctrl(2, LIGHT_OFF);
vTaskDelay(200);
}
}
// 中断管理任务
void InterruptCtrl_task(void *pvParameters)
{
while(1)
{
printf("InterruptCtrl_task: Disable NVIC\n");
portDISABLE_INTERRUPTS();
delay_xms(5000);
printf("InterruptCtrl_task: Enable NVIC\b");
portENABLE_INTERRUPTS();
delay_xms(5000);
}
}
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)