FreeRTOS中断管理(STM32F103C8T6)

 

 

FreeRTOS 中断配置项

FreeRTOSConfig.h 文件中有 6 个与中断相关的 FreeRTOS 配置项,如表 3.2.7.1 所示。这 6 个 FreeRTOS 配置项在 3.2.7 小节“中断嵌套行为相关定义”中已经做了相应的描述,本小节主 要根据本章 4.1 小节“ARM Cortex-M 中断”,为读者分析,如何配置这 6 个中断相关的 FreeRTOS 配置项。

1. configPRIO_BITS 此宏是用于辅助配置的宏,主要用于辅助配置宏 configKERNEL_INTERRUPT_PRIORITY 和宏configMAX_SYSCALL_INTERRUPT_PRIORITY 的,此宏应定义为MCU的8位优先级配 置寄存器实际使用的位数,因为 STM32 只使用到了中断优先级配置寄存器的高4位,因此,此宏应配置为4

2. configLIBRARY_LOWEST_INTERRUPT_PRIORITY 此宏是用于辅助配置宏 configKERNEL_INTERRUPT_PRIORITY 的,此宏应设置为 MCU 的最低优先等级,因为 STM32 只使用了中断优先级配置寄存器的高 4 位,因此 MCU 的最低优 先等级就是 2^4-1=15,因此,此宏应配置为 15

3. configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 此宏是用于辅助配置宏 configMAX_SYSCALL_INTERRUPT_PRIORITY 的,此宏适用于配置 FreeRTOS 可管理的最高优先级的中断,此功能就是操作 BASEPRI 寄存器来实现的。此宏的 值可以根据用户的实际使用场景来决定,本教程的配套例程源码全部将此宏配置为 5,即中断 优先级高于 5 的中断不受 FreeRTOS 影响,如下图所示:

4. configKERNEL_INTERRUPT_PRIORITY 此宏应配置为 MCU 的最低优先级在中断优先级配置寄存器中的值,在 FreeRTOS 的源码 中,使用此宏将 SysTick 和 PenSV 的中断优先级设置为最低优先级。因为 STM32 只使用了中 断优先级配置寄存器的高 4 位,因此,此宏应配置为最低中断优先级在中断优先级配置寄存器 高 4 位的表示,即(configLIBRARY_LOWEST_INTERRUPT_PRIORITY<<(8-configPRIO_BITS))

5. configMAX_SYSCALL_INTERRUPT_PRIORITY 此宏用于配置 FreeRTOS 可管理的最高优先级的中断,在 FreeRTOS 的源码中,使用此宏来 打开和关闭中断。因为 STM32 只使用了中断优先级配置寄存器的高 4 位,因此,此宏应配置为 (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY<<(8-configPRIO_BITS))

6. configMAX_API_CALL_INTERRUPT_PRIORITY 此宏为宏 configMAX_SYSCALL_INTERRUPT_PRIORITY 的新名称,只被用在 FreeRTOS 官方一些新的移植当中,此宏于宏 configMAX_SYSCALL_INTERRUPT_PRIORITY 是等价的。

STM32F103C8T6实际源码如下图所示:

FreeRTOS 开关中断

 前面说过,FreeRTOS 使用 BASEPRI 寄存器来管理受 FreeRTOS 管理的中断,而不受 FreeRTOS 管理的中断不受 FreeRTOS 开关中断的影响,那么 FreeRTOS 开关中断是如何操作的 呢?首先来看一下 FreeRTOS 开关中断的宏定义,代码如下所示:

FreeRTOS 进出临界区

       临界区是指那些必须完整运行的区域,在临界区中的代码必须完整运行,不能被打断。

       例如一些使用软件模拟的通信协议,通信协议在通信时,必须严格按照通信协议的时序进行,不能被打断。

       FreeRTOS 在进出临界区的时候,通过关闭和打开受 FreeRTOS 管理的中断,以保护临界区中的代码。FreeRTOS 的源码中就包含了许多临界区的代码,这部分代码都是用临界区进 行保护,用户在使用 FreeRTOS 编写应用程序的时候,也要注意一些不能被打断的操作,并为这部分代码加上临界区进行保护。 对于进出临界区, FreeRTOS 的源码中有四个相关的宏定义 , 分别为 taskENTER_CRITICAL() 、 taskENTER_CRITICAL_FROM_ISR() 、 taskEXIT_CRITICAL() 、 taskEXIT_CRITICAL_FROM_ISR(x),这四个宏定义分别用于在中断和非中断中进出临界区,定 义代码如下所示:

FreeRTOS 中断测试实验

      本实验主要用于测试 FreeRTOS 打开和关闭中断对中断的影响。因为在本demo中,          
       configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY的值设置为5,即FreeRTOS能够管理的最大优先级是5。所以这里定义了两个定时器任务,定时器2和定时器3,定时器2的中断优先级为4,定时器3的中断优先级为5。
       按照设计预期,程序会在一定的时间范围内关闭中断。由于定时器3的中断优先级为5,所以受到FreeRTOS的中断管理,当FreeRTOS关闭中断时,定时器3的中断响应也会停止,当FreeRTOS中断开启时,定时器3的中断响应又会恢复。而定时器2的中断优先级为4,不受FressRTOS中断管理,所以会一直保持触发。
TIM2和TIM3中断配置函数:
TIM_TimeBaseInitTypeDef  TIM3_TimeBaseStructure;
TIM_TimeBaseInitTypeDef  TIM2_TimeBaseStructure;

NVIC_InitTypeDef TIM3_NVIC_InitStructure;
NVIC_InitTypeDef TIM2_NVIC_InitStructure;

void TIM3_Init(unsigned int arr, unsigned int psc)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 , ENABLE);
    TIM_DeInit(TIM3);
    
    TIM3_TimeBaseStructure.TIM_Prescaler = psc;                           
    TIM3_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;          
    TIM3_TimeBaseStructure.TIM_Period = arr;
    TIM3_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;              
    
    TIM_TimeBaseInit(TIM3, &TIM3_TimeBaseStructure);
    TIM_ClearFlag(TIM3, TIM_FLAG_Update);                                          
    TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
    TIM_Cmd(TIM3, ENABLE);                                                                
    
    TIM3_NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;      
    TIM3_NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
    TIM3_NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    
    TIM3_NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&TIM3_NVIC_InitStructure);
}

void TIM2_Init(unsigned int arr, unsigned int psc)
{
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);
    TIM_DeInit(TIM2);
    
    TIM2_TimeBaseStructure.TIM_Prescaler = psc;
    TIM2_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;         
    TIM2_TimeBaseStructure.TIM_Period = arr;
    TIM2_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;                 
    
    TIM_TimeBaseInit(TIM2, &TIM2_TimeBaseStructure);
    TIM_ClearFlag(TIM2, TIM_FLAG_Update);                                          
    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
    TIM_Cmd(TIM2, ENABLE);                                                                
    
    TIM2_NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;      
    TIM2_NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;
    TIM2_NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    
    TIM2_NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&TIM2_NVIC_InitStructure);
}

TIM2和TIM3中断配置函数参数调用:

计算方式为:72000000 / (7200)* 10000 = 1S。即TIM2和TIM3都会以1S的频率产生中断。

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
TIM2_Init(10000 - 1, 7200 - 1);
TIM3_Init(10000 - 1, 7200 - 1);

TIM2和TIM3中断响应和处理函数:

注:一定要注意清空中断标志位,不然中断程序会一直触发!

void TIM2_IRQHandler(void)
{
    if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET )
    {
       TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);
       HAL_TIM_PeriodElapsedCallback(&TIM2_TimeBaseStructure);
    }
}


void TIM3_IRQHandler(void)
{
    if ( TIM_GetITStatus(TIM3 , TIM_IT_Update) != RESET )
    {
       TIM_ClearITPendingBit(TIM3 , TIM_FLAG_Update);
       HAL_TIM_PeriodElapsedCallback(&TIM3_TimeBaseStructure);
    }
}


void HAL_TIM_PeriodElapsedCallback(TIM_TimeBaseInitTypeDef *htim)
{
    if(htim == (&TIM3_TimeBaseStructure))
    {
        printf("\r\n");
        printf("TIM3输出......\r\n");
    }else if(htim == (&TIM2_TimeBaseStructure))
    {
        printf("\r\n");
        printf("TIM2输出......\r\n");
    }
}

us和ms级的延时函数:

void delay_us(u32 nus)
{        
    uint32_t fac_us;
    uint32_t ticks;
    uint32_t told, tnow, tcnt = 0;
    uint32_t reload = SysTick->LOAD;
    fac_us = SystemCoreClock / 1000000;
    ticks = nus * fac_us;
    told = SysTick->VAL;
    while (1) {
        tnow = SysTick->VAL;
        if (tnow != told) {
            if (tnow < told)tcnt += told - tnow;
            else tcnt += reload - tnow + told;
            told = tnow;
            if (tcnt >= ticks)break;
        }
    };                    
}  

void delay_xms(u32 nms)
{
    u32 i;
    for(i=0;i<nms;i++) delay_us(1000);
}

TIM2和TIM3中断实验调试任务函数:

unsigned char led_change_flag = 0;
void interrupt_task(void *pvParameters)
{
    static u32 total_num = 0;
    while(1)
    {
        total_num += 1;
        
        if(total_num == 5)
        {
            printf("关闭中断......\r\n");
            portDISABLE_INTERRUPTS();
            
            delay_xms(5000);
            
            printf("打开中断......\r\n");
            portENABLE_INTERRUPTS();
        }
        
        led_change_flag = ~led_change_flag;
        if(led_change_flag)
        {
             LED_GREEN_ON;
       LED_RED_ON;             
        }else
        {
             LED_GREEN_OFF;
             LED_RED_OFF;
        }
        
        vTaskDelay(1000);
    }
}

实验验证效果:

结论:验证成功!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

moon2shine

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值