FreeRTOS(六)----中断配置

本文深入解析FreeRTOSConfig.h配置文件,重点介绍其在实时嵌入式系统中的作用,包括CPU、调度算法、中断优先级及中断管理配置,通过实例展示如何通过配置实现对特定中断的管理和控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      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);
    }
}  

 

测试结果:

以上可知:

  1. 一开始没有关闭中断,所以TIM3和TIM5都正常运行,红框显示部分
  2. 当任务interrupt_task()运行了5次以后就关闭了中断,此时由于TIM5的中断优先级为5,等于configMAX_SYSCALL_INITERRUPT_PRIORITY,因此TIM5被关闭;但是TIM3的中断优先级高于configMAX_SYSCALL_INITERRUPT_PRIORITY,不会被关闭,所以TIM3正常运行,绿框显示部分
  3. 中断关闭5s后,调用函数portENABLE_INTERRUPTS()重新打开中断,且TIM5恢复运行,蓝框显示部分

 

Tist:

  • FreeRTOSConfig.h前部分是一些CPU、调度算法等配置,后部分是中断配置
  • FreeRTOSConfig.h的中断配置使得FreeRTOS系统可以理会和不理会某些中断
### FreeRTOS定时器中断实现使用 #### 创建定时器 在FreeRTOS中,创建一个定时器可以通过`xTimerCreate()`函数完成。此函数允许定义定时器名称、周期长度、是否自动重载(即单次或周期模式)、关联的ID以及超时时应调用的回调函数[^4]。 ```c TimerHandle_t xTimer; const TickType_t xTimerPeriod = pdMS_TO_TICKS(1000); // 设置为1秒 UBaseType_t uxAutoReload = pdTRUE; // 使用pdFALSE表示单次模式 void *pvTimerID = ( void * ) 0; // 可选参数,用于传递给回调函数的数据指针 TimerCallbackFunction_t pxCallbackFunction = vTimerCallback; xTimer = xTimerCreate( "OneSecondTimer", /* 名字 */ xTimerPeriod, /* 超时期限 */ uxAutoReload, /* 自动重启标志位 */ pvTimerID, /* ID */ pxCallbackFunction /* 回调函数 */ ); ``` #### 启动和停止定时器 一旦创建了定时器实例,则可以利用`xTimerStart()`来激活它;如果需要在一个中断上下文中启动定时器,则应该使用`xTimerStartFromISR()`版本。同样地,存在对应的停止单个定时器的方法——`xTimerStop()`及其从中断环境调用的形式`xTimerStopFromISR()`。 #### 处理定时器溢出 对于硬件定时器而言,在达到设定的时间间隔后会产生一个中断请求IRQ,随后程序跳转至相应的中断服务子程序(ISR),在这里执行预设的操作逻辑。而对于软件定时器来说,当计数结束时并不会直接引发真正的硬件中断,而是由内核安排特定的任务去检查是否有任何到期的定时器,并据此触发各自的回调函数[^3]。 #### 中断管理实践案例 为了更好地理解如何管理和配置这些特性,考虑这样一个例子:有两个不同优先级级别的定时器被用来每隔一秒向控制台输出消息。通过调整全局中断使能状态(`vTaskSuspendAll()/xTaskResumeAll()`)可观察到预期的行为变化—关闭期间不会有任何新消息显示出来,而恢复之后又恢复正常运作[^5]。 #### 定时器工作模式对比 值得注意的是,FreeRTOS支持两种主要类型的定时器行为: - **单次模式**:在这种情况下,每当指定的一段时间过去以后只会运行一次预先注册好的处理例程,接着便处于等待下一轮的手动唤醒之中; - **周期模式**:相比之下更为常见也更实用的方式是让定时器不断重复相同的动作直至显式销毁为止。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值