【STM32F1】RTOS中断管理

1. 实验前置知识

RTOS可以控制的中断优先级在5~15范围内的,0-4的中断优先级不属于RTOS的控制范围。后面会通过实验来验证。这个管理范围配置如下:

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         15                  /* 中断最低优先级 */
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5                   /* FreeRTOS可管理的最高中断优先级 */

中断优先级配置示例图如下:

 FreeRTOS开关中断 

开关中断的宏定义如下,我们在开启关闭中断的时候用这里的宏就行的。

#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
#define taskDISABLE_INTERRUPTS() portDISABLE_INTERRUPTS()
#define taskENABLE_INTERRUPTS() portENABLE_INTERRUPTS()

FreeRTOS进出临界区 

这边临界区的概念是:临界区内的代码不允许打断,所以进入的时候我们会关闭中断,出去的时候会开启中断,当然这里提到的中断指的是被RTOS所管理的中断。进出代码如下:

/* 进入临界区 */
#define taskENTER_CRITICAL() portENTER_CRITICAL()
#define portENTER_CRITICAL() vPortEnterCritical()
/* 中断中进入临界区 */
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()
/* 退出临界区 */
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
#define portEXIT_CRITICAL() vPortExitCritical()
/* 中断中退出临界区 */
#define taskEXIT_CRITICAL_FROM_ISR(x) portCLEAR_INTERRUPT_MASK_FROM_ISR(x)
#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)

普通进入临界区的宏taskENTER_CRITICAL()与中断中进入进阶区的宏taskENTER_CRITICAL_FROM_ISR(),前者是任务级的,进入临界区后屏蔽任务之间相互抢资源。后者是中断中进入的。taskENTER_CRITICAL()宏展开后是函数vPortEnterCritical()。下面通过实验来测试一下。

2. FreeRTOS中断测试实验

目的与功能:主要用于测试FreeRTOS打开和关闭中断的影响。设计了两个任务,start_task用于初始化定时器和创建其他任务。task1用于打开和关闭中断。

这部分代码在freertos_demo函数中初始化了定时器6和7,并创建start_task任务。函数执行先进入临界区,初始化定时器之后创建start_task并退出临界区。接着start_task任务创建task1任务,在task1任务中测试rtos开启中断与关闭中断的影响。

void freertos_demo(void){
	 taskENTER_CRITICAL();
	//初始化tim6 tim7
	 btim_timx_int_init(10000-1, 7200-1);
	 btim_tim7_int_init(10000-1, 7200-1);
	
	//创建开始任务
	 xTaskCreate( 
								(TaskFunction_t ) start_task,
                (const char*    ) "start_task", /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                (uint16_t       ) START_TASK_SIZE,
                (void *         ) NULL,
                (UBaseType_t    ) START_TASK_PRIO,
                (TaskHandle_t*  ) &STARTTask_Handler);
	 //开启任务调度
	 vTaskStartScheduler();
	 taskEXIT_CRITICAL(); //退出临界区
}

/*开始任务任务函数
* 该任务用于创建其他任务,本实验创建LED0任务和LED1任务。
* 功能:LED0与LED1以不同频率进行闪烁
*/

void start_task(void *pvParameters){
	   //进入临界区,目的是为了打断中断
	   taskENTER_CRITICAL();
	   //创建任务1
	 	 xTaskCreate( 
								(TaskFunction_t ) task1_task,
                (const char*    ) "task1_task", /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
                (uint16_t       ) TASK1_TASK_SIZE,
                (void *         ) NULL,
                (UBaseType_t    ) TASK1_TASK_PRIO,
                (TaskHandle_t*  ) &TASK1Task_Handler);

	   vTaskDelete(NULL);   //删除开始任务,为NULL默认删除该任务,或者写该任务句柄
		 taskEXIT_CRITICAL(); //退出临界区
}

/*
*task1任务
*/
void task1_task(void *pvParameters){
	uint32_t task1_num = 0;
	while(1)
	{
		if(++task1_num == 5)
		{
			printf("FreeRTOS关闭中断\r\n");
			portDISABLE_INTERRUPTS();
		  delay_ms(5000);
			printf("FreeRTOS开启中断\r\n");
		  portENABLE_INTERRUPTS();
		}
		vTaskDelay(1000);
	
	}

定时器6设置中断优先级为4及定时器7设置中断优先级为6,定时器7实在FreeRTOS管理范围内的,而定时器6不在。我们在中断函数中打印看是那个定时器输出的,以进行对比,达到验证FreeRTOS管理中断优先级在5-15之间的中断。定时器初始化函数代码如下:

TIM_HandleTypeDef g_timx_handle;      /* 定时器x句柄 */
TIM_HandleTypeDef g_tim7_handle;      /* 定时器7句柄 */

/**
 * @brief       基本定时器TIMX定时中断初始化函数
 * @note
 *              基本定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
 *              基本定时器的时钟为APB1时钟的2倍, 而APB1为36M, 所以定时器时钟 = 72Mhz
 *              定时器溢出时间计算方法: 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)
{
    BTIM_TIMX_INT_CLK_ENABLE();                                      /* 使能TIMx时钟 */
    
    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;                                 /* 自动装载值 */
    g_timx_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;       /* 时钟分频因子 */
    HAL_TIM_Base_Init(&g_timx_handle);
    
    HAL_NVIC_SetPriority(BTIM_TIMX_INT_IRQn, 4, 0);  /* 设置中断优先级,抢占优先级1,子优先级3 */
    HAL_NVIC_EnableIRQ(BTIM_TIMX_INT_IRQn);          /* 开启ITMx中断 */
    
    HAL_TIM_Base_Start_IT(&g_timx_handle);           /* 使能定时器x和定时器x更新中断 */
    
    
}


/**
 * @brief       基本定时器TIM7定时中断初始化函数
 * @note
 *              基本定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
 *              基本定时器的时钟为APB1时钟的2倍, 而APB1为36M, 所以定时器时钟 = 72Mhz
 *              定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
 *              Ft=定时器工作频率,单位:Mhz
 *
 * @param       arr: 自动重装值。
 * @param       psc: 时钟预分频数
 * @retval      无
 */
void btim_tim7_int_init(uint16_t arr, uint16_t psc)
{
    BTIM_TIM7_INT_CLK_ENABLE();                                      /* 使能TIM7时钟 */
    
    g_tim7_handle.Instance = BTIM_TIM7_INT;                          /* 通用定时器7 */
    g_tim7_handle.Init.Prescaler = psc;                              /* 分频 */
    g_tim7_handle.Init.CounterMode = TIM_COUNTERMODE_UP;             /* 向上计数器 */
    g_tim7_handle.Init.Period = arr;                                 /* 自动装载值 */
    g_tim7_handle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;       /* 时钟分频因子 */
    HAL_TIM_Base_Init(&g_tim7_handle);
    
    HAL_NVIC_SetPriority(BTIM_TIM7_INT_IRQn, 6, 0);  /* 设置中断优先级,抢占优先级1,子优先级3 */
    HAL_NVIC_EnableIRQ(BTIM_TIM7_INT_IRQn);          /* 开启ITMx中断 */
    
    HAL_TIM_Base_Start_IT(&g_tim7_handle);           /* 使能定时器x和定时器x更新中断 */
    
    
}


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

void BTIM_TIM7_INT_IRQHandler(void)
{
    HAL_TIM_IRQHandler(&g_tim7_handle);
}


/**
 * @brief       定时器更新中断回调函数
* @param        htim:定时器句柄指针
 * @retval      无
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if (htim == (&g_timx_handle))
    {
        printf("TIM6输出\r\n");
    }
		else if (htim == (&g_tim7_handle))
		{
				printf("TIM7输出\r\n");
		}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

快乐大队队长

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

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

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

打赏作者

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

抵扣说明:

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

余额充值