Serial reading in two digit numbers

Alright so this is my first assigned task to conquer with my arduino. I’m controlling a blinking LED through the serial monitor. I have chosen to code it to accept an integer as the HZ of the LED. I originally had a switch statement to handle the input of 1-9 but have chosen to make the program capable of taking in any integer value. Im having trouble taking in two digit numbers and storing them as their true decimal value to be used in a formula. Im well trained in C++ but this is my first time with C so I apologize if any of this seems trivial. Thanks in advance.

void setup() 
{
    //start serial communication
    Serial.begin(9600);
    //assign pin 9 for output
    pinMode(9, OUTPUT);
}

//initialize variable for time delay
double time;

void loop() 
{
    //Blink the LED while no serial data is available
    while(Serial.available() == 0)
    {
      digitalWrite(9, HIGH);   // set the LED on
      delay(time);              // wait for a second
      digitalWrite(9, LOW);    // set the LED off
      delay(time); 
    }
    
    //Assign the serial input to a variable
    char inputC[5] = {0,0,0,0,0};
    int count = 0;
    while(Serial.available() > 0)
    { 
      delay(10);
      inputC[count] = Serial.read();
      count++;
    }
    
    Serial.println(count);
    //if statements to multiply array positions by powers of 10
    if(count==2)
      inputC[0] = inputC[0]*10;
    if(count==3)
    {
      inputC[0] = inputC[0]*100;
      inputC[1] = inputC[1]*10;
    }
    if(count==4)
    {
      inputC[0] = inputC[0]*1000;
      inputC[1] = inputC[1]*100;
      inputC[2] = inputC[2]*10;
    }
    if(count==5)
    {
      inputC[0] = inputC[0]*10000;
      inputC[1] = inputC[1]*1000;
      inputC[2] = inputC[2]*100;
      inputC[3] = inputC[3]*10;
    }
    
    //Add all applicable array elements up
    double input = 0;
    int count2 = 0;
    Serial.println(count2);
    while(count2 < count)
    {
      double inputD = 0;
      inputD = atof(&inputC[count2]);
      input = input + inputD;
      count2++;
    }
    
    
    Serial.println(count); 
    Serial.println(count2);
    Serial.println(inputC);
    Serial.println(input);
    
    //Formula to covert input in desired Hz
    time = (1000.00 / (2 * input));
    
    Serial.println(time);
    /*
    //Display current blink rate in serial monitor
    Serial.println(input);
    Serial.println("Hz");
    Serial.println(time); */
}

Moderator edit: CODE TAGS

Before we tackle the specific problem, I want to point out that the Arduino IDE actually is C++, not C.

Next, your code is easier to read if you edit the post, select it, and hit the "#" button above the input box to put it all into [ code ] tags.

You might want to look at this:

http://www.gammon.com.au/serial

That shows how you can read in text (eg. multiple digits) until you hit a delimiter (eg. a newline) and then process it.

Another thing to remember is that serial comms are slow, but loop() gets executed many, many times per second. About the only thing saving you from confusion at the moment is the fact that you don't allow flash rates above 500Hz.

Please use code tags. If you go back to your post, click on "modify", highlight the code, then click on the # icon, then click on "save".

AWOL: Another thing to remember is that serial comms are slow, but loop() gets executed many, many times per second. About the only thing saving you from confusion at the moment is the fact that you don't allow flash rates above 500Hz.

Please use code tags. If you go back to your post, click on "modify", highlight the code, then click on the # icon, then click on "save".

So what your saying is that when I input a number such as '15', the 1 and the 5 are being read in separate passes through the loop function? Is there a proper way to fix this? Is a newline '\n' character follow all serial input? This way I could just write the code to wait for the newline character before exiting the loop.

Why not try to see what happens (after reposting your code as requested above please). Just try printing each character out as you receive it so see what you are getting and when.

This works for me as a quick lashup:

byte converthexdigit(char c1)
{
  byte retval;
  if (c1 >= '0' && c1 <= '9') retval = (c1 - 48 );
  if (c1 >= 'A' && c1 <= 'F') retval = (c1 - 65 + 10 );       
  if (c1 >= 'a' && c1 <= 'f') retval = (c1 - 97 + 10 );
  return retval;
}
// at top of loop
  if (Serial.available()) {
    char c = Serial.read();

// intervening stuff skipped

 case 'L':
        {
          while(Serial.available() < 2) { // expecting 2 characters
            ; 
          }
          int k = converthexdigit(Serial.read()) * 16 + converthexdigit(Serial.read());
          print_hex_byte_leading_zero(k);
          Serial.println(_ccvar.get_cmdname_by_ele(k));   
        }
        break;

That will pause the loop until the 2 characters are read though, which may matter to you.

matt1212: So what your saying is that when I input a number such as '15', the 1 and the 5 are being read in separate passes through the loop function?

Yes

matt1212: Is there a proper way to fix this?

I think you meant, "handle" and not "fix." This behavior isn't broken.

matt1212: Is a newline '\n' character follow all serial input? This way I could just write the code to wait for the newline character before exiting the loop.

That's one of the best options. Create a character array to store characters as they come in. Keep adding characters to the array until some delimiter comes along. Just make sure your serial program sends what you expect. e.g. the Serial Monitor in the Arduino IDE has a drop down that selects what the "end of line" looks like. (Default is none.)

matt1212: Is there a proper way to fix this?

To handle this? Apart from what I showed here? ...

http://www.gammon.com.au/serial

That describes two methods:

  • Buffering up incoming input until (say) a newline. Then process it.
  • Use a state machine to handle the input as it arrives. So if you get "15" you initially put "1" into a variable. Then when you get the "5" you multiply the "1" by 10 and add in the "5". And so on.

Here’s a (working) sample of Nick’s character at a time approach. The getb() function gets a single character from the Serial interface, and the get_time() function builds a binary value…

/*----------------------------------------------------------------------------*/
/* Get a single character from the host                                       */
/*----------------------------------------------------------------------------*/
static int getb(void)
{  while (!(Serial.available() > 0));  /* Wait for data to arrive             */
   return Serial.read();               /* Return next character               */
}                                      /*  end: getb()                        */
/*----------------------------------------------------------------------------*/
/* Get current date/time and set the system reset time                        */
/*----------------------------------------------------------------------------*/
void get_time(void)
{  time_t t;                           /* Current system time                 */
   int c;                              /* Input character                     */
   do                                  /* Until end of message                */
   {  Serial.println("?T");            /* Send time query to host via USB     */
      t = 0;                           /* Initialize time value               */
      while ('T' != getb()) ;          /* Watch for start of time response    */
      while (('0' <= (c = getb())) && (c <= '9')) /* Is this a decimal digit? */
      {  t = 10 * t + (c & 0x0F);      /* If so, build time value             */
      }                                /*  end: building time value           */
   }  while (c != '!');                /* Until a valid time is received      */
   set_time(t * 1000000);              /* Calculate and save reset time       */
}                                      /*  end: set_time()                    */

Thank you everyone for your input. I’ll attempt to apply the suggested modifications later on today and report back