Serial.available() 的 Arduino 草图通过两次

Arduino sketch with Serial.available() passes twice

当我在 loop() 函数中测试 Serial.available()Serial.available() > 0 时,它似乎 return true 两次 每次我输入串行数据。第二次,它将我代码中的 throttle 值设置为 0。这是代码:

#include <Servo.h>

Servo rc_rotor;

int throttle = 0; // servo position indicates throttle position.

String s_throttle_set = "Throttle set to: ";
String s_throttle_read = "Reading throttle value: ";
String s_action_error = "No action known for input value: ";

void setup() 
{
  rc_rotor.attach(9);
  Serial.begin(9600);
  while(! Serial);
  Serial.println("Throttle value: 0 through 255, or 999 to read current value.");
}

void loop() 
{
  rc_rotor.write(throttle);
  delay(20);
  if (Serial.available()) 
  { 
    int temp_throttle = Serial.parseInt();

    if (temp_throttle >= 0 && temp_throttle <= 180)
    {
      throttle = temp_throttle;
      Serial.println(s_throttle_set + throttle);
    } 
    else if (temp_throttle == 999) 
    {
      Serial.println(s_throttle_read + throttle);
    } 
    else 
    {
      Serial.println(s_action_error + temp_throttle);
    }
  }
}

请注意这段代码不是我的最终杰作。其中大部分来自公开可用的示例。不管怎样,语句 if (Serial.available()) 成功了两次。我的意思是,当我输入 125 之类的值时它是 true,片刻之后当我没有输入任何其他值时它又会是 'true'。我只希望通过这种方式传递一个值。结果是我的 throttle 被设置为我输入的值,然后几乎立即重新设置为 0。为什么会发生这样的事情?

事实证明,硬件或代码没有神秘的问题,正如我最初怀疑的那样。实际上,解决方案只是在 Arduino Serial Monitor 的下拉选项中 select “no line ending”(默认情况下,我猜我的设置为“New Line”)。没有串行监视器插入的附加字符,一切都按预期运行。

我没想到的一件事是 Arduino 软件如何解释换行符。我通过打印通过我的 if 语句生成的 ascii 值进行调试。首先,串行监视器发送了我输入的数字,紧接着是 ascii 10,这是换行符。很好,没问题。但随后 Serial.parseInt() 咀嚼了那条换行符(有轻微但明显的延迟),然后将数字 0 送入我的函数。我花了一点时间才弄清楚原因。以下是 Arduino 语言参考的串行部分的解释:

parseInt()

Description

Looks for the next valid integer in the incoming serial stream. parseInt() inherits from the Stream utility class.

In particular:

  • Initial characters that are not digits or a minus sign, are skipped;
  • Parsing stops when no characters have been read for a configurable time-out value, or a non-digit is read;
  • If no valid digits were read when the time-out (see Serial.setTimeout()) occurs, 0 is returned;

所以Serial.available()换行符进入缓冲区后是true,但是根据Serial.parseInt()没有“有效数字”。可以理解......我们正在查看一个最终超时的空缓冲区。因此 Serial.parseInt() returns 0 并且后面的代码继续使用该值。

问题中的代码假设唯一的输入是来自串行连接的整数,这实际上是一个非常脆弱的假设。如果您需要在可能出现空缓冲区 (null)、换行符或其他意外字符的情况下使用 Serial.parseInt,这应该只是比我在示例代码中做的更好地过滤输入的问题。