Arduino readString(); 代码运行缓慢

The*_*sin 2 arduino arduino-ide

我有以下代码,我需要快速执行,但它需要花费大量时间来改变价值,无论如何更快地完成这项任务?

我正在使用indexOf()substring()完成这项任务.这是为了改变条形LED的颜色.

// declare LED Series A Pins R-G-B (PWM Pins)
  int const AledRedPin = 6;
  int const AledGreenPin = 5;
  int const AledBluePin = 3;

// declare LED Series B Pins R-G-B (PWM Pins)
  int const BledRedPin = 10;
  int const BledGreenPin = 11;
  int const BledBluePin = 9;

// serial input variable & string
// initialise LED Series A Pins R-G-B (PWN Value: 0 to 255)
// initial value = 255
  int AledRed = 255;
  int AledGreen = 255;
  int AledBlue = 255;

// initialise LED Series A Pins R-G-B (PWN Value: 0 to 255)
// initial value = 255
  int BledRed = 255;
  int BledGreen = 255;
  int BledBlue = 255;

//serial input
  String Command = "";

//string manipulation
  int cmdindexval = 0;
  String CommandType = "";
  int CommandValue = 0;
  String Series = "";

void setup() {
  // put your setup code here, to run once:
  // start serial
    Serial.begin(9600);
      while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB
      }

  // set LED Series A Pins as Output R-G-B
    pinMode(AledRedPin, OUTPUT);
    pinMode(AledGreenPin, OUTPUT);
    pinMode(AledBluePin, OUTPUT);

  // set LED Series B Pins as Output R-G-B
    pinMode(BledRedPin, OUTPUT);
    pinMode(BledGreenPin, OUTPUT);
    pinMode(BledBluePin, OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  // read from serial if it's available
    if (Serial.available() > 0) {
      Command = Serial.readString(); //read string from serial monitor
      cmdindexval = Command.indexOf('='); //read characters until '=' then assign the value
      CommandType = Command.substring(0, cmdindexval); //assign the value from 0 to cmdindexval
      //Series = Command.substring(0, 1); //read first character
      CommandValue = Command.substring(cmdindexval + 1).toInt(); //assign the value after '=' and convert string to Int
      Serial.println(CommandType + " ,is equal to " + CommandValue + " ,Series: " + Series);    
      //if (Series == "A") {
        if (CommandType == "ACledRed"){
          AledRed = CommandValue;
        }
       else if (CommandType == "ACledGreen"){
          AledGreen = CommandValue;
        }
        else if (CommandType == "ACledRedBlue") {
          AledBlue = CommandValue;
        }
      //}
      //else if (Series == "B") {
        if (CommandType == "BCledRed") {
          BledRed = CommandValue;
        }
        else if (CommandType == "BCledGreen") {
          BledGreen = CommandValue;
        }
        else if (CommandType == "BCledBlue") {
          BledBlue = CommandValue;
        }
     //}
    } //end serial

    analogWrite(AledRedPin, AledRed);
    analogWrite(AledGreenPin, AledGreen);
    analogWrite(AledBluePin, AledBlue);

    analogWrite(BledRedPin, BledRed);
    analogWrite(BledGreenPin, BledGreen);
    analogWrite(BledBluePin, BledBlue);

}
Run Code Online (Sandbox Code Playgroud)

gre*_*gor 10

来自Arduino 文档readString:

Serial.readString()将串行缓冲区中的字符读入字符串.如果超时,函数将终止(请参阅setTimeout()).

文档setTimeout:

Serial.setTimeout()设置使用Serial.readBytesUntil(),Serial.readBytes(),Serial.parseInt()或Serial.parseFloat()时等待串行数据的最大毫秒数.默认为1000毫秒.

这意味着readString始终等待1秒以确保完成字符串的发送并具有完整的字符串.
不幸的是,这意味着它的反应很慢.你可以用它来降低超时setTimeout,但你仍然会有一些延迟,或者如果你设置得太低,你可能会得到不完整的叮咬.

最好的解决方案是使用readStringUntil,因此当你得到终结符时(比如换行符),你知道你有一个完整的字符串.

更换

Command = Serial.readString();
Run Code Online (Sandbox Code Playgroud)

Command = Serial.readStringUntil('\n');
Run Code Online (Sandbox Code Playgroud)

并确保设置串行监视器,以便发送换行符.

  • 如果您要发送换行符,则不应发送。 (2认同)

Dan*_*_ds 5

编辑:请参阅最后的重要更新。

这可以大大提高速度,但是首先让我们看一下使用当前代码在每次循环迭代中必须完成的工作:

  • 正如@gre_gor已经解释的,您可能会在中浪费一些时间readString()
  • 对于每个值,必须发送,读取,解析和转换为到15到20个字节之间int
  • 对于每个接收到的值(R,G或B),analogWrite()被调用6次(而且analogWrite()速度不是很快)。这意味着为了更改两个序列,analogWrite()被称为36次(这可能是浪费最多时间的地方)。如果没有可用的串行数据,analogWrite()仍将被调用6次。
  • 并且Serial.println()在示例中每次都被调用-因此最好将其关闭。

为了加快速度,可以在一个小的缓冲区中发送RGB值(假设您也可以控制发送方),并使用读取Serial.readBytesUntil()

如果将A和B的值一起发送,则可以将6个RGB值作为6个字节发送:

byte rcvBuffer[7];

void loop() {

    if (Serial.available() > 0) {

        // message: RGBRGBx - but see update below
        int numRead = Serial.readBytesUntil(0x78, rcvBuffer, 7); // 0x78 is 'x'

        if (numRead == 7) { // or 6, see below

            analogWrite(AledRedPin,   rcvBuffer[0]);
            analogWrite(AledGreenPin, rcvBuffer[1]);
            analogWrite(AledBluePin,  rcvBuffer[2]);

            analogWrite(BledRedPin,   rcvBuffer[3]);
            analogWrite(BledGreenPin, rcvBuffer[4]);
            analogWrite(BledBluePin,  rcvBuffer[5]);
        }
        // else ignore this read - could be a first unaligned read
    }
}
Run Code Online (Sandbox Code Playgroud)

如果仅将A或B的值一起发送:

byte rcvBuffer[5];

void loop() {

    // You could probably even remove the Serial.available() check
    if (Serial.available() > 0) {

        // message: TRGBx where T is Type ('A' or 'B')
        int numRead = Serial.readBytesUntil(0x78, rcvBuffer, 5); // 0x78 is 'x'

        if (numRead == 5) {  // or 4, see below

            switch (rcvBuffer[0]) {
                case 'A':
                    analogWrite(AledRedPin,   rcvBuffer[1]);
                    analogWrite(AledGreenPin, rcvBuffer[2]);
                    analogWrite(AledBluePin,  rcvBuffer[3]);
                    break;
                case 'B':
                    analogWrite(BledRedPin,   rcvBuffer[1]);
                    analogWrite(BledGreenPin, rcvBuffer[2]);
                    analogWrite(BledBluePin,  rcvBuffer[3]);
                    break;
                default :
                    // do nothing, or send error message
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我用作'x'停止字节以使其可见,但您也可以使用零字节。

现在,我不确定是否readBytesUntil()还会将终止字节读入缓冲区或跳过它,并且现在无法进行测试。但我认为只有RGB值会读入缓冲区。在这种情况下,您必须将这些值更改为我在注释中输入的值。

为了节省更多时间,您可以检查每个值,并且仅analogWrite()在该值自上次调用(对于每个R,G和B)以来确实发生更改时才调用。


更新:显然我们不能只使用'x'零字节作为停止字节,因为每个RGB值也可以是'x'零字节或零字节(在这里很晚了:)。尽管ReadBytes()可以代替使用,但最好有一个停止字节来保持缓冲区对齐。因此,我建议使用0xff(255)作为停止字节,并确保所有RGB值都不能为0xff

并且,以防万一将来可能会有其他消息类型,每个消息也可以在前面加上消息代码(1或2个字节)。