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?
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.
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')) {
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