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上实现高效、稳定的中断管理。这些机制不仅提高了系统的实时性,还确保了任务调度的正确性和可靠性。

相关推荐
周洲08301 小时前
STM32 ADC 采集实战|电压采集、分压计算、数据滤波
stm32·单片机·嵌入式硬件
SKH.3 小时前
单片机(2)
单片机
DaTou大头3 小时前
STM32第三篇
单片机·嵌入式·电路基础
H_oRIZoN_4 小时前
Linux入门DAY40(51 单片机入门:GPIO、中断、定时器、PWM、蜂鸣器完整梳理)
单片机·嵌入式硬件
LCG元5 小时前
STM32F103 复位来源诊断实战:RCC_CSR 标志位判优、BKP 复位计数持久化与六种复位源注入实测
stm32·单片机·嵌入式硬件
国产HT1621B7 小时前
显示省不了电,休眠才见真章:1621 低功耗实操
驱动开发·单片机·嵌入式硬件·led驱动·lcd驱动
国科安芯7 小时前
低轨卫星姿轨控系统中高可靠嵌入式控制单元的设计与验证
单片机·mcu·低轨卫星·星间链路·卫星姿轨控
老当益壮梁奶奶9 小时前
ARM 汇编学习笔记(二)启动代码、指令、函数调用与 C 混合编程
c语言·arm开发·单片机·嵌入式硬件·51单片机
天空'之城10 小时前
单片机基础核心知识点汇总(三十八)
单片机·嵌入式硬件
崇山峻岭之间11 小时前
HC32F460PETB的PH2的EVENTOUT
单片机