【FreeRTOS-中断实验】

本文详细介绍了如何在FreeRTOS中使用定时器3和4进行中断实验,探讨了不同优先级对中断屏蔽的影响,通过TIM3和TIM4的配置,展示了4和5级优先级中断的特性和5级及以上优先级的中断屏蔽效果。

FreeRTOS-中断实验

本次实验简单验证优先级问题
用定时器3和定时器4优先级分别配置4和5 优先级低于5的时候FreeRTOS中断不能屏蔽而大于等于5的优先级会屏蔽

在这里插入图片描述

FreeRTOS开关中断函数为portENABLE_INTERRUPTS ()和portDISABLE_INTERRUPTS(),这两个函数其实是宏定义,在portmacro.h中有定义,

#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI() //关闭中断
#define portENABLE_INTERRUPTS() vPortSetBASEPRI(0)  //开启中断

time.h

#ifndef _TIME_H_
#define _TIME_H_

#include "stm32f10x.h"

void Init_TIM3(void);
void Init_TIM4(void);

#endif

timc.c

#include "time.h"
#include "usart.h"


void Init_TIM3(void)
{
	TIM_TimeBaseInitTypeDef TIME3_InitStructure;
	NVIC_InitTypeDef        TIM3_NVICStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	TIME3_InitStructure.TIM_ClockDivision  = TIM_CKD_DIV1;
	TIME3_InitStructure.TIM_CounterMode    = TIM_CounterMode_Up;
	TIME3_InitStructure.TIM_Period         = 10000 - 1;
	TIME3_InitStructure.TIM_Prescaler      = 3600 - 1;
	TIM_TimeBaseInit(TIM3,&TIME3_InitStructure);
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
	
	TIM3_NVICStructure.NVIC_IRQChannel     =  TIM3_IRQn;
	TIM3_NVICStructure.NVIC_IRQChannelCmd  =	ENABLE;
	TIM3_NVICStructure.NVIC_IRQChannelPreemptionPriority =	4;
	TIM3_NVICStructure.NVIC_IRQChannelSubPriority        = 	0;
	NVIC_Init(&TIM3_NVICStructure);
	TIM_Cmd(TIM3,ENABLE);
	
}



void Init_TIM4(void)
{
	TIM_TimeBaseInitTypeDef TIME4_InitStructure;
	NVIC_InitTypeDef        TIM4_NVICStructure;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
	
	TIME4_InitStructure.TIM_ClockDivision  = TIM_CKD_DIV1;
	TIME4_InitStructure.TIM_CounterMode    = TIM_CounterMode_Up;
	TIME4_InitStructure.TIM_Period         = 10000 - 1;
	TIME4_InitStructure.TIM_Prescaler      = 3600 - 1;
	TIM_TimeBaseInit(TIM4,&TIME4_InitStructure);
	TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
	
	TIM4_NVICStructure.NVIC_IRQChannel     =  TIM4_IRQn;
	TIM4_NVICStructure.NVIC_IRQChannelCmd  =	ENABLE;
	TIM4_NVICStructure.NVIC_IRQChannelPreemptionPriority =	5;
	TIM4_NVICStructure.NVIC_IRQChannelSubPriority        = 	0;
	NVIC_Init(&TIM4_NVICStructure);
	TIM_Cmd(TIM4,ENABLE);
}



void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update) != RESET)
	{
		printf("time3 interrupt\r\n");
		
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
	
}


void TIM4_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM4,TIM_IT_Update) != RESET)
	{
		printf("time4 interrupt\r\n");
		
	}
	TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
	
}

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "time.h"


/*--------------------------------------------------------------------
*FreeRTOS中断实验
*Date:2022-2-13
*Author:小殷同学
*--------------------------------------------------------------------*/


//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define INTERRUPT_TASK_PRIO		2
//任务堆栈大小	
#define INTERRUPT_STK_SIZE 		50  
//任务句柄
TaskHandle_t INTERRUPTTask_Handler;
//任务函数
void interrupt_task(void *pvParameters);



int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	  
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	Init_TIM3();
	Init_TIM4();
	 
	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    //创建LED0任务
    xTaskCreate((TaskFunction_t )interrupt_task,     	
                (const char*    )"interrupt_task",   	
                (uint16_t       )INTERRUPT_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )INTERRUPT_TASK_PRIO,	
                (TaskHandle_t*  )&INTERRUPTTask_Handler);          
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//LED0任务函数 
void interrupt_task(void *pvParameters)
{
  char task_num = 0;  
	while(1)
    {
        task_num++;
			//低于5的中断优先级不会被屏蔽 TIM3 中断优先级配置4 正常运行
			if(task_num == 5)
			{
				printf(" 关闭中断 \r\n");
				portDISABLE_INTERRUPTS();
				delay_xms(5000);
				printf(" 开启中断 \r\n");
				portENABLE_INTERRUPTS();				
			}
			LED0 = ~LED0;
			vTaskDelay(1000);
    }
}      

在这里插入图片描述

### FreeRTOS 中断测试实验方法与示例代码 #### 实验概述 为了验证 FreeRTOS中断的支持以及 `configMAX_SYSCALL_INTERRUPT_PRIORITY` 参数的作用,可以通过设计一个简单的实验来观察不同优先级的中断行为。此实验可以基于 STM32 平台实现。 --- #### 系统配置 在开始编写代码之前,需要完成以下基本配置: 1. **设置 `configMAX_SYSCALL_INTERRUPT_PRIORITY`** 在 FreeRTOSConfig.h 文件中定义 `configMAX_SYSCALL_INTERRUPT_PRIORITY` 值。例如,将其设为 5 表示只有优先级大于等于 5 的中断才能安全调用 FreeRTOS API[^2]。 ```c #define configMAX_SYSCALL_INTERRUPT_PRIORITY (5 << __NVIC_PRIO_BITS) ``` 2. **配置 SYSTICK 定时器** 使用 `configTICK_RATE_HZ` 设置系统滴答频率,默认值为 1000 Hz(即每毫秒触发一次中断)。如果需要更低的频率,可以在 FreeRTOSConfig.h 中修改该参数[^3]。 ```c #define configTICK_RATE_HZ ((TickType_t)1000) ``` 3. **启用 NVIC 中断优先级分组** 在启动文件中初始化 NVIC,并选择合适的优先级分组模式。例如,在 STM32F1xx 下可以选择分组 4(子优先级占全部位数),以便更灵活地分配优先级[^1]。 ```c NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); ``` --- #### 测试方案 以下是具体的测试流程和对应的代码片段: ##### 方案描述 - 创建两个定时器 TIM1 和 TIM2。 - 将 TIM1 的中断优先级设置为 4,TIM2 的中断优先级设置为 5。 - 每隔一秒分别通过串口打印一条消息。 - 在某个任务中禁用中断一段时间,观察两者的输出差异。 ##### 示例代码 ###### 初始化定时器 ```c void Timer_Init(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 启动 TIM2 时钟 TIM_TimeBaseInitTypeDef TIM_InitStruct; TIM_InitStruct.TIM_Period = SystemCoreClock / 10; // 每秒计满一次 TIM_InitStruct.TIM_Prescaler = 9; TIM_InitStruct.TIM_ClockDivision = TIM_CKD_DIV1; TIM_InitStruct.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_InitStruct); TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); // 开启更新中断 } ``` ###### 中断服务程序 ```c // TIM2 中断优先级为 5 void TIM2_IRQHandler(void) { if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { printf("Timer 2 Interrupt\n"); TIM_ClearITPendingBit(TIM2, TIM_IT_Update); } } // TIM1 中断优先级为 4 void TIM1_UP_IRQHandler(void) { if (TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET) { printf("Timer 1 Interrupt\n"); TIM_ClearITPendingBit(TIM1, TIM_IT_Update); } } ``` ###### 主任务逻辑 ```c void vTaskFunction(void *pvParameters) { while (1) { taskENTER_CRITICAL(); // 关闭中断 vTaskDelay(pdMS_TO_TICKS(100)); // 模拟长时间临界区操作 taskEXIT_CRITICAL(); // 打开中断 vTaskDelay(pdMS_TO_TICKS(1000)); } } ``` --- #### 结果分析 运行上述代码后,可以看到以下现象: - 当进入临界区 (`taskENTER_CRITICAL`) 时,优先级为 4 的 TIM1 中断被完全屏蔽,而优先级为 5 的 TIM2 中断仍然能够正常执行并输出日志。 - 这表明低于 `configMAX_SYSCALL_INTERRUPT_PRIORITY` 的中断无法打断当前的任务或临界区域操作。 --- ### 注意事项 1. 如果应用中有多个外设共享同一中断线,则需特别注意其优先级分配策略。 2. 调试过程中建议使用调试工具(如 ST-LINK 或 JTAG 探针)捕获实时数据流,便于定位潜在问题。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

华阳电子工作室

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

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

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

打赏作者

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

抵扣说明:

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

余额充值