Error printing a single element from a sensor data array

Hey everyone

So as the title suggests, I have been trying to Serial.print a specific element from an array that is fed into by a serial device but when I run the following code the serial monitor returns multiple items from the array.

The serial monitor output ranges from outputing all 12 bytes from the array to minimum of 2 bytes of the data i need plus the next element on the array when using a delay function.

The data in comes from bypassing a controller and lcd connection that outputs 12 bytes, 1 by 1 with the start byte of 65.

In the following code I try to test just outputing the 1st byte with Serial.println(contrlrData[0]); but with no delay i get all the data on the serial monitor, and with a delay of 10ms, I can 3 elements including the first bit.

Watched and read almost every resource online on C++ arrays and using serial first before bothering you fine folk but can't seem to find a solution. Please help.

const int arraylength = 12; //controller sends 12 bytes to LCD, first is a start byte is 65 or "A"

int contrlrData[arraylength];

int t = 10;

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600); // test data on monitor
  Serial2.begin(9600); // open port to receive data from controller

  for (int i = 0; i <= arraylength-1; i++) //set initial array elements to 0
    contrlrData[i] = 0;
  
}

void loop() // run over and over
{
  if (Serial2.available()) //check if rx from controller is sending start byte i.e. 65
  {
   for (int j = 0; j < arraylength-1; j++)  //if yes save byte by byte to contrlrData array
    contrlrData[j] = Serial2.read(); // assign incoming data to contrlrData array
       
   Serial.println(contrlrData[0]); //print 1st element in contrlrData array
   
   for (int i = 0; i <= arraylength-1; i++) //reset array elemetns to 0
    contrlrData[i] = 0;    

   delay(t);
  }
}

Serial monitor output for the above code is

65
16
0
65
16
0
65
16
0
65
16
0

and so on... increasing or reducing the delay doesn't help.

you are only reading in 11 bytes in your for(j=0...) loop since you iterate from 0..10

Every time through loop() if anything is available, you do the entire routine of reading in data and printing it. Does this other device continuously send data? Serial communication is very slow compared to how fast a MCU will operate.

What do you expect as output?

  for (int i = 0; i <= arraylength-1; i++) //set initial array elements to 0
    contrlrData[i] = 0;

Waste of time/ code - they're already zero

  if (Serial2.available()) //check if rx from controller is sending start byte i.e. 65

If there is any data available it most likely will be a single byte, and it could be any byte. No where do you test if it is 65, or indeed anything else. So you read a single byte that could be anything and do stuff with it I don't understand.

I think you need to ask yourself why you thought that line of code checked for 65 being present and why you think that after it all the data will be present (it won't be).

I suggest you read Serial input basics, which should explain what you need to do far better than I can.

++Karma; // For posting your code correctly on your first post.

blh64:
you are only reading in 11 bytes in your for(j=0...) loop since you iterate from 0..10

Every time through loop() if anything is available, you do the entire routine of reading in data and printing it. Does this other device continuously send data? Serial communication is very slow compared to how fast a MCU will operate.

What do you expect as output?

The device continously sends 12 bytes one after the other. The serial speed is fine for my end use, which is doing some arthematic to specific bytes in the array (1, 2, 3, 4, 8 ) and serially sending those bytes to another device, which I think is easy if my selected array element is printed on Serial.

Currently with this code, all I want is printing a specific byte i desire, I just dont understand why 3 is printed instead of one? I mean how is that even possible.

TheMemberFormerlyKnownAsAWOL:

  for (int i = 0; i <= arraylength-1; i++) //set initial array elements to 0

contrlrData[i] = 0;



Waste of time/ code - they're already zero

I read somewhere that its good to set them to zero first, but ok, will delete it.

PerryBebbington:
I think you need to ask yourself why you thought that line of code checked for 65 being present and why you think that after it all the data will be present (it won't be).

++Karma; // For posting your code correctly on your first post.

Thanks for the karma, but bummed that its just not doing what I want, :frowning:

Sorry, that was a typo. That comment was actually for a previous rendition of code where I check for the first byte i.e. "65" and then run loop, but realized that it doesnt matter.

Just an FYI, I think there is something related to the timing, cuz changing the delay changes the number of outputs that is printed, I mean printing more than one itself is a bit weird cuz the code only asks for one byte, nevertheless, please help, I am so close to pulling my hair out! lol

Just an FYI, I think there is something related to the timing, cuz changing the delay changes the number of outputs that is printed

It's not the timing, it's the whole approach to the program. I'm not going to explain more because the tutorial I linked to tells you what you need to know and does so much better than anything I can type here.

I think its better to place a identifying byte to specify the end of the message. other vise buffer contains random values.

Thank you of the advice,

I went through the Serial Input Basics thread, great advice, really helpful and came up with the following code.

change1* had to change to a for loop because unlike the example in the thread, i have no control over the recieving data to include an end marker, even though there is a start marker, unless i first print the data with start and end markers and then send it to parse which i dont think i need to do

// variables to hold the parsed data

//int B1 = 0; //
//int B2 = 0; //
//int B3 = 0; //
//int B4 = 0; //
//int B8 = 0; //

#define B1 0
#define B2 0
#define B3 0
#define B4 0
#define B8 0

const int arraylength = 12; 

int contrlrData[arraylength];

int t = 10;

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing

      

boolean newData = false;

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600); // test data on monitor
  Serial2.begin(9600); // open port to receive data from controller
  Serial3.begin(9600); // open port to send data to phone through bluetooth
  
}

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

void loop() {
    recvWithStartEndMarkers(); 
    if (newData == true) {
        //strcpy(tempChars, receivedChars);
            // this temporary copy is necessary to protect the original data
            //   because strtok() used in parseData() replaces the commas with \0
        parseData();
        showParsedData();
        newData = false;
    }
}

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

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    int startMarker = 65; //controller sends 12 bytes to LCD, first is a start byte is 65 or "A"
    int rc;

    while (Serial2.available() > 0 && newData == false) {
        rc = Serial2.read();

        if (recvInProgress == true) {
            for (ndx = 0; ndx < arraylength; ndx++) {  //change1* most significant change
                receivedChars[ndx] = rc;
            }
            //receivedChars[ndx] = '\0'; 
            recvInProgress = false;
            newData = true;  // above 3 lines to reset data input
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

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

void parseData() {      // split the data into its parts

    //tempChars[1] = B1; // copy from index 1 to defined variable
    //tempChars[2] = B2; // 
    //tempChars[3] = B3; //   
    //tempChars[4] = B4; //  
    //tempChars[8] = B8; // 

    receivedChars[1] = B1;
    receivedChars[2] = B2;
    receivedChars[3] = B3;
    receivedChars[4] = B4;
    receivedChars[8] = B8;

    //B1 = tempChars[1]; doesnt work
    //B2 = tempChars[2];
    //B3 = tempChars[3];
    //B4 = tempChars[4];
    //B8 = tempChars[8];    
}

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

void showParsedData() {
    Serial.print("B1 ");
    Serial.print(B1);
    Serial.print(" B2 ");
    Serial.print(B2);
    Serial.print(" B3 ");
    Serial.print(B3);
    Serial.print(" B4 ");
    Serial.print(B4);
    Serial.print(" B5 ");
    Serial.println(B8);
}

There is good news and bad,

Good news, the loop works great, the print only happens based on the set flags, as per the advice on the thread.

However the result on Serial Monitor is

B1 0 B2 0 B3 0 B4 0 B5 0
B1 0 B2 0 B3 0 B4 0 B5 0
B1 0 B2 0 B3 0 B4 0 B5 0
B1 0 B2 0 B3 0 B4 0 B5 0
B1 0 B2 0 B3 0 B4 0 B5 0
B1 0 B2 0 B3 0 B4 0 B5 0
B1 0 B2 0 B3 0 B4 0 B5 0
B1 0 B2 0 B3 0 B4 0 B5 0

I cannot seem to get the data out of the array correctly.

Now i tried multiple things, such as not copying the string temporarily, not sending the termninate string code. Also parse data function does not work when i define the variables B# using int B# = 0;, not well versed enough in C++ to know why.

Does anyone have an idea whats wrong?

What did you expect?
B1 etc are all defined to be zero.

I can't match your expectations to your code.

Wouldn't B# be updated? Declaring using int, the code doesnt compile, defining it compiles it but it doesn't run.

Im confused as to what should i do.

Im confused as to what should i do.

Start by explaining what you want to do, not how you think you should do it.

My serial device connected sends a packet consisting of 12 bytes. 9600 baud, 8-n-1, byte-by-byte, no separators, that comes in as follows,

65
16
48
0
139
0
164
2
13
0
0
4

(e.g: 65 16 48 0 139 0 164 2 13 0 0 0)
(e.g: B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11)

From the 12, first is a start byte, "A", rest are data.

I need to parse bytes B1, B2, B3, B4 and B8, and send it to an app i am building in one line that is comma seperated, the code for parsing and sending as required is not written yet. First i want to test if the data is collected and outputted correctly which is what the above code is intended to do.

However I am unable to successfully retrieve the specific element from the array. I am not sure why.

Thanks in advance

A couple of things...

  1. you don't want to read in all 12 bytes in a for() loop. Read what is available and then return. Your "end marker" is when you reach 12 characters input since you have a constant length string.

  2. You don't need to parse() the data, just access the received characters by index to get the values you want.

// variables to hold the parsed data

//int B1 = 0; //
//int B2 = 0; //
//int B3 = 0; //
//int B4 = 0; //
//int B8 = 0; //

#define B1 0
#define B2 0
#define B3 0
#define B4 0
#define B8 0

const int arraylength = 12;

int contrlrData[arraylength];

int t = 10;

const byte numChars = 32;
char receivedChars[numChars];
char tempChars[numChars];        // temporary array for use when parsing



boolean newData = false;

void setup()
{
  // Open serial communications and wait for port to open:
  Serial.begin(9600); // test data on monitor
  Serial2.begin(9600); // open port to receive data from controller
  Serial3.begin(9600); // open port to send data to phone through bluetooth

}

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

void loop() {
  recvWithStartEndMarkers();
  if (newData == true) {
    showParsedData();
    newData = false;
  }
}

//============
void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = 'A';
  char rc;

  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      receivedChars[ndx] = rc;
      ndx++;
      if (ndx >= arraylength) {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }
    else if (rc == startMarker) {
      recvInProgress = true;
      receivedChars[ndx] = rc;
      ndx++;
    }
  }
}


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

void showParsedData() {
  Serial.print("B1 ");
  Serial.print(receivedChars[1]);
  Serial.print(" B2 ");
  Serial.print(receivedChars[2]);
  Serial.print(" B3 ");
  Serial.print(receivedChars[3]);
  Serial.print(" B4 ");
  Serial.print(receivedChars[4]);
  Serial.print(" B8 ");
  Serial.println(receivedChars[8]);
}

Thanks for the reply, ashamed to say that I gave up trying to parse the data on the arduino and now I am just spitting the data out as it is recieved from the controller serially, and I accomplished my end objective from that approach.

Thanks everyone for helping out.