Arduino readString();代码运行缓慢

时间:2017-03-17 17:40:44

标签: 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);

}

2 个答案:

答案 0 :(得分:6)

来自Arduino docs on readString

  

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

docs on setTimeout

  

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

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

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

替换

Command = Serial.readString();

Command = Serial.readStringUntil('\n');

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

答案 1 :(得分:4)

修改:最后查看重要更新。

这可以明显加快,但首先让我们看一下使用当前代码在每次循环迭代中必须完成的工作:

  • 作为@gre_gor already explained,您可能会在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
    }
}

如果只发送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
            }
        }
    }
}

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

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

为了节省更多时间,您可以检查每个值,并且只有在上次调用后该值发生变化时才会调用analogWrite()(对于每个R,G和B)。

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

如果以后可能有其他消息类型,每条消息也可以添加消息代码(1或2个字节)。