在 C++11 中模拟类似 Arduino 的中断 [英] Simulate Arduino-like Interrupts in C++11

查看:33
本文介绍了在 C++11 中模拟类似 Arduino 的中断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on a crude Arduino simulator. It's main function should be to test simple code consisting of control structures, loops, switches and subroutines.

我的主要想法是简单地自己提供Arduino库的功能,例如像 digitalWrite()digitalRead() 这样的函数,它们会读取和发送外部应用程序(如虚拟面包板)之间的引脚状态.

My main idea is to simply provide the functions of the Arduino library myself, for example functions like digitalWrite() or digitalRead(), which would read and send the pin states from and to an external application (like a virtual breadboard).

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

The following diagram shows my current concept. The simulator is basically a thread which executes the setup() function once and then starts to execute the loop() function until stopped. It can be stopped or paused from the control (main) thread.

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

The implemention of the setup() and loop() function, as well as some variables, are provided by the user and cannot be modified or accessed.

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

So far, so good. Now I want so simulate interrupts. While the simulator thread is executing the loop() function the external application triggers an interrupt. This should result in the execution of the interrupt handler isr(), which is also provided by the user and cannot be changed.

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

I had two different approaches to this problem:

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

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

Both approaches have their own problems. With the first one, I need to synchronize state somehow, and it seems more like a horrible hack. For the second option, as far as I know, I can't specify which thread will execute the signal handler.

如果可能,解决方案应该与平台无关.但是,该解决方案绝对需要在 Windows 下编译和运行(MinGW 甚至 Cygwin).

If possible, the solution should be platform independent. However, the solution absolutely needs to compile and run under Windows (MinGW or even Cygwin).

推荐答案

IMO 可能会将所有中断视为具有极低延迟的线程(或基本线程),因此空闲线程是主要线程,而 int 线程可以抢占主线程但不被抢占.

IMO all the interrupts might be considered as threads (or rudimentary threads) with a very low latency, so the idle thread is the main and the int-threads can preempts the main thread but not be preempted.

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

So basically, the purpose is to execute all the threads until a condition in one of the int-threads is met, when that happens, block all the threads (kind of critical region, i.e. mutex or condition variable) until the int-thread finishes its job. After that, execute all the threads again (the less time in the interrupt the better):

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

]


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


With low-end uCs looks simple ( i.e. ATmega328P), there are not nested interrupts nor priorities. With more expensive uCs (let´s say an ATSAMD51 Cortex M4), things are much more complicated. Now the threads have to be able to trigger, block all the other lower or equal priority threads and be able to be blocked by higher priority threads. Threads based on priorities is not a big deal (pthread_setschedparam or SetThreadPriority), but nested mutexs in threads without deadlocks is not trivial, so here condition_variable makes more sense due to the capabilities of notifying:

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 通知到所有线程.

If mutexHigh is taken (by a high prio task), Task1 and Task3 waits until Task2 notifies to all the threads.

如果 mutexLow 被占用(由 Task3 的低优先级任务),Task3 执行其工作(包括检查更高的通知),而 Task1Task2 不断检查它们的条件.

If mutexLow is taken (by a low prio task as Task3 is), Task3 performs its job (which includes checking higher notifications), whilst Task1 and Task2 keep checking their conditions.

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

I would avoid sharing resources between different levels of priorities in order to not add more sync mechanisms.

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

All of this depends on the Arduino you want to simulate and the level of simulation you want to achieve, not sure if you want to go deeper and include interrupts queue to minimise the latency, context switching,...

这篇关于在 C++11 中模拟类似 Arduino 的中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆