基于STM32的FreeRTOS学习之中断测试实验(五)

记录一下,方便以后翻阅~

本章内容是接着上一章节进行的实际演练。

1. 实验目的

FreeRTOS可以屏蔽优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断,不会屏蔽高于其的中断。本次实验就是验证这个说法。本实验使用两个定时器,一个优先级为4,另一个为5,两个定时器每隔1s通过串口输出一串字符串。然后在某个任务中关闭中断一段时间,查看输出情况。

2. 实验设计

本实验设计了两个任务start_task()和interrupt_task(),这两个任务的任务功能分别为:
start_task():创建另外一个任务;
interrupt_task():中断测试任务,任务会调用FreeRTOS的中断函数portDISABLE_INTERRUPTS()来将中断关闭一段时间。

3. 硬件

3.1 正点原子战舰v3开发板(其他板子应该也可以,主要涉及USART,TIM3,TIM5,LED);
3.2 JLINK仿真器。

4. 代码解读

4.1 timer.h和timer.c
因为用到2个定时器,这里选择TIM3和TIM5,其定时器初始化和中断函数如下:

#ifndef __TIMER_H
#define __TIMER_H
#include "stm32f10x.h" 
void TIM3_Int_Init(u16 arr,u16 psc);   // 优先级4,认为高优先级
void TIM5_Int_Init(u16 arr,u16 psc);   // 优先级5, 认为低优先级
#endif
#include "timer.h"
#include "usart.h" 	 
// 函数名称:通用定时器3中断初始化
// 入口参数:arr:自动重装值;psc:时钟预分频数
void TIM3_Int_Init(u16 arr,u16 psc)
{
    
    
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStruct;
    NVIC_InitTypeDef NVIC_InitStruct;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); 	
	// 定时器TIM3初始化
	TIM_TimeBaseStruct.TIM_Period = arr;               
	TIM_TimeBaseStruct.TIM_Prescaler =psc; 
	TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1; 
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;  
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStruct); 
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); 
	// 中断优先级NVIC设置
	NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn; 
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 4;  
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;  
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; 
	NVIC_Init(&NVIC_InitStruct);  
	TIM_Cmd(TIM3, ENABLE);  				 
}
// 函数名称:通用定时器5中断初始化
// 入口参数:arr:自动重装值;psc:时钟预分频数
void TIM5_Int_Init(u16 arr,u16 psc)
{
    
    
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); 	
	// 定时器TIM5初始化
	TIM_TimeBaseStruct.TIM_Period = arr; 			
	TIM_TimeBaseStruct.TIM_Prescaler =psc; 				
	TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1; 
	TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up; 
	TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStruct); 			
	TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE ); 				
	// 中断优先级NVIC设置
	NVIC_InitStruct.NVIC_IRQChannel = TIM5_IRQn;  		
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 5;  	
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;  	
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; 		
	NVIC_Init(&NVIC_InitStruct);  						
	TIM_Cmd(TIM5, ENABLE);  										 
}
// 函数名称:定时器3中断服务函数
void TIM3_IRQHandler(void)
{
    
    
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) 
	{
    
    	printf("TIM3输出.......\r\n"); }
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  
}
// 函数名称:定时器5中断服务函数
void TIM5_IRQHandler(void)
{
    
    
	if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET) 
	{
    
    	printf("TIM5输出.......\r\n");  }
	TIM_ClearITPendingBit(TIM5,TIM_IT_Update); 
}

4.2 main.c文件代码

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "FreeRTOS.h"
#include "task.h"
// 设计第一个任务start_task()
#define START_TASK_PRIO			  1         // 任务优先级
#define START_STK_SIZE 			  256       // 任务堆栈大小	
TaskHandle_t StartTask_Handler;             // 任务句柄
void start_task(void *pvParameters);        // 任务函数
// 设计第二个任务interrupt_task()
#define INTERRUPT_TASK_PRIO		  2         // 任务优先级
#define INTERRUPT_STK_SIZE 		  256       // 任务堆栈大小
TaskHandle_t INTERRUPTTask_Handler;         // 任务句柄
void interrupt_task(void *p_arg);           // 任务函数

// 主函数
int main(void)
{
    
    
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);    // 设置系统中断优先级分组4	 
	delay_init();	    				               // 延时函数初始化	 
	uart_init(115200);					               // 初始化串口
	LED_Init();		  					               // 初始化LED
	TIM3_Int_Init(10000-1,7200-1);		               // 初始化定时器3,定时器周期1S
	TIM5_Int_Init(10000-1,7200-1);		               // 初始化定时器5,定时器周期1S
	// 创建开始任务
	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();                                       // 进入临界区
	// 创建中断测试任务,用来执行开关中断操作
	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();                                        // 退出临界区
}

// 开始任务里创建了第二个任务函数——中断测试任务 
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);											// 延时5s
			printf("打开中断.............\r\n");	  // 打开中断
			portENABLE_INTERRUPTS();
		}
		LED0=~LED0;
		vTaskDelay(1000);
	}
} 

5. 实验结果

在这里插入图片描述
运行一开始,TIM3和TIM5都有输出,当运行5次后,关闭中断,这时只有TIM3有输出(因为优先级为4,高于configMAX_SYSCALL_INTERRUPT_PRIORITY),而TIM5优先级为5,与configMAX_SYSCALL_INTERRUPT_PRIORITY相等,被关闭了。待5s之后,重新打开中断,此时TIM5恢复运行。

最后回顾下一个知识点,configMAX_SYSCALL_INTERRUPT_PRIORITY值在哪里定义的?在FreeRTOSConfig.h文件里!
在这里插入图片描述
如果将configMAX_SYSCALL_INTERRUPT_PRIORITY改为4或更小,则TIM3也会被关闭。

猜你喜欢

转载自blog.csdn.net/Leisure_ksj/article/details/114762188