Practical Debugging Issues- Serial.read for debugging is creating added issues

My magnetometer project will have two arduino’s (+RFM69HW) with one sending control codes and the other receiving the control codes and returning sensor data. My control codes and sensor data are all 2 byte (3 digits (DEC) positive integers (0-999). The control codes are determined by pin interrupts from 3 momentary switches based on look-up table to provide the unique 3 digit integer.

In debugging my control codes and the RFM69 routines, I was under the impression that the main debugging tool was the Serial monitor, so for my early development (before I have the switches wired, etc) I wanted to get the RFM69 code in place and thought I would use the serial input to simply type in various 3 digit codes. I want to have the RFM69 code done and robust to avoid run-on numbers or lose the correct sequence/alignment.

With serial.read debugging I first have to take the serial string and convert it to 3 digit integer to simulate what my final hardware will provide. I want to make sure that only the first 3 digits are captured by the code in case of bounce or any other glitch that could change the sequence control digits processed. In the final it will all be integer but with the serial monitor I need to first limit the string (char) size, use string trimming methods before using functions like atoi() and then I need the Serial. read created string to be wiped clean before the next read and memset() wont work here. I have made sure to add a null to the end of the string but I cannot get it bullet proof, ie to only take the first 1,2,or 3 serial characteris and convert to a string and wipe anything remaining in the string. Years ago I learned my fundamentals with editors where you can set watches and breaks and monitor variables throughout but its been so long I thought Arduino would make this project fly faster.

Here is a simple sketch that just wont return a clean 3 digit integer. Any advice would be greatly appreciated.

// Creates a number from a string
#include <stdlib.h>
char input[4];

void setup()
{
 Serial.begin(9600); 
}

void loop()
{
  if ( Serial.available () > 0 ) 
  {
    static byte i;
    char c = Serial.read ();
    if ( c != '\r' && i < 3 ) // assuming "Carriage Return" is chosen in the Serial monitor as the line ending character
      {
        input[i++] = c;
        Serial.print("Partial input: ");
        Serial.println(input);
      }
    else
    {
      input[i] = '\0';
      i = 0;
      int number = atoi( input );
      Serial.print("here is your number : ");
      Serial.println( number );
      //reset input using memset next line doesn't seem to do anything
      //memset(input,'\r',sizeof(input));
    }
  }
}

Some servo control code that might have some use in your setup.

//zoomkat 11-22-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port
//multi servos added 

String readString;
#include <Servo.h> 
Servo myservoa, myservob, myservoc, myservod;  // create servo object to control a servo 

void setup() {
  Serial.begin(9600);

  //myservoa.writeMicroseconds(1500); //set initial servo position if desired

  myservoa.attach(6);  //the pin for the servoa control
  myservob.attach(7);  //the pin for the servob control
  myservoc.attach(8);  //the pin for the servoc control
  myservod.attach(9);  //the pin for the servod control 
  Serial.println("multi-servo-delimit-test-dual-input-11-22-12"); // so I can keep track of what is loaded
}

void loop() {

  //expect single strings like 700a, or 1500c, or 2000d,
  //or like 30c, or 90a, or 180d,
  //or combined like 30c,180b,70a,120d,

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      if (readString.length() >1) {
        Serial.println(readString); //prints string to serial port out

        int n = readString.toInt();  //convert readString into a number

        // auto select appropriate value, copied from someone elses code.
        if(n >= 500)
        {
          Serial.print("writing Microseconds: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.writeMicroseconds(n);
          if(readString.indexOf('b') >0) myservob.writeMicroseconds(n);
          if(readString.indexOf('c') >0) myservoc.writeMicroseconds(n);
          if(readString.indexOf('d') >0) myservod.writeMicroseconds(n);
        }
        else
        {   
          Serial.print("writing Angle: ");
          Serial.println(n);
          if(readString.indexOf('a') >0) myservoa.write(n);
          if(readString.indexOf('b') >0) myservob.write(n);
          if(readString.indexOf('c') >0) myservoc.write(n);
          if(readString.indexOf('d') >0) myservod.write(n);
        }
         readString=""; //clears variable for new input
      }
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}

There seems to be an inverse correlation between jargon-laden prolixity in asking these sorts of questions, and any actual comprehension by the questioner.

Here's some of the issues I notice with your sketch.

Your loop only does anything, if serial data is available. If you send it three characters, and then no more serial data is available, then it will not actual finish what you presumably intend it to be doing. You might want to consider alternative approaches, like realising when you have received the third character, and therefore starting to do whatever it is that you intend to do with them.

Your Serial.println() of the partially received "string", is dependent upon "input" being a valid argument to the println( ) function, which it might not be, if there is no zero byte anywhere at the end of it.

If you are going to "reset" the array input after you have finished with it, you should reset it to zeros, not to carriage return characters.

What does your sketch actually return ? What does return if you send characters to it, which are not numeric digit characters ? Here's a suggestion, in the else part of your if statement, try printing the actual final version of the input array, to see what you actually got before you tried to convert it to a number.

If you are concerned about alignment of your control codes, the most straightforward approach is to use a delimiter character at the start and/or end of each code message.

I don't know if it is an issue in this particular example, but if you are not aware of the issues concerning the use of the ascii characters 0x0D and 0x0A ( also known as "carriage return" and "line feed" ), and the supposed abstract C/C++ newline character '\n' , then you might find it useful to look into it.

There is a useful explanation here. http://en.wikipedia.org/wiki/Newline#In_programming_languages

Many thanks for the servo code, its very much appreciated.

Putting aside my app, let me ask my question again without all the ancillary stuff. The code example I posted in my 1st message runs fine and converts serial input string to an integer as long as the serial input is 3 digits or less. Please try the code. The problem I am having is if the serial data is more than 3 digits. Type in 9999 and the program returns two values of int number in the serial monitor (this is set for CR option on the serial monitor window).

Partial input: 9
Partial input: 99
Partial input: 999
here is your number : 999
here is your number : 0

If I select in Serial monitor either no line ending or new line, and type in 9999 and hit enter and then 8888, the numbers become truncated incorrectly. I read about the different implementations of CR and NL in various C but I am a newbie and I would greatly appreciate someone explaining how I can get a consistent 3 digit integer from the serial.input regardless of the string length and how I can wipe or reset the string to blank ( it cannot be zero as the integer 0 for the magnetometer is same as due North).

thanks for your patience and sorry if I am not explaining myself too well.

just for further clarification of my last sentence: "how I can get a consistent 3 digit integer from the serial.input regardless of the string length and how I can wipe or reset the string to blank" . I only want to get the first three typed digits and ignore/wipe anything more in the string. As this will be a wireless app I assume some noise will find its way and there may be a transmission-reception with some junk numbers. I want to avoid error checking as the magnetometer values will be changing quickly (it will be mounted on an antenna that is rotating). I would rather throw out a integer that may be junk knowing the next value will not become corrupted because my code did not clean up the previous number (or string in my debugging). I prefer that my project will send integers not strings back and forth, i am only using serial input to manually test the code with different possible integer sequences and this problem came up which i am trying to understand. I would like to avoid having to do 'int to string' conversions on one end and the reverse on the other end. Hope this makes sense...

Type in 9999 and the program returns two values of int number in the serial monitor (this is set for CR option on the serial monitor window).

When you type in 9999, it will collect the first three character as you would expect. When you get the 4th 9, it will read that character, but because i is already 3, it will go to the else clause and convert and print out the 999. What else would you expect it to do ? Meanwhile, you have read the 4th 9 and effectively chucked it away.

What do you want the system to do , if you type in 9999 ? Or a better question might be, what do you expect it to do if you type in 1234 ?? Do you want the answer 123 ? Do you want the answer 234 ? Do you want 123, and keep the 4 for later, or do you want 123, and chuck the 4 away ?

You need to decide what your program is supposed to do in these scenarios, and then implement that plan in the code.

And back to your supposed example.... Your program will read and store the first 3 9's correctly. It will then read the 4th 9 and execute the else clause and print that you got 999 and reset the array and effectively discard the 4th 9.

It will then receive the carriage return, and again execute the else clause ( with nothing in the array "input" ), and the atio ( ) function will return zero, which is what it does if there is no data there, and then you print that you got the number zero.

So your program is doing exactly what you asked it to do.

Well since you mentioned that you want your code to be “bulletproof”, here are some suggestions.

When you read the char from the serial, check if it is a digit, either ‘0’ or ‘1’ or ‘2’ etc up to ‘9’. If it isn’t, chuck it away.

When you plan to convert the data to an integer, you never check if you actually got three characters, or even whether you got any characters at all.

You don’t seem to have any plan how to deal with the fact that atoi( ) returns zero if it doesn’t get a valid number. This means you cannot tell if you actually got a 0, or garbage somehow.

You say you want to ignore any characters after the first three. How long do you want to ignore them for ? How do you know that the 4th character isn’t the start of another message ? You might want to consider implementing some kind of timeout logic to impose a maximum and/or minimum time between messages.

For a simple process like getting a number from three characters, it might be simpler to control the process yourself by implementing the logic which is in atoi( ) yourself. Here’s an example of how to do this.

int ndig;
int result ;

void do_all_other_stuff ( int code )
{
     //  do all the other stuff in your system using input "code"
}

void setup()
{  
    ndig=0 ;
   result=0 ;
}

void loop()
{
    if ( Serial.available() > 0 )
    {
        int c = Serial.read( ) ;
        if ( c >= '0' && c <= '9' )
        {
            ndig++ ;
            result = 10*result + c ;
            if ( ndig == 3 )
            {
                do_all_other_stuff ( result ) ;
                result=0 ;
                ndig=0 ;
            }
        }
    }
}

If you do it this way, you got no problems with having arrays, no problem of bounds-checking the array, no problems with null-terminated strings, you can completely ignore whether you got carriage returns or line feeds or both, and your system will respond as soon as it receives the third digit instead of waiting around for some other char which might never come, you avoid the need to include a function which may include code verbosity not needed in your application ( like checking for and dealing with + and - signs, which atoi( ) handles, but you don't need here ) and you don't get a spurious response if you just enter the return key several times in a row, and any other character you type will simply be ignored.

You still have the problem of re-synching after bad data. That is where the previous suggestion about delimiters come into use.

If your serial input is coming from something like a GPS, you need to consider how you handle a two-digit number. Do you expect 091 or just 91 ?

Yay, I learned a new word today. I can't wait to weave prolixity into a conversation at work.

It is almost synonymous with "verbose", which is quite common in some computing contexts, in fact more common in computing contexts than any other context, these days. In fact, if there is a distinction between "prolix" and "verbose", I don't know what it is. My guess is that one is latin and the other is greek.

Prolix is waaaaay cooler....

It would be a good name for an unwieldy, inefficient operating system

JimboZA: It would be a good name for an unwieldy, inefficient operating system

No, that would be called "Windows 8".

You won't find ex-PFC Wintergreen saying "Too Windows 8" down the phone.

No, that would be called "Windows 8".

It's funny you should say that, because I was going to say "It would be a good name for an unwieldy, inefficient operating system. Oh wait, they already named it Windows 8."

This whole Thread is too prolix (one is almost tempted to replace the first 2 letters with B but that would make it rude).

If I understand the OP he wants a simple arrangement JUST FOR TESTING so he can send a 1 to 3 digit mumber from the Serial Monitor.

The JUST FOR TESTING is important. If the OP is in control he can easily use his brain (instead of code) to ensure that only suitable data is transmitted. He could even make it really simple by always sending 3 characters such as 007 or 013 or 116.

And ALL of the code for receiving this data should be in a function that can be parachuted into the project code during testing and removed again (without affecting anything else) when no longer needed.

So how about (I haven’t checked if I am using atoi() correctly, but it will be close).

int valRecv = 0; // global variable

void getDataFromSerialMonitor() {
    char dataRecv[4];
    dataRecv[3] = 0;
    if (Serial.available >= 3) {
        for (byte n = 0; n < 3; n++) {
            dataRecv[n] = Serial.read();
        }
       valRecv = atoi(dataRecv);
       while (Serial.available > 0) {   // discard any other characters
           byte discard = Serial.read();
       }
    }
}

…R

Edit to change byte dataRecv[4]; to char so it works with atoi(). …R

He could even make it really simple by always sending 3 characters such as 007 or 013 or 116.

Wouldn't sending octal be more confusing?

Thank you to all for your advice and patience with a newbie. I apologize for my verbosity but I thought giving some insight into my project would be helpful but I realize now that questions should be kept more succinct and better focused. Being new at this, I code something (that may not be the best or correct code) and then find my code doesn’t work as I thought it should so I want to understand why not, even if there could be alternate options to my goal.

Robin2 is correct this came up as I was using Serial for testing and it throws in string arrays whereas my project will likely not deal with that for passing raw data between the wireless Arduinos. But you all raised important advice I need to now consider. The magnetometer will provide a integer between 0-360 and this can be 1, 2 or 3 digits. To get the integer, my code asks the magnetometer for a reading so the frequency of the integer sampling is limited by the instruction cycles and any added delay I impose but the integer will not collide with the next reading unless I screw something up in my code, such as converting to a string array and back again. Yes I am worried about junk characters cropping up in the wireless as there is no error checking but I don’t need error checking since I only have to throw away a nonsense integer. One way I am using is to ignore all integers above 360, and then I also take a moving average of the last 10 values so 1 or 2 junk values will not impact the moving average value.

Thanks again,

I’m surprised nobody has pointed out one rather glaring error in the OPs code - He is indexing the array using the variable i, which is never initialized! This alone could be the source of the flakiness he’s seeing.

There was also an example given in another post to use an atoi replacement as follows:

int c = Serial.read( ) ;
if ( c >= ‘0’ && c <= ‘9’ )
{
ndig++ ;
result = 10*result + c ;
if ( ndig == 3 )
{
do_all_other_stuff ( result ) ;
result=0 ;
ndig=0 ;
}
}

This, of course, will not give the desired result. If a ‘0’ is received, result will be set to 48. If a ‘1’ is then received, result will be set to 97. To get the correct result, the 5th line should read:

result = (10 * result) + (c - ‘0’);

Regards,
Ray L.

He is indexing the array using the variable i, which is never initialized!

The static byte i;?
That’s initialised.