有100种不同的方法可以完成这个任务,这取决于CPU架构(中断嵌套和优先级、软件中断支持等),但让我们采用一个相当直接简单且没有抢占内核的竞争条件和资源共享风险的方法。
(免责声明:我的第一选择通常是预先实时内核,其中许多可以在极度资源受限的系统中运行... SecurityMatt的建议很好,但如果您不熟悉实现自己的可抢占内核/任务切换器,尤其是处理异步(由中断触发的)抢占,您可能很快就会感到困惑。因此,我下面提出的方案不像基于抢占的内核那样响应迅速,但它更简单,通常足够)。
创建3个事件/工作队列:
1. Q1 是最低优先级,处理缓慢的后台SD卡写入。
2. Q2 保存处理传入UART数据包的请求。
3. Q3(最高优先级)保存UART RX FIFO读取请求。
我将UART RX FIFO的读取和读取包的处理分开,以便FIFO的读取始终优先于包的处理;也许您想将它们放在一起,这是您的选择。
"To make this work, you need to divide your large (~100ms) SD card write process into smaller, discrete steps that can be completed independently. For example, if you want to write 5 blocks, each taking 20ms, you first write the first block and then add "write next block" to Q1. After each step, you return to the scheduler and scan the queues in priority order, starting with Q3. If Q2 and Q3 are empty, you take the next event from Q1 ("write next block") and run that command for another 20ms before returning to scanning the queues again. If 20ms is not fast enough, you can break down each 20ms block write into more detailed steps and continuously add the next work step to Q1."
现在讲一下串口接收相关的内容;在串口RX ISR中,你只需将“读取串口FIFO”命令入队到Q3中,然后从中断返回到被打断的20毫秒“写入块”步骤。一旦CPU完成了写入操作,它就会回去按优先级顺序扫描队列(最坏情况的响应时间为20毫秒,如果块写刚好在中断发生时开始)。队列扫描程序(调度程序)会发现Q3现在有任务要做,然后在回去再次扫描之前运行该命令。
你的系统的响应性,最坏情况下,将由系统中最长的运行至完成步骤决定,而与优先级无关。通过以小、离散、运行至完成步骤的方式进行工作,可以使系统非常灵敏。
请注意,这里必须以概论形式讲解。也许你想在ISR中读取UART RX FIFO,将数据放入缓冲区,并仅推迟数据包处理,而不是实际读取FIFO(那么你只需要2个队列)。你必须自己解决这个问题。但我希望这种方法是有道理的。
这种优先队列驱动的事件处理方法正是
Quantum Platform (QP)事件驱动框架所采用的方法。 QP实际上支持底层的非抢占式(协作式)调度程序,如本文所述,或者是每次排队一个事件就运行调度程序的抢占式调度程序(类似于SecurityMatt建议的方法)。 您可以在QP网站上查看QP协作式调度程序的代码/实现。