Go Down

Topic: Weirdness with Serial.read() - extra character? (Read 960 times) previous topic - next topic

gpvillamil

I am having a weird problem with the program below. Basically it is designed to read an ascii character, followed by a 3 digit decimal number, and use that to position a servomotor and return a sensor reading.

For example, a message would look like 'a123' - the 'a' would be stripped off, the '123' converted to an integer with that value, etc.

The weirdness is this: the initial 'a' is read correctly, and the right case statement chosen. However, the first of the numeric characters read is always a byte with a value of 255! The next two bytes are the correct ascii values for the first two digits of the numeric parameters. It is as if an extra byte was sneaking in between the 'a' and the '123'.

/*
Rangefinder control
Gian Pablo Villamil
October 10, 2006

This program waits for a signal from processing to move to an angle, then returns a
rangefinder reading at that angle.

*/

int servoPin = 9;     // Control pin for servo motor
int minPulse = 500;   // Minimum servo position
int maxPulse = 2500;  // Maximum servo position
int pulse = 0;        // Amount to pulse the servo

int lastPulse = 0;    // the time in milliseconds of the last pulse
int refreshTime = 20; // the time needed in between pulses

int analogValue = 0;  // the value returned from the analog sensor
int analogPin = 0;    // the analog pin that the sensor's on

int rangeFinderValue = 0;
int rangeFinderPin = 1;

int servoAngle = 0;
byte incomingByte ;

int scale(int inputValue, int inputMin, int inputMax, int outputMin, int outputMax);
void moveServoTo(int angle) ;
void returnReading() ;

void setup() {
 pinMode(servoPin, OUTPUT);  // Set servo pin as an output pin
 pulse = minPulse;           // Set the motor position value to the minimum
 Serial.begin(9600);
 servoAngle = 0;
 lastPulse = millis();
}

void loop() {
 if (Serial.available()) { // message available?
   incomingByte = Serial.read();
   switch (incomingByte) { // what is it?
   case 'a':
     // set servo angle and get reading
     servoAngle = 0;
     for (int i = 0; i <=2; i++) {
       incomingByte = Serial.read();
       Serial.println(incomingByte,DEC);
       servoAngle = servoAngle * 10 + (incomingByte - 48);
     };
     Serial.print("received servoangle = ");
     Serial.println(servoAngle);
     pulse = scale(servoAngle,0,255,minPulse,maxPulse);
     Serial.print("pulse = ");
     Serial.println(pulse);
     moveServoTo(pulse);  // move the motor
     returnReading();     // return the reading
     break; // Break from the switch
   case 'i':
     // set minimum
     Serial.println("minimum");
     break;
   case 'o':
     // set maximum
     Serial.println("maximum");
     break;
   }
   while (Serial.available()) {
     incomingByte = Serial.read(); // clear the buffer
   };

 }

 // if nothing else happened, refresh the servo

 if (millis() - lastPulse >= refreshTime) {
   moveServoTo(pulse);
   lastPulse = millis();           // save the time of the last pulse
 }
}

void moveServoTo(int pulse) {
 digitalWrite(servoPin, HIGH);   // Turn the motor on
 delayMicroseconds(pulse);       // Length of the pulse sets the motor position
 digitalWrite(servoPin, LOW);    // Turn the motor off
}

void returnReading() {
 rangeFinderValue = analogRead(rangeFinderPin);
 Serial.print("r ");  // we are returning a reading
 Serial.print(rangeFinderValue, DEC); // send the reading
 Serial.println(); // send a carriage return
}

int scale(int inputValue, int inputMin, int inputMax, int outputMin, int outputMax) {
 return ((outputMax-outputMin)*(inputValue-inputMin)/(inputMax-inputMin)+outputMin);
}

mellis

255 (or -1) is the value returned by Serial.read() when no character is available.  It sounds as though you're trying to read the characters faster than they are arriving on the serial connection. Try adding a delay before the second Serial.read() call, or check that more than one byte is available with Serial.available().  


Go Up