FreeRTOSConfig.h前部分是一些CPU、调度算法等配置,后部分是中断配置。在FreeRTOSConfig.h中,能够知道config前缀宏的映射内容,下面是部分的注释:
#define configUSE_PREEMPTION 1 //0-协程调度,1-抢占式调度
#define configUSE_IDLE_HOOK 0 //0-除能空闲任务的钩子函数,1-使能
#define configUSE_TICK_HOOK 0 //0-除能时间片钩子函数,1-使能
#define configCPU_CLOCK_HZ ( SystemCoreClock ) //设置CPU频率
#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) //设置滴答计时器的中断频率,为HZ/1000=1ms
#define configMAX_PRIORITIES ( 5 ) //任务优先级是0~(configMAX_PRIORITIES-1)
#define configMINIMAL_STACK_SIZE ( ( unsigned short ) 130 ) //设置空闲任务的堆栈大小,单位是字(4字节)
#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 75 * 1024 ) ) //设置系统总堆栈大小
#define configMAX_TASK_NAME_LEN ( 10 ) //设置任务名最大长度
#define configUSE_TRACE_FACILITY 1 //0-除能可视化跟踪调试,1-使能
#define configUSE_16_BIT_TICKS 0 //节拍计时器变量范围,0-16位,1-32位
#define configIDLE_SHOULD_YIELD 1 //0-空闲任务不会让出CPU给同等优先级的任务,1-会让出CPU
#define configUSE_MUTEXES 1 //0-除能互斥信号量,1-使能
#define configQUEUE_REGISTRY_SIZE 8 //0-除能内核调试中查看队列和信号量数量,>0-可以注册的数量
#define configCHECK_FOR_STACK_OVERFLOW 0 //0-除能堆栈溢出检测,1-使能
#define configUSE_RECURSIVE_MUTEXES 1 //0-除能递归互斥信号量,1-使能
#define configUSE_MALLOC_FAILED_HOOK 0 //0-除能malloc失败时调用的钩子函数,1-使能
#define configUSE_APPLICATION_TASK_TAG 0 //0-除能一些应用程序钩子函数,1-使能
#define configUSE_COUNTING_SEMAPHORES 1 //0-除能计数信号量,1-使能
#define configGENERATE_RUN_TIME_STATS 0 //0-除能时间统计功能,1-使能
……
//硬件相关的中断位数
#ifdef __NVIC_PRIO_BITS
/* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4 /* 15 priority levels */
#endif
//最低优先级,一般与configPRIO_BITS对应,2^configPRIO_BITS-1
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0xf
//可管理的最大优先级(设置STM的BASEPRI寄存器)
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
//真正的中断优先级,用于设置滴答中断等等的优先级
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
//真正的中断优先级,最大可以使用FreeRTOS-API的中断优先级
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
前部分的内容是硬件能运行的基本配置,而后部分的中断配置是实时嵌入式系统的需求配置,中断配置内存如下:
中断优先级数量的寄存器位数:(STM32F4)4位,16个优先级
最低优先级:2^4-1=15
FreeRTOS可管理的最大优先级:设置为5,意味着优先级>=5的优先级不被FreeRTOS控制
为了测试 --> 可管理的最大优先级为5,也就优先级<5的中断不归FreeRTOS管理,逻辑图如下:
定时器使用通用定时器3和4,两者都是定时1s,定时器3的优先级是4,定时器5的优先级是5,前者可以被FreeRTOS管理,后者超过了FreeRTOS管理的优先级、
//timer.c
void TIM3_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); ///使能TIM3时钟
TIM_TimeBaseInitStructure.TIM_Period = arr; //自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断
TIM_Cmd(TIM3,ENABLE); //使能定时器3
NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x04; //抢占优先级4
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void TIM5_Int_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //使能TIM5时钟
TIM_TimeBaseInitStructure.TIM_Period = arr; //自动重装载值
TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStructure); //初始化TIM5
TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE); //允许定时器5更新中断
TIM_Cmd(TIM5,ENABLE); //使能定时器5
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn; //定时器5中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x05; //抢占优先级5
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x00; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//定时器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); //清除中断标志位
}
//main.c
TIM3_Int_Init(10000-1,8400-1); //初始化定时器3,定时器周期1S
TIM5_Int_Init(10000-1,8400-1); //初始化定时器5,定时器周期1S
//开始任务任务函数
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);
}
}
测试结果:
以上可知:
- 一开始没有关闭中断,所以TIM3和TIM5都正常运行,红框显示部分。
- 当任务interrupt_task()运行了5次以后就关闭了中断,此时由于TIM5的中断优先级为5,等于configMAX_SYSCALL_INITERRUPT_PRIORITY,因此TIM5被关闭;但是TIM3的中断优先级高于configMAX_SYSCALL_INITERRUPT_PRIORITY,不会被关闭,所以TIM3正常运行,绿框显示部分。
- 中断关闭5s后,调用函数portENABLE_INTERRUPTS()重新打开中断,且TIM5恢复运行,蓝框显示部分。
Tist:
- FreeRTOSConfig.h前部分是一些CPU、调度算法等配置,后部分是中断配置
- FreeRTOSConfig.h的中断配置使得FreeRTOS系统可以理会和不理会某些中断