STM32 FreeRTOS中断管理

STM32 FreeRTOS 中断管理

一、中断优先级配置

在STM32上使用FreeRTOS时,合理配置中断优先级是非常重要的。STM32使用8位宽的寄存器来配置中断的优先等级,但实际只使用了高4位(7:4),因此提供了最大16级的中断优先级。中断优先级数值越小,优先级越高。

二、中断优先级分组

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

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

• 子优先级:当同时发生具有相同抢占优先级的中断时,子优先级数值小的优先执行,但不能互相打断。

为了方便FreeRTOS管理,建议将所有优先级位指定为抢占优先级位,即将优先级分组设置为组4。可以通过以下代码设置:

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);

这样,4位优先级就都作为抢占优先级,没有子优先级,共有0~15共16个优先级。

三、FreeRTOS 中断管理

  1. 中断优先级配置

FreeRTOS通过宏configMAX_SYSCALL_INTERRUPT_PRIORITY来定义可管理的最高中断优先级。例如:

#define configMAX_SYSCALL_INTERRUPT_PRIORITY (5 << 4)

这意味着FreeRTOS可以管理优先级数值大于等于5的中断。

  1. 中断服务例程(ISR)

在中断服务例程中,如果需要调用FreeRTOS的API函数,只能使用带"FromISR"后缀的函数。例如:

xQueueSendFromISR(queue, &data, &higherPriorityTaskWoken);

这样可以确保在中断服务例程中安全地与FreeRTOS任务进行通信。

  1. 临界区保护

FreeRTOS提供了宏taskENTER_CRITICAL()和taskEXIT_CRITICAL()来进入和退出临界区。这些宏通过禁用和启用中断来保护临界区代码。例如:

void vPortEnterCritical(void) {

portDISABLE_INTERRUPTS();

uxCriticalNesting++;

if (uxCriticalNesting == 1) {

configASSERT((portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK) == 0);

}

}

void vPortExitCritical(void) {

configASSERT(uxCriticalNesting);

uxCriticalNesting--;

if (uxCriticalNesting == 0) {

portENABLE_INTERRUPTS();

}

}

这些宏确保在临界区代码执行期间,不会被其他中断打断,从而保证操作的原子性。

四、中断控制器配置

在使用FreeRTOS时,需要合理配置中断控制器。例如,设置SysTick和PendSV中断的优先级:

#define configMAX_SYSCALL_INTERRUPT_PRIORITY (5 << 4)

NVIC_SetPriorityGrouping(0);

NVIC_SetPriority(SysTick_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY);

NVIC_SetPriority(PendSV_IRQn, configMAX_SYSCALL_INTERRUPT_PRIORITY);

这样可以确保FreeRTOS的系统任务切换不会阻塞其他中断的响应。

五、延迟中断处理

FreeRTOS采用延迟中断处理机制,将中断处理任务延迟到RTOS任务中执行。例如:

• t1-t2这段时间低优先级的任务Task1正在执行,高优先级的任务Task2因等待事件被阻塞。

• t2时刻发生了中断,该中断就是Task2等待的事件,因此Task2进入就绪态。

• t3时刻中断服务程序执行完毕,由于就绪任务中Task2优先级更高,因此调度器选择Task2进入运行态。

六、实际案例

以下是一个实际案例,展示了如何在STM32上使用FreeRTOS进行中断处理和任务调度:

  1. 初始化代码

#include "stm32f10x.h"

#include "OLED.h"

#include "FreeRTOS.h"

#include "task.h"

#include "FreeRTOS_experiment.h"

#include "Key.h"

#include "LED.h"

#include "Timer.h"

int main(void) {

Key_Init();

LED_Init();

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

Timer2_Init();

Timer3_Init();

FreeRTOS_Test();

while (1) {

}

}

void TIM2_IRQHandler(void) {

if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) {

LED1_Turn();

TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

}

}

void TIM3_IRQHandler(void) {

if (TIM_GetITStatus(TIM3, TIM_IT_Update) == SET) {

LED2_Turn();

TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

}

}

  1. 任务创建和调度

#include "FreeRTOS.h"

#include "task.h"

#include "LED.h"

#include "Key.h"

#include "Delay.h"

#define START_TASK_STACK_SIZE 128

#define START_TASK_PRIO 1

#define TASK3_STACK_SIZE 128

#define TASK3_PRIO 4

void start_task(void);

void task3(void);

TaskHandle_t start_task_handler;

TaskHandle_t task3_handler;

void FreeRTOS_Test(void) {

xTaskCreate((TaskFunction_t)start_task,

"start_task",

START_TASK_STACK_SIZE,

NULL,

START_TASK_PRIO,

(TaskHandle_t *)&start_task_handler);

vTaskStartScheduler();

}

void start_task(void) {

taskENTER_CRITICAL();

xTaskCreate((TaskFunction_t)task3,

"task3",

TASK3_STACK_SIZE,

NULL,

TASK3_PRIO,

(TaskHandle_t *)&task3_handler);

vTaskDelete(NULL);

taskEXIT_CRITICAL();

}

void task3(void) {

uint8_t key = 0;

while (1) {

key = Key_GetNum();

if (key == 1) {

portDISABLE_INTERRUPTS();

}

if (key == 2) {

portENABLE_INTERRUPTS();

}

Delay_ms(10);

}

}

七、总结

通过合理配置中断优先级、使用临界区保护、延迟中断处理等机制,FreeRTOS可以在STM32上实现高效、稳定的中断管理。这些机制不仅提高了系统的实时性,还确保了任务调度的正确性和可靠性。

相关推荐
番茄老夫子8 小时前
工业温湿度传感器芯片推荐
单片机·嵌入式硬件
小鱼做毕设12 小时前
基于单片机的智能输液系统
单片机·嵌入式硬件·毕业设计·课程设计·智能输液系统
gyeolhada12 小时前
计算机组成原理(计算机系统3)--实验二:MIPS64乘法实现实验
stm32·单片机·嵌入式硬件
疯狂的豆包12 小时前
基于 STM32 连接 Mini MP3 播放器的实践探索
stm32·单片机·嵌入式硬件
wit_@14 小时前
单片机的原理及其应用:从入门到进阶的全方位指南
单片机·嵌入式硬件
兢兢业业的打野14 小时前
智能家居电机控制
单片机·嵌入式硬件
daybydayby16 小时前
Hooks扩展
单片机
不能只会打代码16 小时前
32单片机综合应用案例——基于GPS的车辆追踪器(三)(内附详细代码讲解!!!)
单片机·嵌入式硬件·32单片机
放我去玩单片机16 小时前
基于 STM32 的多功能时间管理器项目
stm32·单片机·嵌入式硬件