【问题标题】:Does Arduino support threading?Arduino 支持线程吗?
【发布时间】:2022-03-07 17:06:20
【问题描述】:

我有几项与 arduino 相关的任务,但其中一项需要很长时间,所以我正在考虑使用线程同时运行它们。 我有一个 Arduino Mega

[更新] 四年后,我终于可以在我的 arduino mega 中安装 FreeRTOS。这是link

【问题讨论】:

标签: multithreading arduino


【解决方案1】:
【解决方案2】:

还没有,但我总是将此库用于大型项目: https://github.com/ivanseidel/ArduinoThread

我将回调放在定时器中断中,瞧!您在 Arduino 上运行了伪线程...

【讨论】:

    【解决方案3】:

    只是为了使这个线程更完整:还有 protothreads 具有非常小的内存占用(如果我没记错的话,是几个字节)并保留线程本地的变量;非常方便且节省时间(更少的有限状态机 -> 更易读的代码)。

    示例和代码: arduino-class / ProtoThreads wiki

    只是为了让您知道您可能期望的结果:串行通信@153K6 波特率,线程用于:状态二极管闪烁、计时、请求的功能评估、IO 处理和逻辑以及所有在 atmega328 上。

    【讨论】:

      【解决方案4】:

      不是真正的线程,但 TimedActions 是许多用途的不错选择

      http://playground.arduino.cc/Code/TimedAction#Example

      当然,如果一个任务阻塞,其他任务也会阻塞,而线程可以让一个任务冻结而其他任务将继续......

      【讨论】:

        【解决方案5】:

        不,你不能,但你可以使用定时器中断。 参考:https://www.teachmemicro.com/arduino-timer-interrupt-tutorial/

        【讨论】:

          【解决方案6】:

          前面的答案是正确的,然而,arduino 通常运行得很快,所以如果你适当地计时你的代码,它可以或多或少地同时完成任务。

          最好的做法是自己制作函数,避免在默认的 void 循环中放入过多的真实代码

          【讨论】:

          • 我不能同意这一点:“最好的做法是制作自己的函数,避免在默认的 void 循环中放入太多真实代码”——代码是否在循环或在您自己的函数中,如果它从循环中被 调用,则在时间方面几乎是相同的(加上很小的函数调用开销)
          • @MartinThompson 我认为他写这篇文章的时机并不明智。我宁愿认为他指的是功能组织,事实上,稍后重新排列代码更为实用(例如,稍后将 TimedAction 或 ArduinoThread 添加到相同的代码中)。
          • @FrancescoMM:谢谢-我根本没有那样读过它,但是现在您提到它,这可能就是OP的意思!我认为第一句话中提到的“时间”是通过我的。
          【解决方案7】:

          您可以使用arduinos

          它是为 Arduino 环境设计的。特点:

          • 仅静态分配(无 malloc/new)
          • 延迟执行时支持上下文切换
          • 实现信号量
          • 轻量级,CPU 和内存兼备

          当我需要从蓝牙/网络/串行接收新命令同时执行旧命令并且旧命令有延迟时,我会使用它。 一个线程是执行以下循环的服务器线程:

          while (1) {
              while ((n = Serial.read()) != -1) {
                  // do something with n, like filling a buffer
                  if (command_was_received) {
                      arduinos_create(command_func, arg);
                  }
              }
              arduinos_yield(); // context switch to other threads
          }
          

          另一个是执行命令的命令线程:

          int command_func(void* arg) {
              // move some servos
              arduinos_delay(1000); // wait for them to move
              // move some more servos
          }
          

          【讨论】:

            【解决方案8】:

            Arduino 不支持多线程编程。

            但是有一些解决方法,例如this project 中的一个(您也可以从 Arduino IDE 安装它)。

            似乎您必须自己定义调度时间,而在真正的多线程环境中,决定何时执行任务的是操作系统。

            您也可以使用protothreads

            【讨论】:

              【解决方案9】:

              直接的答案是不不不!有一些替代方案,但您不能指望 arduino mega 提供完美的多线程功能。您可以使用 arduino due 或 lenado 进行多线程,如下所示-

              void loop1(){
              }
              void loop2(){
              }
              void loop3(){
              }
              

              通常,我会在后端处理这些类型的案例。您可以在服务器中运行主要代码,同时使用 Arduino 来收集输入和显示输出。在这种情况下,我更喜欢内置 wifi 的 nodemcu。

              【讨论】:

                【解决方案10】:

                线程不! 并发是的!

                您可以使用 FreeRTOS 库同时运行不同的任务。 https://www.arduino.cc/reference/en/libraries/freertos/

                void TaskBlink( void *pvParameters );
                void TaskAnalogRead( void *pvParameters );
                
                
                  // Now set up two tasks to run independently.
                  xTaskCreate(
                    TaskBlink
                    ,  (const portCHAR *)"Blink"   // A name just for humans
                    ,  128  // Stack size
                    ,  NULL
                    ,  2  // priority
                    ,  NULL );
                
                  xTaskCreate(
                    TaskAnalogRead
                    ,  (const portCHAR *) "AnalogRead"
                    ,  128 // This stack size can be checked & adjusted by reading Highwater
                    ,  NULL
                    ,  1  // priority
                    ,  NULL );
                
                void TaskBlink(void *pvParameters)  // This is a task.
                {
                  (void) pvParameters;
                
                  // initialize digital pin 13 as an output.
                  pinMode(13, OUTPUT);
                
                  for (;;) // A Task shall never return or exit.
                  {
                    digitalWrite(13, HIGH);   // turn the LED on (HIGH is the voltage level)
                    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
                    digitalWrite(13, LOW);    // turn the LED off by making the voltage LOW
                    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
                  }
                }
                
                void TaskAnalogRead(void *pvParameters)  // This is a task.
                {
                  (void) pvParameters;
                
                  // initialize serial communication at 9600 bits per second:
                  Serial.begin(9600);
                
                  for (;;)
                  {
                    // read the input on analog pin 0:
                    int sensorValue = analogRead(A0);
                    // print out the value you read:
                    Serial.println(sensorValue);
                    vTaskDelay(1);  // one tick delay (15ms) in between reads for stability
                  }
                }
                

                小心点! 当不同的任务试图同时到达变量时,比如 i2c 通信线或 sd 卡模块。使用信号量和互斥量 https://www.geeksforgeeks.org/mutex-vs-semaphore/.

                【讨论】:

                  【解决方案11】:

                  Arduino 不支持线程。但是,您可以做次优的事情,并围绕以交错运行的状态机构建代码。

                  虽然有很多方法可以将任务实现为状态机,但我推荐这个库 (https://github.com/Elidio/StateMachine)。这个库抽象了大部分过程。

                  你可以像这样创建一个状态机:

                  #include "StateMachine.h"
                  class STATEMACHINE(Blink) {
                    private:
                      int port;
                      int waitTime;
                      CREATE_STATE(low);
                      CREATE_STATE(high);
                  
                      void low() {
                        digitalWrite(port, LOW);
                        *this << &STATE(high)<< waitTime;
                      }
                      void high() {
                        digitalWrite(port, HIGH);
                        *this << &STATE(low)<< waitTime;
                      }
                    public:
                      Blink(int port = 0, int waitTime = 0) :
                        port(port),
                        waitTime(waitTime),
                        INIT_STATE(low),
                        INIT_STATE(high)
                        {
                          pinMode(port, OUTPUT);
                          *this << &STATE(low);
                        }
                  };
                  

                  STATEMACHINE()抽象类继承,宏CREATE_STATE()抽象状态包装器创建,宏INIT_STATE()抽象方法包装,宏STATE()抽象状态机类中的状态包装器引用。

                  状态转换由状态机类和状态之间的&lt;&lt; 运算符抽象,如果您想要延迟状态转换,您所要做的就是将该运算符与一个整数一起使用,其中整数是延迟以毫秒为单位。

                  要使用状态机,首先你必须实例化它。在设置函数上使用new 实例化它时在全局空间中声明对类的引用可能会解决问题

                  Blink *led1, *led2, *led3;
                  
                  
                  void setup() {
                    led1 = new Blink(12, 300);
                    led2 = new Blink(11, 500);
                    led3 = new Blink(10, 700);
                  }
                  

                  然后你在循环中运行状态。

                  void loop() {
                      (*led2)();
                      (*led1)();
                      (*led3)();
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2012-06-18
                    • 2015-12-20
                    • 1970-01-01
                    • 2011-10-14
                    • 2011-03-04
                    • 2012-09-12
                    • 2013-04-09
                    • 2012-02-27
                    相关资源
                    最近更新 更多