arduino serial erratic behaviour missing character

2019-09-05 07:53发布

问题:

I have a problem with the hardware serial on the UNO, in many occasions it seems to drop a character (usually the first character being received) and in some cases it misses a whole transmission. this only occurs when the Arduino is receiving data from the computer typed by me in the serial monitor. I can see the RX light flashing when I send the string but the arduino just completely ignores it.

The data I am sending is three comma separated 8 bit unsigned integers

#include <Adafruit_NeoPixel.h>
//#include <OneSheeld.h>

#define PIN 6
#define LEDS 5

Adafruit_NeoPixel strip = Adafruit_NeoPixel(LEDS, PIN, NEO_GRB + NEO_KHZ800);
int leds = LEDS-1;
byte red;
byte green;
byte blue;
int i;
// pins for the LEDs:
//const int red = 3;
//const int green = 5;
//const int blue = 6;

void setup() {
  // initialize serial:
  Serial.begin(9600);
  strip.begin();
  strip.setPixelColor(0,12,12,12);
     strip.show(); // Initialize all pixels to 'off'
     Serial.print("number of LEDS in strip:");
     Serial.println(LEDS);
     i=0;
  // make the pins outputs:
//  pinMode(redPin, OUTPUT); 
//  pinMode(greenPin, OUTPUT); 
//  pinMode(bluePin, OUTPUT); 

}

void loop() {
  red = 0;
  green=0;
  blue= 0;

 // i=0;
  // if there's any serial available, read it:
  while (Serial.available() > 0) {

    // look for the next valid integer in the incoming serial stream:
      red = Serial.parseInt(); 
    // do it again:
      green = Serial.parseInt(); 
    // do it again:
       blue = Serial.parseInt();
       delay(1);

    // look for the newline. That's the end of your
    // sentence:
    if (Serial.read() == '\n') {
      // constrain the values to 0 - 255 and invert
      // if you're using a common-cathode LED, just use "constrain(color, 0, 255);"
//      red = constrain(red, 0, 255);
//      green = constrain(green, 0, 255);
//      blue = constrain(blue, 0, 255);     
         Serial.print("LED being served = ");
         Serial.println(i);


      // fade the red, green, and blue legs of the LED: 

//      analogWrite(redPin, red);
//      analogWrite(greenPin, green);
//      analogWrite(bluePin, blue);
      strip.setPixelColor(i,red,green,blue);
      strip.show();

      // print the three numbers in one string as hexadecimal:
      Serial.print("R=");
      Serial.println(red);
      Serial.print("G=");
      Serial.println(green);
      Serial.print("B=");
      Serial.println(blue);

     if(i==leds)
     i=0;
     else
     i=i+1;
    }
  }
}

and here is some example output from the serial monitor when entering the following string string: <25,25,25>

output:

number of LEDS in strip:5
LED being served = 0
R=25
G=25
B=25
LED being served = 1   <<< this transmission got lost the first time it was sent
R=25
G=25
B=25
LED being served = 2
R=25
G=25
B=25
LED being served = 3
R=5
G=25
B=25
LED being served = 4 <<< This transmission got lost the first 4 times it was sent
R=5
G=25
B=25
LED being served = 0
R=25
G=25
B=25
LED being served = 1
R=25
G=25
B=25
LED being served = 2
R=25
G=25
B=25
LED being served = 3
R=25
G=25
B=25
LED being served = 4
R=5
G=25
B=25
LED being served = 0
R=25
G=25
B=25
LED being served = 1
R=5
G=25
B=25
LED being served = 2
R=25
G=25
B=25
LED being served = 3
R=25
G=25
B=25
LED being served = 4
R=25
G=25
B=25

Thanks

回答1:

Your problem is most likely a timing issue:

while (Serial.available() > 0) {
  red = Serial.parseInt(); 
  green = Serial.parseInt(); 
  blue = Serial.parseInt();

Note that the first time you get inside this while loop, you've only just received your first byte from the serial line. The second byte may not even be on the wire yet. If you've sent "25,25,25" to the Arduino and it only has the first character, red = Serial.parseInt() will return 2 and assign that to red. green = Serial.parseInt() will get 5, and blue = Serial.parseInt() will get 25. Then you're stuck with ",25" in your serial buffer, which will likely cause more problems on the next pass through loop().

The docs on parseInt() say that it will wait up to a second for a valid integer byte, but it doesn't say what it will do once it has one, whether it will wait around for 1/Hz seconds to see if there's more coming or not. If it does, then you have to look at the potential hardware causes....

You have to keep in mind that serial is NOT a reliable protocol. Each byte is checked for parity before it is delivered to the application and, if the parity fails, it may not be delivered at all.

I've had problems like this with the Arduino before. All it takes is some stray RF, noise on your breadboard, or any number of other electrical problems, and when you go to read the serial line, a 0 becomes a 1 or vice-versa. Given that losses are happening on your first byte in a series, I strongly suspect that you're seeing a symptom of this. If you have slow voltage accumulation on your serial pin, when you go to read it, the first thing you're going to see is a 1. My current project identifies high and low bytes by setting the top bit to 0 and 1 in alternation. Occasionally, I get a triple of 0-prefixed bytes or a triple of 1-prefixed and I just chuck those samples.

Is your UNO sitting on an electrically insulated surface? If you're using a breadboard, how much do you trust it? Are you sure that you're getting near-zero resistance along connection lines and near-infinite resistance between them? Do you have a crappy USB cable handling your serial channel? If so, a strong RF signal nearby could be contributing to your problem.