当前位置: 首页 > 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.dtcms.com/a/323849.html

相关文章:

  • 如何利用RabbitMQ延迟消息优化电商支付
  • MPLS特性之PHP(Penultimate Hop Popping)
  • Android的事件分发流程、Kotlin协程、4大组件、Handler机制、架构设计、性能优化、内存泄漏
  • 从神经网络语言模型(NNLM)到Word2Vec:自然语言处理中的词向量学习
  • NLP——TF-IDF算法
  • WebAssembly技术详解:从浏览器到云原生的高性能革命
  • 麒麟系统播放 pptx
  • Spring MVC 九大组件源码深度剖析(二):LocaleResolver - 国际化背后的调度者
  • 集成电路学习:什么是Parameter Server参数服务器
  • 【软件测试】BUG篇 — 详解
  • 从 `unittest` 到 `pytest`:探寻 Python 测试框架的优雅进化与社区选择*
  • Java 后端性能优化实战:从 SQL 到 JVM 调优
  • Spring 依赖注入、AOP代理
  • GC如何判断对象可以被回收?
  • 分享一个基于Python和Hadoop的的电信客户特征可视化分析平台 基于Spark平台的电信客服数据存储与处理系统源码
  • Django @login_required实现登陆认证
  • 十、Linux Shell脚本:流程控制语句
  • Hadoop MapReduce过程
  • K8s DaemonSet 详解
  • K8s四层负载均衡-service
  • NLP学习开始-02逻辑回归
  • DevOps:从GitLab .gitlab-ci.yml 配置文件到CI/CD
  • LeetCode - 搜索插入位置 / 排序链表
  • win11(RTX5060)下进行nanodetplus训练
  • Kafka消费者相关原理
  • 第4章 程序段的反复执行4 多重循环练习(题及答案)
  • Audio Flamingo
  • 网站升级https地址方法
  • LeetCode每日一题,2025-8-10
  • jmeter常规压测【读取csv文件】