Inexplicable serial problem

Hey, guys, I'm faced with a problem I can NOT seem to take care of - or even find what's causing it.
Basically there's one Arduino sending serially the string !A18 and other Arduino (this one) receiving it.

Here's the second Arduino's code:

/*
 * Temperature and Humidity Server
 * version 1.0a
 * by Pedro Tome'
 *
 * How it works:
 * Basically, one Master Arduino receives data
 * from various Slave Arduinos who have Temperature
 * and Humidity sensors, which is then uploaded to
 * a Pachube.com account.
 *
 * This code is for:
 * SLAVE :: TEMPERATURE AND HUMIDITY
 */



/* Temperature Sensor's pre-commands */
#include <OneWire.h>
OneWire  ds(7);  // Temperature Sensor's pin 2 (output) connected to Arduino's pin D7

/* Humidity Sensor's pre-commands */
int humSensor_pin = 0;  // Humidity Sensor's pin 2 (output) connected to Arduino's pin A0
float max_voltage = 3.27;  // Humidity Sensor's output when: 100% humidity @ 0ºC
float ZeroPercentVoltage = 0.8;  // Humidity Sensor's output when: 0% humidity

/* Other pre-comands */
int statusLED = 2;  // Status LED connected to pin D2 to show whether the sketch is running or not
int RX_pin = 0;  // Serial Input pin D0
int TX_pin = 1;  // Serial Output pin D1
char selfAddressLetter = 'A';  // Letter 'A'. Every Arduino has a different Letter Address (Duh!).


void setup() {
  Serial.begin(115200);
  pinMode(statusLED, OUTPUT);
  pinMode(RX_pin, INPUT);
  pinMode(TX_pin, OUTPUT);
}


void loop() {
  Serial.flush();
  boolean stringValid = false;  // initialize a variable that holds the validity status of the received strings
  byte receivedAddressLetter[1] = {'/0'};  // initalize the variable that contains the received Address Letter
  char receivedAddressCRC[2];  // initalize the array that contains the received Address CRC, which is always two characters long
  memset(receivedAddressCRC, '/0', 2);  // set the addressCRC array as all NULL characters
  byte startByte = '/0';  // initialize startByte, the first relevant character of the received messages
  
  unsigned long startTime = millis();  // sets the startTime = to now
  int timeout = 1000;  // sets the timout to 1 second
  while (millis() - startTime < timeout && startByte != '!') {
    startByte = Serial.read();
  }
  
  
  if (startByte == '!') {  // if the Arduino has received a serial message that started with the character '!'
    unsigned long startTime = millis();  // set the startTime = to now
    int timeout = 1000;  // set the timout to 1 second
    while (millis() - startTime < timeout && Serial.available() < 3) {
      ;  // wait for the buffer to be filled with 3 characters while doing nothing
    }
    
    
    /* Read the received Address and its CRC */
    receivedAddressLetter[0] = Serial.read();
    for (int i=0; i < 2; i++) {
      receivedAddressCRC[i] = Serial.read();
    }
    
    
    /* Check the validity of the received content by generating and comparing CRCs */
    unsigned int INTreceivedAddressCRC;
    INTreceivedAddressCRC = htoi(receivedAddressCRC[0])*16+htoi(receivedAddressCRC[1]);  // convert the CRC array into an int
    
    if (INTreceivedAddressCRC == GenerateCRC8(receivedAddressLetter, 1)) {
      stringValid = true;
      Serial.println("The received string is valid.");
    }
    else {
      stringValid = false;
      Serial.println("The received string is NOT valid.");
    }
    
    
    /* Check if the receivedAddressLetter matches THIS ARDUINO's selfAddressLetter
       and, if so, collect data from the sensors and send it to the MASTER */
    if (stringValid == true && receivedAddressLetter[0] == selfAddressLetter) {
      
     /*                        
      * Temperature Sensor code :: START
      */
      int HighByte, LowByte, TReading, SignBit, Tc_100;
      
      byte i;
      byte present = 0;
      byte data[12];
      byte addr[8];
      
      if ( !ds.search(addr)) {
        //Serial.println("No more addresses.");
        ds.reset_search();
        delay(250);
        return;
      }
      
      if ( OneWire::crc8( addr, 7) != addr[7]) {
          Serial.println("CRC is not valid!");
          return;
      }
      
      if ( addr[0] != 0x28) {
          Serial.println("Device is not a DS18B20 family device.");
          return;
      }
      
      // The DallasTemperature library can do all this work for you!
      ds.reset();
      ds.select(addr);
      ds.write(0x44,1);  // start conversion, with parasite power on at the end
      
      delay(900);  // maybe 750ms is enough, maybe not
      // we might do a ds.depower() here, but the reset will take care of it.
      
      present = ds.reset();
      ds.select(addr);    
      ds.write(0xBE);  // Read Scratchpad
      
      for ( i = 0; i < 9; i++) {  // we need 9 bytes
        data[i] = ds.read();
      }
      
      // Converting HEX to readable data...
      LowByte = data[0];
      HighByte = data[1];
      TReading = (HighByte << 8) + LowByte;
      SignBit = TReading & 0x8000;  // test most sig bit
      if (SignBit) // If negative
      {
        TReading = (TReading ^ 0xffff) + 1; // 2's comp
      }
      Tc_100 = (6 * TReading) + TReading / 4;  // multiply by (100 * 0.0625) or 6.25
      
     
      float floated_Tc_100 = Tc_100;  // Floats can't divide ints, so we convert the int to a float
      float cTemperature = floated_Tc_100 / 100;
      if (SignBit) // If it's negative
         {cTemperature = -1 * cTemperature;}
      
      //Serial.print("Tc_100: "); Serial.println(Tc_100);  // Only to make sure cTemperature is correct
      Serial.print("Temperature (Celsius): "); Serial.println(cTemperature);
      
     /*
      * Temperature Sensor code :: END
      */
     
      //--------------------------------------------------------------------------------------
      
     /*
      * Humidity Sensor code :: START
      */
      
      float humSensor_rawRead = analogRead(humSensor_pin);
      //Serial.print("Raw Humidity value: "); Serial.println(humSensor_rawRead);
      
      max_voltage = (3.27-(0.006706*cTemperature));  // The max voltage value drops 0.006705882 Volts for each ºC over 0ºC
      float RH = ((((humSensor_rawRead/1023)*5)-ZeroPercentVoltage)/max_voltage)*100;
      
      Serial.print("Relative Humidity (%): "); Serial.println(RH);
      
     /*
      * Humidity Sensor code :: END
      */
      
      Serial.println("LOOP END -------------------");
      Serial.println();
      
    }  //END if (stringValid == true && receivedAddressLetter[0] == selfAddressLetter)
  }  //END if (startByte == '!')
}  //END void loop()

Here's the expected output:

The received string is valid.
Temperature (Celsius): 16.62
Relative Humidity (%): 84.38
LOOP END -------------------

The received string is valid.
Temperature (Celsius): 16.62
Relative Humidity (%): 83.76
LOOP END -------------------

The received string is valid.
Temperature (Celsius): 16.62
Relative Humidity (%): 83.92
LOOP END -------------------

The received string is valid.
Temperature (Celsius): 16.62
Relative Humidity (%): 83.61
LOOP END -------------------

And here's the ACTUAL output:

The received string is valid.
Temperature (Celsius): 16.62
Relative Humidity (%): 84.38
LOOP END -------------------

The received string is valid.
The received string is valid.
Temperature (Celsius): 16.62
Relative Humidity (%): 83.76
LOOP END -------------------

The received string is valid.
The received string is valid.
Temperature (Celsius): 16.62
Relative Humidity (%): 83.92
LOOP END -------------------

The received string is valid.
The received string is valid.
Temperature (Celsius): 16.62
Relative Humidity (%): 83.61
LOOP END -------------------

This is what I think is happening:

  1. The Arduino receives the string and follows the code to the end.
  2. The Arduino receives the string and DOES NOT follow the code to the end.
  3. The Arduino receives the string and follows the code to the end.
  4. The Arduino receives the string and DOES NOT follow the code to the end.
  5. The Arduino receives the string and follows the code to the end.
  6. etc.

So, can you see the problem? :confused:

Oh, and this also happens with a 9600 baud rate.
I read in another thread this:

  Serial.begin(9600);

This is a limiting factor. Processing and Arduino can talk much faster then this. Try a higher speed, like 115200

So I thought "hey, why the hell not?" and then I turned my baud rate up. :slight_smile:
Does a higher baud rate offer more problems than a lower baud rate? The Master Arduino and the several Slave Arduinos are supposed to talk serially at a distance of approximately 300m (through RS485)...

Thank you!

Does a higher baud rate offer more problems than a lower baud rate?

It can be more prone to line noise, and corruption due to cable capacitance.

void loop() {
  [glow]Serial.flush();[/glow]

On every pass through loop, lets throw away random amounts of data. Hey, that seems like a great idea. NOT!

@PaulS:
So you're against Serial.flush()? I've seen it in most of the sketches that use Serial Comm and it has fixed one problem I had in the early stages of the code.
Anyway, the problem persists even after commenting that line out. :confused:

I've seen it in most of the sketches that use Serial Comm and it has fixed one problem I had in the early stages of the code.

I think you mean masked. Throwing away random amounts of data does not fix anything.

  byte receivedAddressLetter[1] = {'/0'};  // initalize the variable that contains the received Address Letter

Is this comment really useful? Is '/0' supposed to be anything like '\0'?

    unsigned int INTreceivedAddressCRC;
    INTreceivedAddressCRC = htoi(receivedAddressCRC[0])*16+htoi(receivedAddressCRC[1]);  // convert the CRC array into an int
    
    if (INTreceivedAddressCRC == GenerateCRC8(receivedAddressLetter, 1)) {

What value is in INTreceivedAddressCRC if receivedAddressCRC[0] and receivedAddressCRC[1] are both '/0' (whatever that is)?

Where is the GenerateCRC8() function? What does it return if receivedAddressLetter is '/0' (whatever that is)?

Hah, I always get the NULL thingy wrong ('/0' instead of '\0'). Thanks for warning me.

What value is in INTreceivedAddressCRC if receivedAddressCRC[0] and receivedAddressCRC[1] are both '/0' (whatever that is)?

The output of this

char blop[2] = {'\0','\0'};
unsigned int INTreceivedAddressCRC2;
INTreceivedAddressCRC2 = htoi(blop[0])*16+htoi(blop[1]);  // convert the CRC array into an int
Serial.println(INTreceivedAddressCRC2);

is this: 64720

I don't know what it means, but it doesn't matter because [0] and [1] always have a relevant value.

The function is in another code file/tab/whatever.

I don't know what it means, but it doesn't matter because [0] and [1] always have a relevant value.

I don't think so. Look at how often loop executes. What happens if, on any pass through loop, there is no serial data to read?

  unsigned long startTime = millis();  // sets the startTime = to now
  int timeout = 1000;  // sets the timout to 1 second
  [glow]while (millis() - startTime < timeout && startByte != '!')[/glow] {
    startByte = Serial.read();
  }
  
  
  if (startByte == '!') {  // if the Arduino has received a serial message that started with the character '!'
    unsigned long startTime = millis();  // set the startTime = to now
    int timeout = 1000;  // set the timout to 1 second
    [glow]while (millis() - startTime < timeout && Serial.available() < 3)[/glow] {
      ;  // wait for the buffer to be filled with 3 characters while doing nothing
    }

If there's no serial data to read there's nothing to be done. If after one second the Slave doesn't receive a message that starts with '!', the loop ends and starts again.

Going back a bit, I used Serial.flush() to clear the Serial Buffer so that there would be no trash data, like remnants from previously received or sent messages. Does Serial.flush() actually do that? Should I REALLY NEVER even think about using it? Never? Is it one of those functions that is just complete garbage?
(yes, saying goodbye to it is very sad for me.)

Thank you for your continuous support, PaulS.

[edit]Oh, and I tried manually typing the !A18 string in the Serial Monitor and the output is exactly the same.[/edit]

[edit]Hmm.. the problem seems to be in the Temperature sensor code. I tried commenting it out and it worked alright.[/edit]

[edit]OK, the problem is here

if ( !ds.search(addr)) {
        //Serial.println("No more addresses.");
        ds.reset_search();
        delay(250);
        [glow]return;[/glow]
      }

I commented that return out and it worked perfectly. Now I wonder what is happening for the problem to arise intermittently...[/edit]

If there's no serial data to read there's nothing to be done. If after one second the Slave doesn't receive a message that starts with '!', the loop ends and starts again.

If there is no serial data to read, the while loop ends, not the loop function.

The of the code loop is then executed, where you operate on (presumably now) NULL (if you turned the slashes around the right way).

Going back a bit, I used Serial.flush() to clear the Serial Buffer so that there would be no trash data, like remnants from previously received or sent messages.

Only the incoming data is discarded. Output data goes in a different buffer which is not affected by flush(). "The remnants of previously received data" are (typically) not garbage. They are simply the next bytes waiting in the queue to be processed.

Does Serial.flush() actually do that?

Yes, it does.

Should I REALLY NEVER even think about using it? Never? Is it one of those functions

If you know what you are doing, and understand what flush() does, and KNOW that it is going to dump random amounts of data, then, yes, you can use it.

On the other hand, there was some reason that the sender sent the data. Usually, that reason is because the sender expects the Arduino to process, not discard, that data.

Is it one of those functions that is just complete garbage?

No, it isn't garbage. It is often misused, though.

commented that return out and it worked perfectly

That return statement caused a lot of code to be skipped. I'm looking at this on a small screen now. I can't see all the code at once, and I don't understand what it all is doing.

But, I'm glad you found the problem, and were able to fix it.