(第16-17讲)STM32F4单片机,FreeRTOS中断管理简介【视频笔记、代码讲解】【正点原子】【原创】

文章详细讨论了在STM32F4单片机上使用FreeRTOS时,如何设置中断优先级和任务管理,特别是PendSV和Systick中断的优先级。通过代码讲解展示了如何在任务中控制中断,以及定时器中断与FreeRTOS任务的关系。
摘要由CSDN通过智能技术生成


🔴🟡🟢其他文章链接,独家吐血整理

【吐血总结】FreeRTOS难点、Systick中断-滴答定时器、PendSV中断-任务切换、SVC中断-系统底层、时间片调度-时钟节拍【已完结】
(第1-8讲)STM32F4单片机,FreeRTOS基础知识总结【视频笔记、代码讲解】【正点原子】【原创】
(第9-10讲)STM32F4单片机,FreeRTOS任务创建和删除(动态方法)【视频笔记、代码讲解】【正点原子】【原创】
(第12讲)STM32F4单片机,FreeRTOS任务创建和删除(静态方法)【视频笔记、代码讲解】【正点原子】【原创】
(第13-14讲)STM32F4单片机,FreeRTOS任务挂起和恢复【视频笔记、代码讲解】【正点原子】【原创】
(第16-17讲)STM32F4单片机,FreeRTOS中断管理简介【视频笔记、代码讲解】【正点原子】【原创】
(第18-19讲)32单片机,FreeRTOS临界段代码保护、任务调度器的挂起和恢复【视频笔记、代码讲解】【原创】
(第20-22讲)STM32F4单片机,FreeRTOS列表和列表项API函数讲解【视频笔记、代码讲解、正点原子】【原创】
(第34-36讲)FreeRTOS消息队列知识汇总【B站UP、硬件家园、普中科技、正点原子】【视频笔记】【原创】
(第40-44讲)STM32F4单片机,FreeRTOS信号量【二值、计数、翻转、互斥】【代码讲解】【正点原子】【原创】

1、视频笔记

1、2024温故知新(纯文字)

中断优先级0为最高,任务优先级0为最低
中断优先级分组中为方便rtos管理4bit全部设置成抢占优先级
32单片机的中断管理是由3个寄存器完成(名字忽略,具体功能忽略),三个寄存器都是32bit,通过移位可操作设置寄存器上的bit位,比如可设置pendsv中断和systick中断优先级
最终,pendsv与systick被设置成15,pendsv与systick切换任务的时候不会影响到其它中断的触发(比如外部中断)
上面三个寄存器是设置中断优先级;还有三个寄存器用于屏蔽中断,freertos使用了寄存器BASEPRI用于中断屏蔽,为0x50代表关闭(也可以说屏蔽)5-15优先级的中断,为0代表不关闭(屏蔽)任何中断(就是这个寄存器规定了freertos只能控制5-15优先级的中断),如果为0x60,则就是6-15
1、中断优先级分组全部设置成抢占优先级->是为了方便freertos管理中断
2、你的中断优先级设置必须是5-15(当然也可以为0-4,但这样不受控了)
3、freertos只能控制5-15优先级的中断
4、0-4的中断因为rtos不可控,所以禁止0-4的中断调用rtos的api函数,5-15则可以与之前的笔记一致(第13-14讲)STM32F4单片机,FreeRTOS任务挂起和恢复【视频笔记、代码讲解】【正点原子】【原创】)

在这里插入图片描述
老生常谈
在这里插入图片描述
老生常谈
在这里插入图片描述
老生常谈,FreeRTOS只用分组4,因为这样方便打断,不用考虑子优先级了
在这里插入图片描述
老生常谈
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
有点新奇
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
拍案叫绝
在这里插入图片描述

2、实验现象

在这里插入图片描述

3、代码讲解(个人注释)

TIM_HandleTypeDef g_timx_handle; /* 定时器参数句柄 /
//TIM_HandleTypeDef是typedef重命名的结构体(也可以说结构体类型),g_timx_handle是结构体变量名
TIM_HandleTypeDef g_tim7_handle; /
定时器参数句柄 */

/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
    uint8_t task1_num = 0;
    while(1)
    {
        if(++task1_num == 5)
        {
            task1_num = 0;
            printf("关中断!!\r\n");
            portDISABLE_INTERRUPTS();
            delay_ms(5000);
            printf("开中断!!!\r\n");
            portENABLE_INTERRUPTS();
        }
        vTaskDelay(1000);
    }
}
//这里是freeRTOS通过任务来关中断,因此中断优先级为5-15的可以关
//而定时器中断7的抢占优先级为4,因此它不受影响,基本定时器x的为6,它就被freeRTOS关闭了

//这里是freeRTOS通过任务来关中断,因此中断优先级为5-15的可以关
//而定时器中断7的抢占优先级为4,因此它不受影响,基本定时器x的为6,它就被freeRTOS关闭了

在这里插入图片描述

/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
    uint8_t task1_num = 0;
    while(1)
    {
        if(++task1_num == 5)
        {
            task1_num = 0;
            printf("关中断!!\r\n");
            portDISABLE_INTERRUPTS();
            delay_ms(5000);//这里为什么要使用delay延时?
            //因为vTaskDelay函数内部使用到了开关临界区保护,这个会使中断打开了,不符合该实验要求
            //这5s期间,定时器x中断优先级为6的不执行,但是定时器中断7优先级为4的仍然每1s执行(这个1s不是task1的1s)
            //这5s期间,按理说,task1任务也停了,程序卡死这里,即5s后才执行下面的vTaskDelay(1000);
            //没开发板,无法验证呀
            
            //对,就是这样,5s后才会重新运行task1,然后运行5次task1的taskdelay延时,再次进入关开中断
            printf("开中断!!!\r\n");
            portENABLE_INTERRUPTS();
        }
        vTaskDelay(1000);//这个延时涉及到临界区保护,即会影响开关中断
        //这个1s是task1任务的1s,不是上面的定时器中断1s
    }
}
//这里是freeRTOS通过任务来关中断,因此中断优先级为5-15的可以关
//而定时器中断7的抢占优先级为4,因此它不受影响,基本定时器x的为6,它就被freeRTOS关闭了

delay_ms(5000);//这里为什么要使用delay延时?
//因为vTaskDelay函数内部使用到了开关临界区保护,这个会使中断打开了,不符合该实验要求
//这5s期间,定时器x中断优先级为6的不执行,但是定时器中断7优先级为4的仍然每1s执行(这个1s不是task1的1s)
//这5s期间,按理说,task1任务也停了,程序卡死这里,即5s后才执行下面的vTaskDelay(1000);
//没开发板,无法验证呀

//对,就是这样,5s后才会重新运行task1,然后运行5次task1的taskdelay延时,再次进入关开中断

vTaskDelay(1000);//这个延时涉及到临界区保护,即会影响开关中断
//这个1s是task1任务的1s,不是上面的定时器中断1s

//这里是freeRTOS通过任务来关中断,因此中断优先级为5-15的可以关
//而定时器中断7的抢占优先级为4,因此它不受影响,基本定时器x的为6,它就被freeRTOS关闭了
在这里插入图片描述
截到了,就是这样

1、一个弹幕的问题?

在这里插入图片描述
在这里插入图片描述

2、PendSV和Systick中断优先级最低?

这个博主写得有问题,可作参考
这个博主是对的,可看
这个博主作为参考2

其实我也不是很明白,但是认为tick优先级最低,pend优先级次之就行了

4、demo函数

/**
 ****************************************************************************************************
 * @file        freertos.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.4
 * @date        2022-01-04
 * @brief       FreeRTOS 移植实验
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 F407电机开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 ****************************************************************************************************
 */

#include "freertos_demo.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./SYSTEM/delay/delay.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"

/******************************************************************************************************/
/*FreeRTOS配置*/

/* START_TASK 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define START_TASK_PRIO         1
#define START_TASK_STACK_SIZE   128
TaskHandle_t    start_task_handler;
void start_task( void * pvParameters );

/* TASK1 任务 配置
 * 包括: 任务句柄 任务优先级 堆栈大小 创建任务
 */
#define TASK1_PRIO         2
#define TASK1_STACK_SIZE   128
TaskHandle_t    task1_handler;
void task1( void * pvParameters );

/******************************************************************************************************/


/**
 * @brief       FreeRTOS例程入口函数
 * @param       无
 * @retval      无
 */
void freertos_demo(void)
{    
    xTaskCreate((TaskFunction_t         )   start_task,
                (char *                 )   "start_task",
                (configSTACK_DEPTH_TYPE )   START_TASK_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   START_TASK_PRIO,
                (TaskHandle_t *         )   &start_task_handler );
    vTaskStartScheduler();
}


void start_task( void * pvParameters )
{
    taskENTER_CRITICAL();               /* 进入临界区 */
    xTaskCreate((TaskFunction_t         )   task1,
                (char *                 )   "task1",
                (configSTACK_DEPTH_TYPE )   TASK1_STACK_SIZE,
                (void *                 )   NULL,
                (UBaseType_t            )   TASK1_PRIO,
                (TaskHandle_t *         )   &task1_handler );
    vTaskDelete(NULL);
    taskEXIT_CRITICAL();                /* 退出临界区 */
}

/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
    uint8_t task1_num = 0;
    while(1)
    {
        if(++task1_num == 5)
        {
            task1_num = 0;
            printf("关中断!!\r\n");
            portDISABLE_INTERRUPTS();
            delay_ms(5000);//这里为什么要使用delay延时?
            //因为vTaskDelay函数内部使用到了开关临界区保护,这个会使中断打开了,不符合该实验要求
            //这5s期间,定时器x中断优先级为6的不执行,但是定时器中断7优先级为4的仍然每1s执行(这个1s不是task1的1s)
            //这5s期间,按理说,task1任务也停了,程序卡死这里,即5s后才执行下面的vTaskDelay(1000);
            //没开发板,无法验证呀
            
            //对,就是这样,5s后才会重新运行task1,然后运行5次task1的taskdelay延时,再次进入关开中断
            printf("开中断!!!\r\n");
            portENABLE_INTERRUPTS();
        }
        vTaskDelay(1000);//这个延时涉及到临界区保护,即会影响开关中断
        //这个1s是task1任务的1s,不是上面的定时器中断1s
    }
}
//这里是freeRTOS通过任务来关中断,因此中断优先级为5-15的可以关
//而定时器中断7的抢占优先级为4,因此它不受影响,基本定时器x的为6,它就被freeRTOS关闭了



5、定时器函数

/**
 ****************************************************************************************************
 * @file        btim.c
 * @author      正点原子团队(ALIENTEK)
 * @version     V1.0
 * @date        2022-04-20
 * @brief       基本定时器 驱动代码
 * @license     Copyright (c) 2020-2032, 广州市星翼电子科技有限公司
 ****************************************************************************************************
 * @attention
 *
 * 实验平台:正点原子 阿波罗 F429开发板
 * 在线视频:www.yuanzige.com
 * 技术论坛:www.openedv.com
 * 公司网址:www.alientek.com
 * 购买地址:openedv.taobao.com
 *
 * 修改说明
 * V1.0 20220420
 * 第一次发布
 *
 ****************************************************************************************************
 */

#include "./BSP/LED/led.h"
#include "./BSP/TIMER/btim.h"
#include "./SYSTEM/usart/usart.h"

TIM_HandleTypeDef g_timx_handle;         /* 定时器参数句柄 */
//TIM_HandleTypeDef是typedef重命名的结构体(也可以说结构体类型),g_timx_handle是结构体变量名
TIM_HandleTypeDef g_tim7_handle;         /* 定时器参数句柄 */
/**
 * @brief       基本定时器TIMX定时中断初始化函数
 * @note
 *              基本定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
 *              基本定时器的时钟为APB1时钟的2倍, 而APB1为45M, 所以定时器时钟 = 90Mhz
 *              定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
 *              Ft=定时器工作频率,单位:Mhz
 *
 * @param       arr : 自动重装值。
 * @param       psc : 时钟预分频数
 * @retval      无
 */
void btim_timx_int_init(uint16_t arr, uint16_t psc)
{
    g_timx_handle.Instance = BTIM_TIMX_INT;                      /* 定时器x */
    g_timx_handle.Init.Prescaler = psc;                          /* 分频 */
    g_timx_handle.Init.CounterMode = TIM_COUNTERMODE_UP;         /* 递增计数模式 */
    g_timx_handle.Init.Period = arr;                             /* 自动装载值 */
    HAL_TIM_Base_Init(&g_timx_handle);
    
    HAL_TIM_Base_Start_IT(&g_timx_handle);                       /* 使能定时器x和定时器更新中断 */
}

/* TIM7初始化函数 */
void btim_tim7_int_init(uint16_t arr, uint16_t psc)
{
    g_tim7_handle.Instance = BTIM_TIM7_INT;                      /* 定时器x */
    g_tim7_handle.Init.Prescaler = psc;                          /* 分频 */
    g_tim7_handle.Init.CounterMode = TIM_COUNTERMODE_UP;         /* 递增计数模式 */
    g_tim7_handle.Init.Period = arr;                             /* 自动装载值 */
    HAL_TIM_Base_Init(&g_tim7_handle);
    
    HAL_TIM_Base_Start_IT(&g_tim7_handle);                       /* 使能定时器x和定时器更新中断 */
}
/**
 * @brief       定时器底层驱动,开启时钟,设置中断优先级
                此函数会被HAL_TIM_Base_Init()函数调用
 * @param       无
 * @retval      无
 */
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        BTIM_TIMX_INT_CLK_ENABLE();                     /* 使能TIMx时钟 */
        HAL_NVIC_SetPriority(BTIM_TIMX_INT_IRQn, 6, 0); /* 抢占6,子优先级0 */
        HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn);         /* 开启ITMx中断 */
    }
    if(htim->Instance == BTIM_TIM7_INT)
    {
        BTIM_TIM7_INT_CLK_ENABLE();                     /* 使能TIM7时钟 */
        HAL_NVIC_SetPriority(BTIM_TIM7_INT_IRQn, 4, 0); /* 抢占4,子优先级0 */
        HAL_NVIC_EnableIRQ(BTIM_TIM7_INT_IRQn);         /* 开启ITM7中断 */
    }
}

/**
 * @brief       基本定时器TIMX中断服务函数
 * @param       无
 * @retval      无
 */
void BTIM_TIMX_INT_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_timx_handle);  /* 定时器回调函数 */
}

/* TIM7中断服务函数 */
void BTIM_TIM7_INT_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_tim7_handle);  /* 定时器回调函数 */
}

/**
 * @brief       回调函数,定时器中断服务函数调用
 * @param       无
 * @retval      无
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim->Instance == BTIM_TIMX_INT)
    {
        printf("TIM6优先级为6的正在运行!!!\r\n");
    }else if(htim->Instance == BTIM_TIM7_INT)
    {
        printf("TIM7优先级为4的正在运行!!!!!\r\n");
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值