【问题标题】:Simulate Arduino-like Interrupts in C++11在 C++11 中模拟类似 Arduino 的中断
【发布时间】:2020-12-06 01:51:25
【问题描述】:

我正在开发一个粗糙的 Arduino 模拟器。 它的主要功能应该是测试由控制结构、循环、开关和子程序组成的简单代码。

我的主要想法是自己简单地提供Arduino库的功能, 例如 digitalWrite()digitalRead() 之类的函数,它们将读取并发送 将状态从外部应用程序(如虚拟面包板)固定到外部应用程序。

下图显示了我当前的概念。模拟器基本上是一个线程 执行一次setup() 函数,然后开始执行loop() 函数直到停止。 它可以从控制(主)线程中停止或暂停。

setup()loop()函数的实现,以及一些变量,由用户提供 并且无法修改或访问。

到目前为止,一切都很好。现在我想模拟中断。当模拟器线程正在执行loop() 函数时 外部应用程序触发中断。这应该导致中断处理程序isr()的执行, 也是用户自己提供的,不能更改。

我有两种不同的方法来解决这个问题:

  1. 暂停模拟器线程,在不同线程中执行中断处理程序并恢复模拟器线程。
  2. 改用信号处理程序,在发生中断时向进程发送信号。

这两种方法都有自己的问题。对于第一个,我需要以某种方式同步状态,这看起来更像是一个可怕的 hack。 对于第二个选项,据我所知,我无法指定哪个线程将执行信号处理程序。

如果可能,解决方案应该独立于平台。但是,解决方案绝对需要在Windows下编译运行(MinGW甚至Cygwin)。

【问题讨论】:

  • 对于选项 2,您还需要记住信号处理程序被禁止使用几乎所有内容。即使是信号处理程序中的简单 printf 也是未定义的行为。
  • 我想我会把 isr 放在它自己的等待条件变量的线程上。当isr被触发时,释放条件变量,让isr线程执行一次,然后回到等待状态。我不确定我是否有充分的理由停止模拟器线程,除非有关 arduino 架构的某些东西使它成为更准确的模拟。
  • @ttemple 在我的场景中loop()isr() 将共享一些变量,这意味着中断例程将修改主函数中使用的变量。我不确定这是否会导致一些问题。我很确定你的意思是std::condition_variable,对吧?我试试看,谢谢!
  • arduino 如何处理 isr 和主执行之间的共享数据?如果它自动处理共享数据,我会对停止模拟器线程有不同的感觉。 (这就是我的意思是,如果 arduino 有什么东西可以让停止更准确的模拟。)如果没有,您应该以类似于 arduino 的方式对共享数据处理进行建模,因为您的模拟器将帮助确定您是否正在做共享数据而不踩数据等。
  • 是的,std::condition_variable 就是我的意思。它是阻塞和释放正在等待某事的线程的完美工具。

标签: c++ windows arduino simulation interrupt


【解决方案1】:

IMO 所有的中断都可能被认为是延迟非常低的线程(或基本线程),因此空闲线程是主线程,int-threads 可以抢占主线程但不能被抢占。

所以基本上,目的是执行所有线程,直到满足其中一个 int 线程中的条件,当这种情况发生时,阻塞所有线程(一种临界区,即mutexcondition variable)直到 int-thread 完成它的工作。之后,再次执行所有线程(中断时间越短越好):

void interrupt1_thd(void) {
    // try_lock the mutex
    // check the condition of this interrupt
    // if true, do the job
    // release the mutex if locked

]

低端 uC 看起来很简单(即 ATmega328P),没有嵌套中断或优先级。使用更昂贵的 uC(比如说 ATSAMD51 Cortex M4),事情就复杂得多。现在线程必须能够触发、阻塞所有其他较低或相等优先级的线程,并且能够被较高优先级的线程阻塞。基于优先级的线程不是什么大问题(pthread_setschedparamSetThreadPriority),但在没有死锁的线程中嵌套互斥锁并非微不足道,所以这里 condition_variable 更有意义,因为它具有通知功能:

Event:                      Int1   Int3   Int2  Int3         Int3
Main           : -----------                              ---              --------
Task1 (mid)    :             -------------            ----
Task2 (high)   :                          ----------
Task3 (low)    :                                             --------------
Take mutexLow  :            ---------- by 1 ---------        ---- by 3 ----
Take mutexMid  :            ---------- by 1 ---------
Take mutexHigh :                          -- by 2 --

如果mutexHigh 被占用(由高优先级任务),Task1Task3 将等待直到Task2 通知所有线程。

如果mutexLow 被占用(通过像Task3 这样的低优先级任务),Task3 执行其工作(包括检查更高的通知),而Task1Task2 继续检查它们的条件。

我会避免在不同级别的优先级之间共享资源,以免添加更多同步机制。


所有这一切都取决于您想要模拟的 Arduino 以及您想要达到的模拟级别,不确定您是否想要更深入并包括中断队列以最小化延迟、上下文切换......

【讨论】:

    猜你喜欢
    • 2012-10-09
    • 2020-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多