当前位置: 首页 > news >正文

FreeRTOS 任务与中断函数:运行机制、关键区别与使用准则

一、任务相关函数(Task-related Functions)

任务是 FreeRTOS 的基本执行单元,运行在操作系统的调度器控制下,属于线程级代码,通常用于实现复杂的、非实时性要求极高的逻辑。

核心特性:

  • 运行在任务上下文(Task Context),可被调度器暂停、恢复或切换。
  • 允许阻塞(如vTaskDelay()),阻塞时会释放 CPU 资源给其他任务。
  • 函数名通常不带FromISR后缀。
  • 可安全访问大部分 FreeRTOS 内核对象(队列、信号量等)。

常用函数分类:

  1. 任务创建与管理
    • xTaskCreate():创建新任务(动态分配栈空间)。
    • xTaskCreateStatic():创建新任务(静态分配栈空间,需手动指定栈和控制块)。
    • vTaskDelete():删除指定任务。
    • vTaskSuspend() / vTaskResume():暂停 / 恢复指定任务。
    • vTaskDelay():任务延迟(相对时间,单位:ticks)。
    • vTaskDelayUntil():任务延迟(绝对时间,用于周期性任务)。
  2. 内核对象操作(任务上下文)
    • 队列:xQueueSend()、xQueueReceive()、xQueuePeek()等。
    • 信号量:xSemaphoreGive()、xSemaphoreTake()等。
    • 事件组:xEventGroupSetBits()、xEventGroupWaitBits()等。

二、中断相关函数(Interrupt-related Functions)

中断是硬件或软件触发的异步事件,用于快速响应紧急操作(如 GPIO 电平变化、定时器溢出等)。中断服务程序(ISR)运行在中断上下文,需尽可能简短,避免阻塞。

核心特性:

  • 运行在中断上下文,优先级高于所有任务,不可被调度器暂停。
  • 禁止阻塞操作(如vTaskDelay()),否则会导致系统崩溃。
  • 函数名通常带FromISR后缀,明确标识用于 ISR。
  • 操作内核对象时需使用专门的中断安全版本,且需处理 “中断嵌套” 和 “上下文切换请求”。

常用函数分类:

  1. 内核对象操作(中断上下文)
    • 队列:xQueueSendFromISR()、xQueueReceiveFromISR()等(需传入pxHigherPriorityTaskWoken参数)。
    • 信号量:xSemaphoreGiveFromISR()、xSemaphoreTakeFromISR()等。
    • 事件组:xEventGroupSetBitsFromISR()等。
  2. 中断管理辅助函数
    • portYIELD_FROM_ISR():在 ISR 中请求上下文切换(当pxHigherPriorityTaskWoken为pdTRUE时调用)。
    • uxTaskPriorityGetFromISR():获取任务优先级(中断安全版本)。
    • vTaskNotifyGiveFromISR():发送任务通知(中断安全版本)。

三、关键区别对比

维度

任务函数(非 FromISR)

中断函数(FromISR)

运行上下文

任务上下文(可被调度)

中断上下文(不可被调度)

是否允许阻塞

允许(如vTaskDelay())

禁止(否则系统崩溃)

函数名标识

无FromISR后缀

带FromISR后缀

内核对象操作

直接操作,无需额外参数

需传入pxHigherPriorityTaskWoken,用于判断是否需要切换上下文

执行时间

可长(复杂逻辑)

必须短(避免影响系统响应)

优先级

受调度器管理(0~configMAX_PRIORITIES-1)

由硬件 / 内核决定(通常高于任务)

四、使用原则

  1. 任务中调用非 FromISR 函数:任务上下文允许阻塞和复杂操作,优先使用普通版本函数。
  2. ISR 中必须调用 FromISR 函数:中断上下文禁止阻塞,必须使用中断安全版本,且操作完成后需通过portYIELD_FROM_ISR()触发上下文切换(如果需要)。
  3. 避免在 ISR 中执行耗时操作:ISR 应仅完成必要工作(如数据传递给任务),复杂逻辑交给任务处理。

A_Task()任务调度

在while中调用

阻塞超时时间0---100个Tick

失败就阻塞 100个Tick

---------------------------------------------------------------------------------------------------------------------------------

Key_ISR()中断

调用

不进行阻塞超时间 也就是0个Tick

在中断中使用这个函数,要么成功,要么失败

---------------------------------------------------------------------------------------------------------------------------------

A写队列,当写队列时有可能唤醒任务B,B的优先级高于任务A,任务B马上运行,任务B一直没有主动放弃处理器资源的话,任务A就无法执行。这就是一个严重问题。

唤醒问题:

---------------------------------------------------------------------------------------------------------------------------------

就是当写队列A时,在函数内部把任务B唤醒了,任务B的优先级更高,导致函数迟迟无法返回,所以时间为任意(0-∞),B迟迟不放弃运行的话,任务A就永远无法运行。

这个函数

  1. 进行写队列
  2. 写队列失败后,进行阻塞,阻塞的时间最多为100TICK
  3. 写成功后,wake up 。如果唤醒的任务的优先级的任务更高,原来的任务就无法被运行。

---------------------------------------------------------------------------------------------------------------------------------

在中断中使用这个函数,要么成功,要么失败,不会进行等待

调用这个函数

  1. 是否要唤醒B 答案是的
  2. 是否需要马上切换 不进行马上切换,当中断快结束时,再进行切换。函数内部不调用切换

---------------------------------------------------------------------------------------------------------------------------------

假设调用KEY_ISR中断,

写100个数据,假设队列里面有100个任务,等待写入数据

通过中断写队列,队列里面有个链表有1-100个任务,都在等待数据

调用这个函数

  1. 唤醒 就是从阻塞链表移动到就绪链表 不花什么时间
  2. 切换 比较复杂  保存当前的任务现场,恢复新任务现场

涉及到寄存器的写 ,寄存器的读 比较耗时间

在中断里面切换有意义吗?

没有意义,因为你再怎么切换都无法立刻被执行,因为中断的优先级永远高于所有任务

当处于中断时,无法执行其他任务,当中断结束,切换为其他任务

所以

调用这个函数时,就不进行切换 ,改为记录

  1. 唤醒 就是从阻塞链表移动到就绪链表 不花什么时间
  2. 记录 记录是否有更高优先级的任务被唤醒

当执行完这些复杂操作之后,在退出中断之前再切换

---------------------------------------------------------------------------------------------------------------------------------

在这两个场景里面有很大的差别,所以使用这个函数

---------------------------------------------------------------------------------------------------------------------------------

改进实时问题

就是优先级A运行时,发生中断,会唤醒B(高优先级任务)。

按理来说应该当中断结束后,立刻进行高优先级的任务B

但是B没有运行,而是恢复任务A,

当下一个Tick中断到来时,切换为任务B

那么这段过程中任务B就是被延时了

为什么B被延时,就是由于在触发中断时,没有进行发起调度,从而导致了延时,所以为了实时性,应该在中断结束前发起调度

只进行了唤醒,而没有调度,导致实时性有所差距

---------------------------------------------------------------------------------------------------------------------------------

如何进行调度呢?

使用函数

切换函数

portYIELD_FROM_ISR( xHigherPriorityTaskWoken );

示例

void XXX_ISR()
{int i;BaseType_t xHigherPriorityTaskWoken = pdFALSE;for (i = 0; i < N; i++){xQueueSendToBackFromISR(..., &xHigherPriorityTaskWoken); /* 被多次调用 */}/* 最后再决定是否进行任务切换 * xHigherPriorityTaskWoken为pdTRUE时才切换*/portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

xHigherPriorityTaskWoken 用于标记是否有更高优先级任务因队列操作被唤醒,需在中断结束时判断是否触发任务切换。

xQueueSendToBackFromISR 是 FreeRTOS 中断安全的队列发送函数(向队列尾部发数据),循环里多次调用,每次传 &xHigherPriorityTaskWoken 记录调度需求。

最后用 portYIELD_FROM_ISR ,根据 xHigherPriorityTaskWoken 的值(pdTRUE 则触发),决定是否在中断退出时切换到被唤醒的高优先级任务,保证实时性。

http://www.lryc.cn/news/617045.html

相关文章:

  • GC如何判断对象可以被回收?
  • 利用容器编排完成haproxy和nginx负载均衡架构实施
  • 【代码随想录day 15】 力扣 222.完全二叉树的节点个数
  • 【Python 小脚本·大用途 · 第 2 篇】
  • Day11 原理篇
  • afsim2.9_使用QtCreator和VSCode编译
  • Excel版经纬度和百分度互转v1.1
  • 第二章、LSTM(Long Short-term Memory:长短时记忆网络)
  • 基于python/django框架的车型识别系统
  • iptables -F 与 iptables -X
  • 基于Django的图书馆管理系统的设计与实现
  • 精准计算Word文档页数的PHP类
  • foxmail网站邮箱网络营销策略论文
  • 自己做网站排名好吗天津seo推广
  • 长春网站策划制作网页的代码
  • 我想创建一个网站sem 优化价格
  • 网站开发虚拟主机管理系统nba西部最新排名
  • 四川建设部网站官网温州最好的seo
  • 成都建设网站哪个好seo外包杭州
  • 南京学习做网站独立站搭建要多少钱
  • 北京网页设计学校成都sem优化
  • 网站建设方案书 个人做百度推广一个月多少钱
  • 一级a做爰片试看 免费网站百度竞价ocpc
  • php做公司网站seo网站推广怎么做
  • 常州微网站建设游戏搬砖工作室加盟平台
  • 中建建设银行网站北京今日重大新闻
  • wordpress做下载站百度推广代运营公司
  • 网站空间数据库专门看广告的网站
  • 电商网站话费充值怎么做北京推广优化经理
  • 竞价网站服务器台州网站建设优化