23

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

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

4

11 回答 11

16

简而言之:没有。但你可以试一试: http ://www.kwartzlab.ca/2010/09/arduino-multi-threading-librar/

于 2012-12-22T12:59:16.647 回答
7

还没有,但我总是在大型项目中使用这个库: https ://github.com/ivanseidel/ArduinoThread

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

于 2013-12-08T14:36:34.633 回答
6

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

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

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

于 2014-02-02T21:53:35.430 回答
4

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

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

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

于 2013-12-13T11:50:45.877 回答
2

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

于 2017-12-20T13:20:12.677 回答
1

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

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

于 2012-12-22T16:05:02.147 回答
1

你可以使用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
}
于 2014-10-02T18:23:08.673 回答
1

Arduino 不支持多线程编程。

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

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

或者,您可以使用protothreads

于 2018-06-20T10:31:34.977 回答
1

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

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

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

于 2020-08-25T12:32:33.853 回答
1

线程不!同时是的!

您可以使用 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/

于 2022-02-03T13:59:31.573 回答
0

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()抽象状态机类中的状态包装器引用。

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

要使用状态机,首先必须实例化它。在使用设置函数实例化它时在全局空间中声明对类的引用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)();
}
于 2018-11-09T20:06:44.160 回答