Problems with reading serial into an array.

Hi all,

I've got a problem i'm desperate to solve and have been struggling with for some time.

I have telescope which i read it's position from in degrees (0-359) every second through a serial cable and then write it into an array.

My arduino program then check's the contents of the array every 2 mins then displays it on an lcd (e.g 159). This is a continuous loop, checking the array every 2 mins.

My problem is that the first read of the array works fine (e.g. 159), then say 2mins later postion of the telescope hasn't changed and should still read 159, but i'm doing something wrong with the array where it get's truncated and then read 15 instead of 159).

The value from the serial is 3 numbers stored into the array.

My code is below

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);


unsigned long previousMillis;


void setup()
{
  lcd.begin(20, 4);          
  Serial.begin(9600);
}

const int MAX_LEN = 4; // the max digits in the number plus decimal point
char  strValue[MAX_LEN + 1]; // add one for the terminating null

int index = 0;
int x;
int y;
int z = 360;
int result;
int movesteps;


void loop()
{
  
lcd.setCursor(9,3);
lcd.print(x);
    GetAz();
    
    x = y;
       printdome();
       printaz();
       ButtonPress();
       llegirPos();

  
if (millis() - previousMillis > 120000){

  previousMillis = millis();
     GetValue2();


     
     printdome();


 void GetAz(){ 
  if( Serial.available())
  {
    char ch = Serial.read();
    if(index < MAX_LEN && ch != 13) // 13 is ascii value of carriage return
    {
      strValue[index++] = ch; // add the ASCII character to the string;
        
    }
    else
    {
      // here when buffer full or on the first non digit
      strValue[index] = '\0';        // terminate the string with a 0
   
      index = 0;      // reset the index for the next string

    }  
  }
 }
 

 
 void GetValue2(){
            y = atoi(strValue);  // use atof to convert the string to a float
           
            lcd.setCursor(9,3);
            lcd.print(y);
                     previousMillis = millis();
                   }

Apparently, you got cut off before all your code was posted.

The GetAz function concerns me. GetAz may be called thousands of times per second. If some data has been placed in the serial buffer, GetAz will read whatever is there, regardless if what is there represents a complete packet. Ideally, it would keep reading data until the end of the packet (the 13) has arrived.

In addition, the strValue array is not null-terminated after each character is added. Therefore, when atoi is called, in GetValue2, the function is not guaranteed to return meaningful data.

Hi Paul,

Any suggestions / recommendations ?

Rich.

This is how I would code GetAz to read until an end-of-packet marker arrived:

void GetAz()
{
   if(Serial.available())
   {
      char ch = Serial.read(); // Read a character
      while(ch != 13) // 13 is ascii value of carriage return
      {
         if(index < MAX_LEN && ch > 0) If character is valid, and there is room...
         {
           strValue[index++] = ch; // add the ASCII character to the string;
           strValue[index] = '\0';
         }

         ch = Serial.read(); // Read another character
      }  
   }
}

Post the rest of (or more of) your code.

Thanks Paul,

I'll give it a try tomorrow and i'll let you know how i get on.

Rich.

Hi Paul,

I tried your code last night and i couldn't get it to work, it just sat there and did nothing almost as if the array wasn't storing any data.

I'll have another look tonight.

it just sat there and did nothing

That "while" loop is suspect.
Although it calls "Serial.available" at the top, it will read two characters.
Suppose "available" returns 1.
You read the character and buffer it (assuming it isn't a carriage-return).
Then you read another character.
There isn't one (it hasn't arrived yet), so "read" returns -1.
Then you read another one...

The idea behind that function is that it will keep reading until the end-of-packet marker arrives. There may not be any serial data to read. That's OK, because the function does nothing with invalid data (which is what the Serial.read function returns when there is nothing to read).

Hi guys,

assuming that an external program send 3 bytes with an additional carrige return as a null string once a second to arduino.

The arduino application itself then checks the data in the array every 2 mins then drives a motor according the data it reads.

Becuase my inital code works once, then has a problem the second time the arduino reads the array only getting 2 characters returned instead of 3 (e.g. 159 ---> 15 ) effectively loosing the last stored byte, i'm wondering if it's a simple issue of flushing the array after each read ?

If you can suggest a better way of handling the data and storing it in an array so it can be read as a 3 digit number than i'm more than happy to listen to your expert advice.

Rich.

3 bytes with an additional carrige return as a null string

By my understanding, a null string is simply a character array with a zero in the first (zeroth) element.

3 bytes with an additional carrige return as a null string

I think he meant null-terminated.

Hi Guys,

sorry for the confusion with the wrong terminology. the VB program that reads the mount then sends the data to the serial port for the arduino to read.

the string ends with a vb carrige return which i think is ascii 13

Apologies for the poor explanations as i'm new to programming and dont fully understand ther terminology yet.

I guess i'm just trying to understand, what is happening, when arduino read the array properly the first time, then the next time it dumps the first digit, i'm guessing it's shuffling the data along in the array somehow.

I'm wondering if this part of the code could be the culprit

  else
   {
     // here when buffer full or on the first non digit
     strValue[index] = '\0';        // terminate the string with a 0

What does terminating the string with a '\0' actually do ? could this be the cause of the first byte going missing on the next loop ?

Rich.

In C, a string is simply an array of "char"s, with a zero (null) as its last element.
Imagine an array of say 20 "char"s, into which you want to put the word "Hello" and then print it.

So, into element zero, you put the letter 'H', into element one, you put the letter 'e', and so on.

Now, in a 20 element array, you've only got five letters you're interested in. The rest could contain garbage from last time you used the array.

You could say to your "print" routine, "Here's a pointer to an array, and there are five characters in it", or, you could create the convention that a zero in a string represents the end of the string.

Now, you only need to pass your "print" routine a pointer to the array, and it prints characters one-by-one until it finds a zero.

From your original code:

// here when buffer full or on the first non digit
     strValue[index] = '\0';        // terminate the string with a 0
 
     index = 0;      // reset the index for the next string

Where did you put the NULL? You'd know, and have put it in the right place, if you set index to 0 first.

thanks Groove that's a very clear explanation.

Paul / groove, currently my external vb app writes information to the serial port and then adds a carrige return (Ascii 13). So the last thing the serial port see's is the ascii for a carrige return which i'm assuming is 13

Unfortunately i can't tell you much more than that as someone wrote the little app for me. I'm assuming that they dont use a zero to end the string as the number in the scope of the data being sent to serial port (0 -> 359 10, 20, 30 etc all have zero's)

So this is why i use the code below

      char ch = Serial.read(); // Read a character
      while(ch != 13) // 13 is ascii value of carriage return
      {

So lets say the array is 10 bytes in size, and the following 3 bytes are sent 159 followed by (ascii 13) for a carrige return. Then how would the array data look if we terminate with a null zero value

     strValue[index] = '\0';        // terminate the string with a 0

1591300000

I'm also assuming that when i set the index of the array to 0 then it forces data to be put at the very start of the array and overwrite any old data there.

So instead of terminating the string with a Zero, is it ok to terminate a string with a value like an 'X',

     strValue[index] = '\X';        // terminate the string with a X

Earlier in the post, AWOL mentioned something about the the null string 0 being placed in the very first position in the array ? is this correct, as this would explain the missing charater where my data goes from 159 --> 15 ?

One last question, if i have 3 bytes of data plus ascii 13 for carrige return, should i make the array 5 bytes in size ?

Sorry for all the questions, i'm desperately trying to learn.

Regards,
Richard.

I think you may be confusing the number zero (nothing, zippo, zilch) with the ASCII character zero (0x30)

I'm assuming that they dont use a zero to end the string as the number in the scope of the data being sent to serial port

Not necessary. The NULL is the character that terminates the transmission, so it it not sent.

So lets say the array is 10 bytes in size, and the following 3 bytes are sent 159 followed by (ascii 13) for a carrige return. Then how would the array data look if we terminate with a null zero value

On the sending end:

char array[10];

array[0] = '1';
array[1] = '5';
array[2] = '9';
array[3] = 13;
array[4] = '\0';

On the receiving end:

char array[10];

array[0] = '1';
array[1] = '5';
array[2] = '9';
array[3] = '\0';

The carriage return (ascii value 13) is not stored.

I'm also assuming that when i set the index of the array to 0 then it forces data to be put at the very start of the array and overwrite any old data there.

True.

One last question, if i have 3 bytes of data plus ascii 13 for carrige return, should i make the array 5 bytes in size ?

The carriage return is not stored on the Arduino, so the array only needs to be 4 bytes - 3 for the characters and one for the NULL.

Sorry for all the questions, i'm desperately trying to learn.

Sorry for all the answers. We're desperately trying to teach.

Hi Paul,

Thanks for your detail responses, I really appreciate your help.

On the send end, where does this '\0' come from, if the vb application sends 1,5,9 and a carrige return ?

is the null string something that is automatically added ?

I thought it would look like below ?

char array[4];

array[0] = '1';
array[1] = '5';
array[2] = '9';
array[3] = 13;
'

VB hides the details that distinguish strings from character arrays. Internally, the strings are NULL terminated character arrays, just like on the Arduino (in C).

I;m really struggling here.

It doesn't matter what size i make the array, i always end up with the same thing, as soon as arduino reads a 3 byte arrange the second time it reads it always chops off the last byte (159 becomes 15).

Rich.