记录一下,方便以后翻阅~
本章内容是接着上一章节进行的实际演练。
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也会被关闭。