在介绍本文之前,向大家推荐个非常容易入门的人工智能学习网站,建议点击收藏❤️


目录:

  • 1. 前言
  • 2. 内核提供两套API
  • 2.1 优点
  • 2.2 缺点
  • 2.3 常用API函数列表
  • 2.4 pxHigherPriorityTaskWoken获取任务是否切换
  • 2.5 如何切换任务
  • 3. 中断延迟处理
  • 4. 中断和任务间通信
  • 5. 总结


1. 前言

FreeRTOS中断管理目的在MCU中断触发时在内核稳定运行的情况下快速响应。在学习管理策略之前,我们需要知道FreeRTOS中有以下规则:

  • 任务是与硬件无关的,任务的优先级由程序员决定,任务何时运行由调度器决定。
  • ISR虽然也是有软件实现的,但它被认为是硬件特性的一部分。
  • ISR的优先级高于任务:优先级最低的中断,它的优先级也高于优先级最高的任务。任务只有在没有中断的情况下执行。
  • 在ISR里处理的内容一定要快,且不能被阻塞,否则会影响系统的实时性甚至系统挂掉。

内核通过以下策略来对中断进行管理:

  • 两套API
  • 中断延迟处理
  • 中断和任务间通信

2. 内核提供两套API

在FreeRTOS中,有很多API函数都有两套,在任务中一套;在ISR中一套,在ISR中使用的函数名含有“FromISR”后缀。

2.1 优点

很多函数会导致任务进入阻塞,但是在ISR中是不能进入阻塞的,所以里面的内容还是有些差异的。如果使用同一套API的话需要考虑以下问题:

  • 在任务、ISR中调用是,需要的参数不一样,比如在任务中调用需要指定超时时间,表示如果不成功就阻塞一会,但是在ISR中不需要指定超时时间。如果强行把两套API结合在一起,会导致参数无效、臃肿。
  • 两套API里面有些任务切换相关的代码不一样,合在一起的话效率低, 可读性差。
  • 有些处理器架构没办法轻易分辨当前是否处于ISR中,就额外需要添加更多、更复杂的代码。

2.2 缺点

使用两套函数可以让程序更高效,但是也有一些缺点,比如你要使用第三方库函数时,即会在任务中调用它,也会在ISR中调用它。这个第三方库函数用到了FreeRTOS的API函数,你无法修改库函数。针对这个问题可以用以下方法解决:

  • 把中断的处理推迟到任务中进行,在任务中调用库函数。
  • 尝试在库函数中使用"FromISR"函数(在任务中、ISR中都可以调用“FromISR”函数, 反过来不行,非FromISR函数不能在ISR中调用)。

2.3 常用API函数列表

FreeRTOS QEMU 模拟中断 freertos中断触发任务_策略模式

2.4 pxHigherPriorityTaskWoken获取任务是否切换

xHigherPriorityTaskWoken的含义是:是否有更高优先级的任务被唤醒了。

pxHigherPriorityTaskWoken参数,就是用来保存函数的结果:

  • pxHigherPriorityTaskWoken为pdTRUE:函数的操作导致更高优先级的任务就绪了,ISR应该进行任务切换。
  • pxHigherPriorityTaskWoken为pdFALSE:没有进行任务切换的必要。

在ISR中调用API时不进行任务切换,而只是在"xHigherPriorityTaskWoken"中标记一下,除了提高效率,还有多种好处:
效率高:避免不必要的任务切换。
让ISR更可控:中断随机产生,在API中进行任务切换的话,可能导致问题更复杂可移植性。
在Tick中断中,调用vApplicationTickHook():它运行于ISR,只能使用"FromISR"的函数。

使用"FromISR"函数时,如果不想使用xHigherPriorityTaskWoken参数,可以设置为NULL。

2.5 如何切换任务

FreeRTOS的ISR函数中,使用两个宏进行任务切换:

portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
或
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );

这两个宏做的事情是一样的,前者使用汇编实现,后者使用C语言实现。
举例说明:

void XXX_ISR()
{
    int i;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
	xQueueSendToBackFromISR(..., &xHigherPriorityTaskWoken);
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

3. 中断延迟处理

前面提到过,ISR处理要尽量快,不然会有以下问题:

  • 其他低优先级中断无法被处理,实时性无法保证
  • 用户任务无法被执行,系统显得很卡顿
  • 如果运行中断嵌套,逻辑会更复杂,ISR越快越有助于中断嵌套

如果这个中断的处理就是非常耗时间的话怎么办呢:

  • ISR中尽快做些清理、记录工作,然后将通过事件的方式触发某个任务
  • 接收到中断发的事件的任务来处理这次中断需要干的内容

以上处理方式叫“中断延迟处理”,具体流程如下:

FreeRTOS QEMU 模拟中断 freertos中断触发任务_c语言_02

4. 中断和任务间通信

内核提供多种中断和任务及任务间的通信机制,比如队列、信号量、互斥量、任务通知等等,需要注意的是,在ISR中使用的函数要有"FromISR"后缀。

5. 总结

在实际开发中,用得最多的是当中断触发时将中断事件推送到任务,让任务去处理耗时内容。在这过程中,中断和任务间的通信显得至关重要,如果想了解它们之间的更多通信机制,可以点击关注或者订阅FreeRTOS专栏。