七、FreeRTOS中断管理简介

本文详细解释了中断的概念,ARMCortex-M和STM32中断优先级配置,以及FreeRTOS如何利用中断管理。通过实例介绍了如何设置中断优先级、FreeRTOS中断服务函数的使用以及一个关于定时器中断的实验,展示了中断在嵌入式开发中的实际应用。
摘要由CSDN通过智能技术生成

一、什么是中断

让CPU打断正常运行的程序,转而去处理紧急的事件(程序),就叫中断

二、中断优先级分组设置、

        ARM Cortex-M 使用了 8 位宽的寄存器来配置中断的优先等级,这个寄存器就是中断优先级配置寄存器

        但STM32,只用了中断优先级配置寄存器的高4位 [7 : 4](bit4~bit7),所以STM32提供了最大16级的中断优先等级

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

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

子优先级:当同时发生具有相同抢占优先级的两个中断时,子优先级数值小的优先执行

一共有 5 种分配方式,对应着中断优先级分组的 5 个组


        FreeRTOS使用的NVIC_PRIORITYGROUP_4,通过调用函数

HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4)即可完成设置(在HAL_Init中设置)

特点:

1、低于configMAX_SYSCALL_INTERRUPT_PRIORITY优先级的中断里才允许调用FreeRTOS 的API函数

2、建议将所有优先级位指定为抢占优先级位,方便FreeRTOS管理

3、中断优先级数值越小越优先,任务优先级数值越大越优先

三、中断相关寄存器

三个系统中断优先级配置寄存器,分别为 SHPR1、 SHPR2、 SHPR3

SHPR1寄存器地址:0xE000ED18

SHPR2寄存器地址:0xE000ED1C

SHPR3寄存器地址:0xE000ED20

三个中断屏蔽寄存器,分别为 PRIMASK、 FAULTMASK 和BASEPRI

FreeRTOS所使用的中断管理就是利用的BASEPRI这个寄存器

BASEPRI:屏蔽优先级低于某一个阈值的中断

比如: BASEPRI设置为0x50(),代表中断优先级在5~15内的均被屏蔽,0~4的中断优先级正常执行

BASEPRI:屏蔽优先级低于某一个阈值的中断,当设置为0时,则不关闭任何中断

关中断程序示例:

#define portDISABLE_INTERRUPTS() 		vPortRaiseBASEPRI()
static portFORCE_INLINE void vPortRaiseBASEPRI( void ) 
{ 
	uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY; 
	__asm 
	{
		msr basepri, ulNewBASEPRI 
		dsb 
		isb
	} 
}
#define configMAX_SYSCALL_INTERRUPT_PRIORITY            ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY        5      /* FreeRTOS可管理的最高中断优先级 */ 

当BASEPRI设置为0x50时:

 在中断服务函数中调度FreeRTOS的API函数需注意:

1、中断服务函数的优先级需在FreeRTOS所管理的范围内

2、在中断服务函数里边需调用FreeRTOS的API函数,必须使用带“FromISR”后缀的函数

四、FreeRTOS中断管理实验

1、实验目的:学会使用FreeRTOS的中断管理!
本实验会使用两个定时器,一个优先级为4,一个优先级为6,注意:系统所管理的优先级范围:5~15,
现象:两个定时器每1s,打印一段字符串,当关中断时,停止打印,开中断时持续打印。

2、实验设计:将设计2个任务:start_task、task1

 添加定时器7驱动

TIM_HandleTypeDef 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");
    }
}

 

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);
            printf("开中断!!!\r\n");
            portENABLE_INTERRUPTS();
        }
        vTaskDelay(1000);
    }
}



评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值