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也会被关闭。
————————————————
版权声明:天亮继续睡
|