Serial.write stops working if not used?

So I’m using the Arduino Mega 2560 to receive data using Serial1 and trying to print it on my PC screen using Serial0. If I try to print ONLY phi.data with Serial.println(phi.data) from within loop(), I get nothing. However, if I include the line Serial.println(“Reading sensor…”) in the readSensor() function, then the program prints both lines in the Serial Monitor on my PC. For data acquisition purposes, this is infuriating. Why doesn’t the program output just the one line? Why do I have to use the serial.println() function in more than one function for it to work? Shortened version of program follows:

struct Sensor{
int data;
}psi;

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

void loop(){
TRY_AGAIN:
readSensor();
if (Data_not_acquired){
goto TRY_AGAIN;
}
Serial.println(psi.data);

}

void readSensor(){
Serial.println("Reading sensor..."); /*This is the line that creates trouble!*/
//Code that reads data; works perfectly fine. 
psi.data = Serial1.read();
}

If anyone wants to see the full program, let me know. Otherwise, does anyone know what the heck is going on?

If anyone wants to see the full program, let me know.

Do you want help or pointless sarcastic speculation?

Well, I figured I would provide the general outline of the prog to prevent visual clutter, but here it is:

//AUTHOR: Jaz S

#define BAUD    115200
#define ANGLE_SCALE_FACTOR 0.0109863     // Convert register data to Degrees

boolean IMU_flag = false;

struct IMU{
  int data;
} phi, theta, psi;

void setup(){
  Serial.begin(BAUD);   //Sets baud rate for PC USB 
  Serial1.begin(BAUD);  //Sets baud rate for Serial port 1
  Serial.println("Setup complete");
}

void loop(){
 Serial.println("Starting loop"); //Makes no difference if I leave this in or take it out. 
  POLL_AGAIN:
  read_UM6();
  if (IMU_flag == true){
  
  Serial.println(psi.data*ANGLE_SCALE_FACTOR);/*This is the data I want printed, from this very line of code. It doesn't happen if I don't have the Serial.print() in the read_UM6() function.*/
  delay(250);
  }
  else {
    goto POLL_AGAIN; 
  }
}//end VOID

void read_UM6(){
  Serial.print("Reading IMU... "); /*This is the line that creates trouble! If I take it out, loop() the whole program stops.*/
  phi.data = 0;
  theta.data = 0;
  psi.data = 0;
 
  unsigned int c = 0;
  unsigned int data[5] = {0};
  unsigned long data_sum = 0;
  byte blank = 0, temp = 0;
  byte chksum1 = 0, chksum0 = 0;
  unsigned int chksum = 0;
  //If there's data in the serial temp register and we haven't finished retrieving data...
  if ((Serial1.available() > 0)) {
    c = Serial1.read();
    if ((c == 's')){
      c = Serial1.read();
      if ((c == 'n')){
        c = Serial1.read();
        if ((c == 'p')) {
          c = Serial1.read();
          if (c == (PT_HAS_DATA | PT_IS_BATCH | PT_BATCH_LEN))  {
            c = Serial1.read();
              if (c == REG_EULER_PHI_THETA)  {
                for (byte i = 0; i < 6; i++){          
                data[i] = Serial1.read();
                data_sum += data[i];
                }
                blank = Serial1.read();
                blank = Serial1.read();
                chksum1 = Serial1.read();
                chksum0 = Serial1.read();            
                chksum = (chksum1 << 8) | chksum0;
                if (chksum == ('s' + 'n' + 'p' + (PT_HAS_DATA | PT_IS_BATCH | PT_BATCH_LEN) + REG_EULER_PHI_THETA + data_sum)){  /*If checksum is correct...*/
                  phi.data = (data[1] | (data[0] << 8));
                  theta.data = (data[3] | (data[2] << 8));
                  psi.data = (data[5] | (data[4] << 8));
                  IMU_flag = true;
                  return;
                }
                else {
                  FLUSH:
                  while ((Serial1.available() > 0)){
                  blank = Serial1.read();  
                  }
                  IMU_flag = false;
                  return;
                }
              }
            else {
             goto FLUSH;
            }
          }
          else
          {
           goto FLUSH; 
          }
        }
        else
        {
         goto FLUSH; 
        }
      }
      else
      {
       goto FLUSH; 
      }
    }
    else
    {
     goto FLUSH; 
    }
  }//end if
//If no data is available and we have not retrieved data...
  else if (Serial1.available() == 0){
    IMU_flag = false;
    return;
  }  //end else
  else {
   IMU_flag = false;
   return;
  }
}  //end void

I was about to say "get rid of the goto, but I see you are using them all over the place. Ach!

Change:

TRY_AGAIN:
readSensor();
if (Data_not_acquired){
goto TRY_AGAIN;
}

To:

do
  {
  readSensor();
  }
  while (!Data_not_acquired);

Ditto for other similar places.


This is wrong:

 if ((Serial1.available() > 0)) {
    c = Serial1.read();
    if ((c == 's')){
      c = Serial1.read();
      if ((c == 'n')){
        c = Serial1.read();
        if ((c == 'p')) {
          c = Serial1.read();

The line "if ((Serial1.available() > 0))" guarantees you have one byte. You are reading at least four. Your serial print elsewhere simply gives it more time to catch up. You need to rework that bit.

                else {
                  FLUSH:
                  while ((Serial1.available() > 0)){
                  blank = Serial1.read();  
                  }
                  IMU_flag = false;
                  return;
                }
              }
            else {
             goto FLUSH;

Please don't do this. This is what you call "spaghetti code". You will have problems all over the place. Rewrite without using goto.

Duly noted. Rewriting.

However, if I include the line Serial.println(“Reading sensor…”) in the readSensor() function, then the program prints both lines in the Serial Monitor on my PC.

There isn’t such a line! “Reading IMU…” there is however. I presume the time that line takes to execute is allowing the incoming serial data to arrive before you try reading it with your broken code - fix the use of available() and your code won’t be sensitive to such things. How about defining a helper like:

int blocking_read ()
{
  while (Serial1.available () < 1)
  {}
  return Serial1.read () ;
}

I want to express my sincere gratitude for your advice. I have now revised my program. However, it is still experiencing the original problem of not looping unless serial.print() is used in another function (the first line of readUM6()). Any ideas?

//AUTHOR: Jaz S;

#define BAUD    115200

#define REG_EULER_PHI_THETA 0X62
#define REG_EULER_PSI       0x63
#define ANGLE_SCALE_FACTOR 0.0109863     // Convert register data to Degrees

boolean IMU_flag = false;

struct IMU{
  int data;
} phi, theta, psi;

void setup(){
  Serial.begin(BAUD);   //Sets baud rate for PC USB 
  Serial1.begin(BAUD);  //Sets baud rate for Serial port 1
//  Serial.println("Setup complete");
}

void loop(){
// Serial.println("Starting loop");
do{
  read_UM6();
}while (IMU_flag == false);
  Serial.print("psi...   ");
  Serial.println(psi.data*ANGLE_SCALE_FACTOR);
  delay(250);

}//end VOID

void read_UM6(){
  Serial.println("Reading IMU... ");//If this line is excluded from the overall program, the whole thing stops working.
  psi.data = 0;
  byte i = 0;
  unsigned int data[15] = {0};
  unsigned long data_sum = 0;
  byte blank = 0, temp = 0;
  byte chksum1 = 0, chksum0 = 0;
  unsigned int chksum = 0;
  //If there's data in the serial temp register and we haven't finished retrieving data...
  while ((Serial1.available() > 0)) {
    for (i=0; i < 15; i++){
    data[i] = Serial1.read();
    }
  }
    if ((data[0] == 's')){
      if ((data[1] == 'n')){
        if ((data[2] == 'p')) {
          if (data[3] == (PT_HAS_DATA | PT_IS_BATCH | PT_BATCH_LEN)){
              if (data[4] == REG_EULER_PHI_THETA){
                for (byte j = 5; j <= 12; j++){          
                data_sum += data[j];
                }
                blank = data[11];//12
                blank = data[12];//13
                chksum1 = data[13];//14
                chksum0 = data[14];//15        
                chksum = (chksum1 << 8) | chksum0;
                if (chksum == ('s' + 'n' + 'p' + (PT_HAS_DATA | PT_IS_BATCH | PT_BATCH_LEN) + REG_EULER_PHI_THETA + data_sum)){  //If checksum is correct...
                  phi.data = (data[6] | (data[5] << 8));
                  theta.data = (data[8] | (data[7] << 8));
                  psi.data = (data[10] | (data[9] << 8));
                  IMU_flag = true;
                  return;
                }//1
              }//2
              else{
                IMU_flag = false;
                return;
              }
          }//3
          else{
            IMU_flag = false;
            return;
          }
        }//4
        else{
          IMU_flag = false;
          return;
        }
      }//5
      else{
        IMU_flag = false; 
        return;
      }
    }//6
      else{
        IMU_flag = false;
        return;
      }
else {
  IMU_flag = false;
  return;
}
  while ((Serial1.available() > 0)) {
    for (i=0; i < 15; i++){
    data[i] = Serial1.read();
    }
  }
    if ((data[0] == 's')){
    ...

Still reading 15 bytes of data after checking for only more than 0. If you know it’s going to be 15 bytes, why not just wait until there is 15 bytes in the buffer instead of more than 0?

if ((data[0] == 's')){
      if ((data[1] == 'n')){
        if ((data[2] == 'p')) {

This should help shorten it a bit:

if (strncmp(data, "snp", 3) == 0)

Slappy:
I want to express my sincere gratitude for your advice. I have now revised my program. However, it is still experiencing the original problem of not looping unless serial.print() is used in another function (the first line of readUM6()). Any ideas?

Your code doesn't compile, so it is difficult to help.

sketch_oct09d.cpp: In function 'void read_UM6()':
sketch_oct09d:49: error: 'PT_HAS_DATA' was not declared in this scope
sketch_oct09d:49: error: 'PT_IS_BATCH' was not declared in this scope
sketch_oct09d:49: error: 'PT_BATCH_LEN' was not declared in this scope
sketch_oct09d:91: error: 'else' without a previous 'if'
sketch_oct09d.cpp:43: warning: unused variable 'temp'
sketch_oct09d:94: error: expected `}' at end of input
                blank = data[11];//12
                blank = data[12];//13

What does this achieve? You don’t use blank.


  while ((Serial1.available() > 0)) {
    for (i=0; i < 15; i++){
    data[i] = Serial1.read();
    }
  }

How about:

  while ((Serial1.available() >= 15)) {
    for (i=0; i < 15; i++){
    data[i] = Serial1.read();
    }
  }

All of this:

    if ((data[0] == 's')){
      if ((data[1] == 'n')){
        if ((data[2] == 'p')) {
          if (data[3] == (PT_HAS_DATA | PT_IS_BATCH | PT_BATCH_LEN)){
              if (data[4] == REG_EULER_PHI_THETA){
                for (byte j = 5; j <= 12; j++){          
                data_sum += data[j];
                }
                blank = data[11];//12
                blank = data[12];//13
                chksum1 = data[13];//14
                chksum0 = data[14];//15        
                chksum = (chksum1 << 8) | chksum0;
                if (chksum == ('s' + 'n' + 'p' + (PT_HAS_DATA | PT_IS_BATCH | PT_BATCH_LEN) + REG_EULER_PHI_THETA + data_sum)){  //If checksum is correct...
                  phi.data = (data[6] | (data[5] << 8));
                  theta.data = (data[8] | (data[7] << 8));
                  psi.data = (data[10] | (data[9] << 8));
                  IMU_flag = true;
                  return;
                }//1
              }//2
              else{
                IMU_flag = false;
                return;
              }
          }//3
          else{
            IMU_flag = false;
            return;
          }
        }//4
        else{
          IMU_flag = false;
          return;
        }
      }//5
      else{
        IMU_flag = false; 
        return;
      }
    }//6
      else{
        IMU_flag = false;
        return;
      }
else {
  IMU_flag = false;
  return;

Could be simplified to:

    if (data[0] == 's' && data[1] == 'n' && data[2] == 'p')
          if (data[3] == (PT_HAS_DATA | PT_IS_BATCH | PT_BATCH_LEN)){
              if (data[4] == REG_EULER_PHI_THETA){
                for (byte j = 5; j <= 12; j++){          
                data_sum += data[j];
                }
                chksum1 = data[13];//14
                chksum0 = data[14];//15        
                chksum = (chksum1 << 8) | chksum0;
                if (chksum == ('s' + 'n' + 'p' + (PT_HAS_DATA | PT_IS_BATCH | PT_BATCH_LEN) + REG_EULER_PHI_THETA + data_sum)){  //If checksum is correct...
                  phi.data = (data[6] | (data[5] << 8));
                  theta.data = (data[8] | (data[7] << 8));
                  psi.data = (data[10] | (data[9] << 8));
                  IMU_flag = true;
                  return;
                }//1
              }//2

  IMU_flag = false;
  }

I might have left off a curly brace there, but you see the idea. Either it succeeds with IMU_flag as true, or you fall through with IMU_flag as false.