STM32 FreeRTOS中断管理

embedded/2025/1/18 23:59:26/

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的中断。
2. 中断服务例程(ISR)
在中断服务例程中,如果需要调用FreeRTOS的API函数,只能使用带“FromISR”后缀的函数。例如:
xQueueSendFromISR(queue, &data, &higherPriorityTaskWoken);

这样可以确保在中断服务例程中安全地与FreeRTOS任务进行通信。
3. 临界区保护
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);
    }
}

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


http://www.ppmy.cn/embedded/155083.html

相关文章

【使用EasyExcel快速实现数据下载到Excel功能】

使用EasyExcel快速实现数据下载到Excel功能 EasyExcel官方文档 1. 引言 在Web应用开发中&#xff0c;数据导出为Excel文件是一个常见的需求。本文将介绍如何使用EasyExcel库快速实现数据的下载功能。我们将通过一个具体的例子来展示如何设置响应头、获取数据并将其写入Excel…

leetcode 3095. 或值至少 K 的最短子数组 I

题目&#xff1a;3095. 或值至少 K 的最短子数组 I - 力扣&#xff08;LeetCode&#xff09; 加班用手机刷水题 class Solution { public:int minimumSubarrayLength(vector<int>& nums, int k) {int n nums.size();int m, l, ret n 10;for (int i 0; i < n…

github 端口22 超时问题解决

github 端口22 超时问题解决 问题描述报错信息解决方案步骤1步骤2步骤3 问题描述 搬了个公司后发现自己的sourcetree 以及 本地命令行在拉取代码或者clone时均报错&#xff0c;根据网友的解决方案&#xff0c;做了个整理 报错信息 $ git pull project develop ssh: connect …

Vue3组件通信进阶: 大型项目中Provide/Inject与EventBus的实战应用

Vue3组件通信进阶: 大型项目中Provide/Inject与EventBus的实战应用 在Vue3中&#xff0c;组件通信一直是一个非常重要的议题。除了常用的props和emit之外&#xff0c;Vue3还提供了更为灵活和强大的组件通信方式&#xff0c;如Provide/Inject和EventBus。本文将介绍如何在大型项…

【Linux】常见指令(一)

Linux常见指令 01.whoami02.pwd03.ls04.mkdir05.cd 本文LInux环境为&#xff0c;使用XShell远程登陆到Linux。 具体如何环境搭建&#xff0c;大家可以查看其他博客。 01.whoami whoami 指令用来查看当前账户是谁。 如上图所示&#xff0c;使用whoami指令&#xff0c;查看到现在…

【MyDB】3-DataManager数据管理 之 4-数据页缓存

【MyDB】3-DataManager数据管理 之 3-数据页管理 页面缓存设计与实现PageImpl页面定义getForCache() 文件中读取页面数据releaseForCache() 驱逐页面AtomicInteger 记录当前打开数据库文件页recoverInsert()和recoverUpdate() 参考资料 本章涉及代码&#xff1a;top/xianghua/m…

几个Linux系统安装体验(续): 中科方德服务器系统

本文介绍中科方德服务器系统&#xff08;NFSDesktop&#xff09;的安装。 下载 下载地址&#xff1a; https://www.nfschina.com/index.php?catid68 下载文件&#xff1a;本文下载的文件名称为NFSCNS-4.0-G330-x86_64-241128.iso。 下载注意事项&#xff1a;无法直接下载&…

【Rust自学】13.3. 闭包 Pt.3:使用泛型参数和fn trait来存储闭包

13.3.0. 写在正文之前 Rust语言在设计过程中收到了很多语言的启发&#xff0c;而函数式编程对Rust产生了非常显著的影响。函数式编程通常包括通过将函数作为值传递给参数、从其他函数返回它们、将它们分配给变量以供以后执行等等。 在本章中&#xff0c;我们会讨论 Rust 的一…