Why does my code give gibberish on the Serial monitor?

/*
Reads Vernier Sensors and outputs the results as follows:

<ec:853.96>
<ph:4.12>
<ec:854.16>
<ph:4.13>

...etc

 See www.vernier.com/arduino for more information.
*/

////////////////////////////////////////
// This is the information on the sensor being used. 
// See the www.vernier.com/products/sensors.

String sensor1 ="ec";
int sensor1Pin = 0;
float interceptSensor1 = 0.0;
float slopeSensor1 = 960;

String sensor2 ="ph";
int sensor2Pin = 1;
float interceptSensor2 = 13.720;
float slopeSensor2 = -3.838;

int timeBetweenReadings = 2000;

//============

void setup() 
{
  Serial.begin(115200); 
}

//============

void loop() 
{
  
  float sensor1Reading = sensorReading(sensor1Pin, interceptSensor1, slopeSensor1);
  Serial.println(serialOutput(sensor1, sensor1Reading));
  
  delay(timeBetweenReadings);
  
  float sensor2Reading = sensorReading(sensor2Pin, interceptSensor2, slopeSensor2);
  Serial.println(serialOutput(sensor2, sensor2Reading));
  
  delay(timeBetweenReadings);
  
}

//============

float sensorReading(int pin, float intercept, float slope){
  float analogReading = analogRead(pin);
  float voltageReading = analogReading / 1023 * 5.0;
  float sensorReading = intercept + voltageReading * slope;
  return sensorReading;
}

//============

String serialOutput(String sensor, float reading){
  char result[5];
  String sensorOutput;
  dtostrf(reading, 4, 2, result);
  if(sensor == "ec"){
    sensorOutput = "<ec:";
    sensorOutput += result;
    sensorOutput += ">";
  } else if(sensor == "ph") {
    sensorOutput = "<ph:";
    sensorOutput += result;
    sensorOutput += ">";
  }
  return sensorOutput;
}

The output on the serial monitor should be:

ec:853.96
ph:4.12
ec:854.16
ph:4.13
ec:852.26
ph:4.13
... etc

But I sometimes get this after plugging / unplugging my board, moving it around, etc, without changing any of the code.

My baud rates match on the serial monitor and the code (115200) and it has worked perfectly before on this baud rate.

⸮⸮⸮⸮⸮⸮(*⸮⸮⸮Necphec ec:455.13⸮m2548.39>548.39>~r⸮.־⸮?
ec:1478.01⸮⸮:4.12>
⸮c:
⸮ec2X⸮⸮⸮ϛ߯⸮⸮⸮L⸮z⸮دl⸮⸮X⸮⸮⸮ƾ⸮⸮⸮⸮⸮⸮⸮⸮⸮⸮]⸮d⸮⸮s⸮⸮⸮}1㫴⸮⸮ď⸮s ⸮⸮jx⸮U>O׭c⸮⸮⸮Aw⸮⸮v⸮⸮⸮⸮,&M⸮⸮4⸮⸮#⸮[ӧ⸮2⸮׭⸮u{⸮⸮.⸮⸮⸮⸮t⸮'⸮⸮⸮⸮s⸮+4⸮y⸮^⸮⸮⸮W⸮ͯ⸮⸮a⸮f⸮⸮⸮)do99⸮⸮⸮⸮⸮⸮⸮⸮7⸮⸮⸮⸮⸮,;⸮;s⸮x⸮⸮h⸮⸮7⸮⸮ R⸮8⸮J⸮ ⸮=⸮⸮.⸮{⸮i⸮zn⸮⸮-⸮⸮⸮⸮⸮K⸮D⸮ Y⸮;n⸮⸮⸮⸮k"^M̻⸮2=⸮_⸮⸮⸮|k⸮O⸮G ߾6⸮⸮⸮⸮I⸮⸮;⸮⸮⸮ӻ⸮⸮⸮%⸮34⸮⸮I⸮⸮'⸮⸮+⸮%⸮⸮⸮⸮G1I@⸮qf]z⸮)>⸮⸮⸮⸮⸮0⸮A⸮o⸮⸮⸮e⸮~⸮

⸮N⸮⸮⸮⸮⸮m⸮{⸮y⸮⸮⸮7⸮⸮/⸮⸮⸮⸮⸮ge⸮⸮⸮⸮⸮⸮⸮⸮⸮p⸮⸮Y⸮y"O⸮o⸮A⸮93V+ڙ⸮ ok⸮N⸮⸮8⸮M⸮⸮ ⸮&銕⸮S⸮⸮o⸮⸮⸮⸮n⸮⸮⸮/⸮\⸮⸮~⸮⸮:⸮m⸮>?⸮⸮⸮u⸮\I⸮^g "en⸮445.75>ec⸮ecӏ
ph:4.12
"en⸮445.75>
ph:4.12
en⸮450.44>
ph:4.12
en⸮450.44>
ph:4.12
e⸮⸮445.75>
ph:4.12
e⸮⸮445.75>
ph:4.12
e⸮⸮445.75>
ph:4.12
e⸮⸮445.75>

What are the causes of gibberish to be sent via serial? This Uno board is also linked via the Tx to an ESP8266 which was happily working, taking the Tx from the Uno and publishing the data to an MQTT broker.

Look at the lower right of your Serial monitor. There is a pull down to change the baud rate. Make sure it matches with your sketch. (115200)

3 Likes

DangerToMyself:
Look at the lower right of your Serial monitor. There is a pull down to change the baud rate. Make sure it matches with your sketch. (115200)

It does. I also tried different baud rates. All the same.

What causes this?

Interference along the USB wire? Interference along the TX wire? Cheap USB cables? Bad 5V USB power source? I've tried powering it from my computer and two different USB chargers.

If I unplug and replug the power it sometimes works. Sometimes it doesn't. I change the cable and it sometimes works. Other times it doesn't.

This is outside right now measuring the pH and electric conductivity of a water tank. I just got it working, walked away, and now after 5 minutes it doesn't work anymore. I put on a plastic rain cover and it doesn't work.

This is really driving me up the wall. The point of this thing is to be able to monitor water conditions when I'm in a different country, and if its going to be this unreliable I can't see how it's going to work.

Hi,
Outside?? How long are your USB Cables??

There are active extenders for USB that work pretty well.

What if you change the baud rate in your Arduino/Monitor to 9600? Better?

terryking228:
Hi,
Outside?? How long are your USB Cables??

There are active extenders for USB that work pretty well.

What if you change the baud rate in your Arduino/Monitor to 9600? Better?

It's just outside on the deck. There's a power cable from the mains extending out there and the USB cables themselves are only 2 feet or so.

Changing the baud rate to 9600 does nothing.

Your sensorOutput variable in serialOutput() goes out of scope. The below will avoid the use of String (capital S) and should work as a drop-in replacement

Create an output buffer in the beginning of your code

char outBuffer[32];
...
...

void setup()
{
  ...
  ...
}

void loop()
{
  ...
  ...
}

/*
  format output information
  in:
    sensor: sensor type (ph or ec)
    reading: sensor reading
  returns:
    pointer to formatted output data
 */
char *serialOutput(String sensor, float reading)
{
  char result[5];
  dtostrf(reading, 4, 2, result);
  if (sensor == "ec")
  {
    sprintf(outBuffer, "<ec:%s>", result);
  }
  else if (sensor == "ph")
  {
    sprintf(outBuffer, "<ph:%s>", result);
  }
  else
  {
    sprintf(outBuffer, "<??>");
  }
  return outBuffer;
}

Compiles, not tested.

You can resize the size of the buffer to suite your needs. I also suggest that you get rid of all Strings (capital S) in favour of normal C strings.

1 Like

Got rid of all Strings

char outBuffer[32];

const char sensor1[] = "ec";
...
...

const char sensor2[] = "ph";
...
...

void setup()
{
  ...
  ...
}

void loop()
{
  ...
  ...
}

/*
  format output information
  in:
    sensor: sensor type (ph or ec)
    reading: sensor reading
  returns:
    pointer to formatted output data
 */
char *serialOutput(const char *sensor, const float reading)
{
  char result[5];
  dtostrf(reading, 4, 2, result);
  sprintf(outBuffer, "<%s:%s>", sensor, result);
  return outBuffer;
}
1 Like

Thank you, that seems to work!

Unfortunately I'm new to C++ code and the Arduino and I still don't understand why my original code doesn't work. I've done Ruby and JavaScript but C++'s handling (mishandling?) of String types really, really confuses me.

  • How was sensorOutput out of scope inside of the serialOutput() function? It was declared inside of the serialOutput() function and then used only inside the if/else statements. It got returned in the end but I haven't experienced out of scope issues in any of the other languages I've done when I've done the exact same thing to other variables.

  • I tried googling for output buffer and I'm still not sure what it is, why there should be one, and when I should use one.

  • I don't understand char result[5]. I think I understand why the 5 is there, but if I change 5 to 1 nothing about my output changes and I still get floats ranging from three to six numbers long. I would expect there to be an error, but there isn't.

Sorry, I should been clearer.

It goes out of scope at the moment that you return from your function. So you return a String object that no longer exists and the results are unpredictable.

sterretje:
Sorry, I should been clearer.

It goes out of scope at the moment that you return from your function. So you return a String object that no longer exists and the results are unpredictable.

Hmmm... interesting that with C++ an object goes out of existence once it's returned if it was originally declared inside the function.

I guess in that case you would need to first declare the variable outside the function, right?

I think I understand what your outBuffer is - it's just an array of some size that you made to eventually hold an array of characters.

What I'm having trouble understanding is why using pointers (*) is necessary in

char *serialOutput(const char *sensor, const float reading)

*sensor I kind of get but I'm at a loss for *serialOutput, the name of the function...

That was not necessary. I made it a drop-in replacement so you did not gave to change loop().

Else you would first have to call the function to fill outBuffer and next print outBuffer.

End yes, if your String was global it would have worked as well. However the use of the String class comes with risks (possibly not on your scenario) and hence it's often advised to forget that it exists in the Arduino; it's fine to use on systems with plenty memory and proper memory management (PCs).

HI Everyone.. Nice work by several people in solving this!