在应用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.不会被中断打断,完整的执行
这些内核控制函数都会分为用在任务中的或者用在中断中的,
如:
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,
后向入队就是正常先进先出,同样该函数分为任务和中断中的执行函数。
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就是这个功能,要注意的是清除标志位应该放在最外面