在应用freeRtos的时候经常会有中断影响程序运行,所以中断设置需要谨慎
1.0到4级的中断,freertos不能管理关闭或开启,5到15可以调用以FromISR结尾的API函数

void interrupt_task(void *pvParameters)
{
    u8 ui = 0;
    while(1)
    {
        ui++;
        if(ui == 20)
        {
            portDISABLE_INTERRUPTS();
            printf("中断关闭!\r\n");
            delay_xms(5000);
            portENABLE_INTERRUPTS();
            printf("中断开启!\r\n");
            //delay_xms(50000);
        }
        
        vTaskDelay(500);
    }
    
```以上代码即可关闭5到15级的中断,这各中断优先级是在一个stm32外设初始化时NVIC的设置中设置,如上一篇文章中所讲的外部中断恢复任务2,该中断优先级为6

```c

	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;		//外部中断4     这个中断通道在stm32F4xx.h找  里面解释了每个中断含义
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x06;//抢占优先级6
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00;	//子优先级0
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//使能外部中断通道
	NVIC_Init(&NVIC_InitStructure);							//配置

2.中断优先级一把设为4 全为抢占优先级
这样就有16个优先级抢占可以选

3.任务临界函数会开启中断关闭5-15

关掉这些中断,就会保护当前执行的任务或者中断中的程序4.不会被中断打断,完整的执行

这些内核控制函数都会分为用在任务中的或者用在中断中的,

如:

cubemx设置freertos 中断优先级_优先级

4.队列是为了数据通信 中断到任务 任务到任务
任何任务都可以从队列读消息也可以发消息,队列是公共的资源
创建队列:
(1)先在主函数前创建队列句柄,用于其他任务后续操作

QueueHandle_t Key_Queue;
#define uxQueueLength 1        //length of queue
#define uxItemSize sizeof(u8)  //size of Item

之后在开始任务中创建队列

Key_Queue = xQueueCreate(uxQueueLength,uxItemSize);

5.向队列发送消息

void task1_task(void *pvParameters)
{
    u8 ui = 0;
    u8 key = 0;
    BaseType_t err;
    while(1)
    {
        key = KEY_Scan(0);
        if((Key_Queue != NULL)&&key)
            err = xQueueSendToBack( Key_Queue, &key, 10 );
        if(err == errQUEUE_FULL)
            printf("发送队列失败,队列已满");
       
        vTaskDelay(7);
        
        
    }
}

10代表入队阻塞时间,如果入队时,队列为满,则等待10ms,

cubemx设置freertos 中断优先级_单片机_02


后向入队就是正常先进先出,同样该函数分为任务和中断中的执行函数。

6.出队

void task2_task(void *pvParameters)
{
    u8 ui = 0;
    u8 key_r = 0;
    BaseType_t flag;
    while(1)
    {
        if(Key_Queue != NULL)
        {
            flag = xQueueReceive( Key_Queue, &key_r, portMAX_DELAY );
            if(flag == pdTRUE)
            {
                printf("key值为%d \r\n",key_r);
            }
        }
        vTaskDelay(7);
    }
}

portMAX_DELAY 是指无限时阻塞,当出队但队列是空的时候这个任务就会一直死等至队列有数据,相当于进入阻塞态
另外,如果中断函数中要向队列发数据或者收数据,需要在这个文件中声明队列。

7.这里插入一个知识点,在中断中恢复任务时要判断是否需要上下文切换。
void EXTI9_5_IRQHandler(void)
{
BaseType_t YieldRequired;

delay_xms(20);	//消抖
if(KEY3==0)	 
{				 
	YieldRequired=xTaskResumeFromISR(Task2Task_Handler);//恢复任务2
	printf("恢复任务2的运行!\r\n");
	if(YieldRequired==pdTRUE)
	{
		/*如果函数xTaskResumeFromISR()返回值为pdTRUE,那么说明要恢复的这个
		任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),所以在
		退出中断的时候一定要进行上下文切换!*/
		portYIELD_FROM_ISR(YieldRequired);
	}
}		 
 EXTI_ClearITPendingBit(EXTI_Line6);//清除LINE4上的中断标志位

}

8.同样的,中断中发消息给队列入队时也需要考虑以上问题

extern QueueHandle_t Key_Queue;
//定时器3中断服务函数
void TIM3_IRQHandler(void)
{
    u8 a = 95;
    BaseType_t xHigherPriorityTaskWoken;
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
	{
		RUNTIME_TICKS++;
       //printf("%lld",RUNTIME_TICKS);
	}
    if(Key_Queue != NULL)
    {
        xQueueSendFromISR(Key_Queue,&a,&xHigherPriorityTaskWoken);
        
       
        
        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
    }  
     TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除中断标志位
}

xHigherPriorityTaskWoken就是这个功能,要注意的是清除标志位应该放在最外面