有两种主要类型的多任务操作系统,抢占式和协作式。两者都允许在系统中定义多个任务,不同之处在于任务切换的工作方式。当然,对于单个核心处理器,一次实际上只运行一个任务。
两种类型的多任务操作系统都需要为每个任务使用单独的堆栈。所以这意味着两件事:首先,处理器允许将堆栈放置在 RAM 中的任何位置,因此具有移动堆栈指针 (SP) 的指令——即没有像低端那样的专用硬件堆栈PIC的。这不包括 PIC10、12 和 16 系列。
您几乎可以完全用 C 编写操作系统,但 SP 移动的任务切换器必须在汇编中。我曾多次为 PIC24、PIC32、8051 和 80x86 编写任务切换器。根据处理器的体系结构,胆量完全不同。
第二个要求是有足够的 RAM 来提供多个堆栈。通常,一个堆栈至少需要几百个字节;但是即使每个任务只有 128 字节,八个堆栈也需要 1K 字节的 RAM——尽管您不必为每个任务分配相同大小的堆栈。请记住,您需要足够的堆栈来处理当前任务以及对其嵌套子例程的任何调用,还需要堆栈空间来进行中断调用,因为您永远不知道何时会发生中断调用。
有相当简单的方法可以确定您为每个任务使用了多少堆栈;例如,您可以将所有堆栈初始化为特定值,例如 0x55,然后运行系统一段时间,然后停止并检查内存。
你没有说你想使用什么样的PIC。大多数 PIC24 和 PIC32 将有足够的空间来运行多任务操作系统;PIC18(唯一在 RAM 中有堆栈的 8 位 PIC)的最大 RAM 大小为 4K。所以这很不确定。
通过协作多任务处理(两者中较简单的一种),任务切换仅在任务“放弃”其控制权返回给操作系统时完成。每当任务需要调用操作系统例程来执行它将等待的某些功能时,就会发生这种情况,例如 I/O 请求或计时器调用。这使得 OS 更容易切换堆栈,因为不需要保存所有的寄存器和状态信息,SP 可以切换到另一个任务(如果没有其他任务准备运行,则空闲堆栈是给予控制)。如果当前任务不需要进行操作系统调用但已经运行了一段时间,它需要主动放弃控制以保持系统响应。
协作多任务处理的问题是,如果任务从不放弃控制,它会占用系统。只有它和任何碰巧获得控制的中断例程才能运行,因此操作系统似乎会锁定。这是这些系统的“合作”方面。如果实现了仅在执行任务切换时重置的看门狗定时器,则可以捕获这些错误任务。
Windows 3.1 和更早的版本是协作操作系统,这也是它们性能不那么出色的部分原因。
抢先式多任务处理更难实现。在这里,任务不需要手动放弃控制,而是可以给每个任务一个最大的运行时间(比如 10 毫秒),然后执行任务切换到下一个可运行任务(如果有的话)。这需要任意停止一个任务,保存所有状态信息,然后将 SP 切换到另一个任务并启动它。这使得任务切换器更加复杂,需要更多的堆栈,并且稍微降低了系统速度。
对于协作式和抢占式多任务处理,任何时候都可能发生中断,这将暂时抢占正在运行的任务。
正如 supercat 在评论中指出的那样,协作式多任务处理的一个优势是更容易共享资源(例如,多通道 ADC 等硬件或修改链表等软件)。有时两个任务想要同时访问同一个资源。通过抢占式调度,操作系统可以使用资源在一个任务的中间切换任务。所以锁是必要的,以防止另一个任务进入并访问相同的资源。对于协作式多任务处理,这不是必需的,因为任务控制何时将其自身释放回操作系统。