基于事件或轮询的嵌入式MCU系统架构?

时间:2012-09-06 11:31:49

标签: event-handling embedded polling

我之前有过编写基于事件和轮询的嵌入式系统的经验(对于没有抢先操作系统的小型MCU)。

在基于事件的系统中,任务通常接收队列上的事件(消息)并依次处理它们。

在基于轮询的系统中,任务以一定的间隔轮询状态并响应更改。

您更喜欢哪种架构?两者可以共存吗?

更新:提出的要点

基于投票
- 与时序方面相关的紧耦合(@Lundin)
*可以使用队列(@ embedded.kyle)与事件系统共存 *适用于较小的程序(@Lundin)

基于事件
+从长远来看,系统更加灵活(@ embedded.kyle)
- RTOS版增加了复杂性(@Lundin)
*小程序=状态机控制(@Lundin)
*可以使用队列和“超级循环”(内部控制器/主要)(@ embedded.kyle)实现 *只有真正的“事件”才是中断的(@Lundin)

相关问题
* Looking for a comparison of different scheduling algorithms for a Finite State Machine(@ embedded.kyle)

相关信息
*“更喜欢使用活动对象而不是裸线程”(@Miro)
http://www.drdobbs.com/parallel/prefer-using-active-objects-instead-of-n/225700095
*“正确使用线程=隔离+异步消息”(@Miro) http://www.drdobbs.com/parallel/use-threads-correctly-isolation-asynch/215900465

3 个答案:

答案 0 :(得分:4)

真的没有"事件驱动"在一个裸骨MCU平台上,尽管流行语 - 吐痰者试图告诉你。您可以接收的唯一真实事件是硬件中断。

根据应用程序的性质及其实时要求,中断可能适合也可能不适合。通常,使用轮询系统实现确定性实时更容易。但是,仅依靠轮询的系统很难维护,因为所有时序方面之间的紧密耦合。

假设您尝试启动LCD,这很慢。而不是在空循环中烧制CPU周期时重复轮询某个定时器,您可能决定在此期间通过总线接收一些数据。然后你想打印液晶显示器上收到的数据。这种设计在LCD启动时间和串行总线之间产生了紧密耦合,并且在串行总线和数据打印之间产生了另一种紧密耦合。从面向对象的角度来看,这些东西根本不相关。如果您将来某个时候加速串行总线,那么突然间您会遇到LCD打印错误,因为当您尝试在其上打印时它还没有完成启动。

在一个小程序中,使用上面示例中的轮询是完全正确的。但如果该计划具有增长潜力,那么民意调查将使其变得非常复杂,紧密耦合将最终导致许多奇怪和致命的错误。

另一方面,多线程和RTOS增加了相当多的额外复杂性,这反过来又会导致错误。画线的位置不容易确定。

出于个人经验,我说任何小于20-30k LOC的程序都不会受益于调度和多任务处理,除了简单的状态机之外。如果程序大于此,我会考虑多任务RTOS。

此外,低端MCU(8位和16位)远不适合运行操作系统。如果您发现需要操作系统来处理8位或16位平台的复杂性,那么您可能会选择错误的MCU。我对在任何小于32比特的任何东西上引入操作系统的尝试持怀疑态度。

答案 1 :(得分:3)

实际上,事件驱动的编程和线程可以组合在一起,结果模式被广泛称为“活动对象”或“演员”。

活动对象(actor)是封装的,事件驱动的状态机,它们通过相互发布事件来异步地相互通信。活动对象处理它们自己的执行线程中的所有事件(至少在概念上,如果使用了协作调度程序),因此它们避免了设计中的大多数并发危险。

演员和活动对象在通用计算中都很流行(你可以搜索Erlang,Scala,Akka)。 Herb Sutter撰写了几篇很好的文章来解释“活动对象”模式:“更喜欢使用活动对象而不是裸线程”(http://www.drdobbs.com/parallel/prefer-using-active-objects-instead -of-n / 225700095)和“正确使用线程=隔离+异步消息”(http://www.drdobbs.com/parallel/use-threads-correctly-isolation-asynch/215900465)

以下是Herb在第一篇文章中所说的内容:

“直接使用原始线程有很多原因...... 活动对象通过提供更高级别的抽象和习惯用语来提高我们程序的语义级别并让我们更直接地表达我们的意图,从而显着提高我们推理线程代码和操作的能力。与所有好的模式一样,我们也可以获得更好的词汇来谈论我们的设计。请注意,活动对象并不新颖:UML和各种库提供了对活动类“

的支持

所以,这一切都不是新的。但是,可能鲜为人知的是,特别是在嵌入式系统社区中,活动对象不仅完全适用于嵌入式系统,而且它们实际上是嵌入式系统的完美匹配,而且它们比传统的更轻 RTOS。

我已经使用事件驱动的活动对象十多年了,并为嵌入式系统创建了QP系列活动对象框架(参见http://www.state-machine.com/)。我永远不会回到投票“superloop”或原始RTOS。

答案 2 :(得分:1)

我更喜欢哪种架构最适合手头的应用程序。

两者都可以在多级队列架构中共存。一个队列在主循环中运行的轮询基础上工作。而另一个(很可能是具有更高优先级事件的任务)通过使用基于中断的抢占来工作。

有关不同调度算法的更详细说明和比较,请参阅我对this SO question的回答。