Arduino Forum

Using Arduino => Programming Questions => Topic started by: Raavgo on Sep 30, 2013, 03:54 pm

Title: Problem with Serial.read and bigger numbers
Post by: Raavgo on Sep 30, 2013, 03:54 pm
Hey guys,

I've got a problem with my code...
The code should read a frequency and generate a square-wave signal but I can't read numbers bigger than 9.

Code: [Select]

int Ausgangspin = 13; 
double Frequenz;

void setup(){
  pinMode(Ausgangspin, OUTPUT);
  Serial.begin(9600);
  Serial.println("Bitte angeben wieviel Hz ausgegeben werden sollen:");

}

void loop(){
  Frequenz = Eingabe();                                                  //Eingabe-Funktion, gibt die Frequenz zurück.
  Serial.print("Es wird gesetzt: ");
  Serial.print(Frequenz,DEC);
  Serial.println("Hz!");
  //tone(Ausgangspin, Frequenz);                                  // Ausgabe der frequenz ohne abhängigkeit der Zeit
}

int Eingabe(){
int  i = 0;                                                            //Ziffern-Zähler rücksetzen
unsigned char Data[6];                                          // String zum einlesen der Zahlen

  do
  {
    if (Serial.available())                                              // Wenn Daten verfügbar 5 Zeichen in Data schreiben
    {
      Data[i] = Serial.read() - '0';                                  //umwandlung zu DEC
      i++;
    }
  }
  while (i<5);
 
  return atof(Data);                                                    //return Zeichenkette -> Zahl (DEC)
}


but I already tried something else (Well it didn't work either)
Code: [Select]

int  i = 0, f = 0; //Ziffern-Zähler rücksetzen
char Data[6];                                          // String zum einlesen der Zahlen

if (Serial.available()>0)
{
    for (i=0 ; Serial.available() >0&& i<5 ; i++)
    {
    Data[i] = Serial.read();
   
    }
    Serial.flush();
   
    Serial.println(atof(Data));
   
}


If I want to get a numeric output of the number 50 I get it as 5.00 and 0.00

thanks for any kind of help
Raavgo
Title: Re: Problem with Serial.read and bigger numbers
Post by: AWOL on Sep 30, 2013, 04:02 pm
Code: [Select]
for (i=0 ; Serial.available() >0&& i<5 ; i++)
    {
    Data[i] = Serial.read();
   
    }

When you get to the start of this for loop, you will probably have just one character available to read.
After one iteration of the for loop, you will probably have no more characters available to read.
How many times will the loop iterate?
Title: Re: Problem with Serial.read and bigger numbers
Post by: PaulS on Sep 30, 2013, 04:05 pm
A clue as to what is sending the data would be useful.
Title: Re: Problem with Serial.read and bigger numbers
Post by: robtillaart on Sep 30, 2013, 09:24 pm
considered this variation?
Code: [Select]

if (Serial.available() >= 5)  // <<<<<<<<
{
    for (i = 0 ; i < 5; i++)
    {
       Data[i] = Serial.read();
    }
    Serial.flush();
    Serial.println(atof(Data));
}
Title: Re: Problem with Serial.read and bigger numbers
Post by: PaulS on Sep 30, 2013, 09:26 pm
Quote
considered this variation?

I'd be more likely to consider that if the useless Serial.flush() was removed.
Title: Re: Problem with Serial.read and bigger numbers
Post by: Raavgo on Oct 07, 2013, 02:01 pm
My Problem is I want to read numbers from the Serial Monitor.
The range should be from 1 to 99999 but I'm messing up somehow.,
I'm able to only read 5 digit numbers so if I want to write 10 I'd have to write 00010.

thank you
for any kind of help
Raavgo
Title: Re: Problem with Serial.read and bigger numbers
Post by: PaulS on Oct 07, 2013, 02:06 pm
Quote
I'm able to only read 5 digit numbers so if I want to write 10 I'd have to write 00010.

That wouldn't be the case if you used end of packet markers. The Serial Monitor can even add them for you.
Title: Re: Problem with Serial.read and bigger numbers
Post by: AWOL on Oct 07, 2013, 02:07 pm
Quote
I'm able to only read 5 digit numbers so if I want to write 10 I'd have to write 00010.

There are a couple of things to bear in mind here:
1) An Arduino "int" holds at most only five decimal digits. To hold more, you need a "long" or unsigned long". Or even a "long long"
2) Some methods of converting ASCII to "int" will consider "00010" to have the decimal value 8 - a leading '0' denotes an octal value.
Title: Re: Problem with Serial.read and bigger numbers
Post by: robtillaart on Oct 07, 2013, 03:22 pm

Quote
I'm able to only read 5 digit numbers so if I want to write 10 I'd have to write 00010.

There are a couple of things to bear in mind here:
1) An Arduino "int" holds at most only five decimal digits. To hold more, you need a "long" or unsigned long". Or even a "long long"
2) Some methods of converting ASCII to "int" will consider "00010" to have the decimal value 8 - a leading '0' denotes an octal value.

an int can also hold a - sign  ==> in theory in 50% of the cases (in practice probably less)
an unsigned int will hold 5
Title: Re: Problem with Serial.read and bigger numbers
Post by: AWOL on Oct 07, 2013, 03:37 pm
Signed or unsigned, a sixteen bit "int" will only ever hold five decimal digits.
Title: Re: Problem with Serial.read and bigger numbers
Post by: Raavgo on Oct 07, 2013, 03:47 pm

Quote
I'm able to only read 5 digit numbers so if I want to write 10 I'd have to write 00010.

That wouldn't be the case if you used end of packet markers. The Serial Monitor can even add them for you.


Could you give me a example how to read the number 50000 out of a serial Monitor and store it in a int or unsigned int?
Title: Re: Problem with Serial.read and bigger numbers
Post by: AWOL on Oct 07, 2013, 04:17 pm
There are plenty of examples out there, but one hint would be to set the line-ending in the serial monitor to "Newline", instead of the default "No line ending"
Title: Re: Problem with Serial.read and bigger numbers
Post by: PaulS on Oct 07, 2013, 04:34 pm
This code uses start and end of packet markers:
Code: [Select]

#define SOP '<'
#define EOP '>'

bool started = false;
bool ended = false;

char inData[80];
byte index;

void setup()
{
  Serial.begin(57600);
  // Other stuff...
}

void loop()
{
 // Read all serial data available, as fast as possible
 while(Serial.available() > 0)
 {
   char inChar = Serial.read();
   if(inChar == SOP)
   {
      index = 0;
      inData[index] = '\0';
      started = true;
      ended = false;
   }
   else if(inChar == EOP)
   {
      ended = true;
      break;
   }
   else
   {
     if(index < 79)
     {
       inData[index] = inChar;
       index++;
       inData[index] = '\0';
     }
   }
 }

 // We are here either because all pending serial
 // data has been read OR because an end of
 // packet marker arrived. Which is it?
 if(started && ended)
 {
   // The end of packet marker arrived. Process the packet

   // Reset for the next packet
   started = false;
   ended = false;
   index = 0;
   inData[index] = '\0';
 }
}

Where it says "Process the packet"., you do whatever you need to do with the serial data, stored in inData. You could remove SOP and the started flag (and related code) if you only want to use an end-of-packet marker.
Title: Re: Problem with Serial.read and bigger numbers
Post by: odometer on Oct 07, 2013, 04:51 pm
No need to muck about with character arrays or strings, or packet monitors for that matter.

You can simply multiply what you already have by 10 and then add the new digit.
But you have to start from 0.
So if I type the number 753:
It sees 7 and figures (0*10)+7 to get 7.
Then it sees 5 and figures (7*10)+5 to get 75.
Then is sees 3 and figures (75*10)+3 to get 753.

Here is my version of Eingabe(). Note its simplicity.
Please test it and tell me if it works correctly for you.

Code: [Select]
unsigned long Eingabe(){
 unsigned long value = 0;
 char char_in = -1;
 while (Serial.available())   // just keep reading characters
 {
   char_in = Serial.read();
   if (char_in != -1) {       // check to make sure there is a character
     if ((char_in >= '0') && (char_in <= '9')) {  // is it a digit?
       value *= 10;                               // multiply total by 10
       value += (char_in - '0');                  // add numeric value of new character
     }
     else return value;   // if the new character is not a digit, then we are done
   }
 }
 return 0; // in case Serial doesn't seem to be working  
}


(Oops! I just corrected a typo.)
Title: Re: Problem with Serial.read and bigger numbers
Post by: AWOL on Oct 07, 2013, 05:16 pm
Odometer: There's a problem with your code - it assumes all the data it needs to read from the serial line is already there.
Title: Re: Problem with Serial.read and bigger numbers
Post by: odometer on Oct 07, 2013, 06:30 pm
My mistake! Here's the corrected version:

Code: [Select]

unsigned long Eingabe(){
 unsigned long value = 0;
 char char_in = -1;
 while (true) {
    char_in = Serial.read();
   if (char_in != -1) {       // check to make sure there is a character
     if ((char_in >= '0') && (char_in <= '9')) {  // is it a digit?
       value *= 10;                               // multiply total by 10
       value += (char_in - '0');                  // add numeric value of new character
     }
     else return value;   // if the new character is not a digit, then we are done
   }
 }
}


NOTE: I fixed another stupid bug. And another.
I can't see shit with this new layout.
Title: Re: Problem with Serial.read and bigger numbers
Post by: PaulS on Oct 07, 2013, 07:46 pm
That still doesn't address the issue of serial data trickling in slowly. It still assumes that the entire packet is available to be read when the function is called.
Title: Re: Problem with Serial.read and bigger numbers
Post by: pbrouwer on Oct 07, 2013, 08:12 pm

That still doesn't address the issue of serial data trickling in slowly. It still assumes that the entire packet is available to be read when the function is called.


It's not really a problem if you can type way faster than the arduino can read.

Some terminal programs send stuff only after a linefeed is entered, it will mostly work in that case.
I agree checking for an end of transmission marker of some sorts is always a good idea, packing data in a verifiable format an even better one. It makes for a less challenging debugging experience, although it does take away the surprise factor.

Pieter
Title: Re: Problem with Serial.read and bigger numbers
Post by: PaulS on Oct 07, 2013, 08:20 pm
Quote
It's not really a problem if you can type way faster than the arduino can read.

It is a problem UNLESS you can get serial data in faster than the Arduino can read it. And, that is not possible.

Quote
Some terminal programs send stuff only after a linefeed is entered, it will mostly work in that case.

So? Data is still sent, and received, one character at a time. Sssslllloooowwwwllllyyyy. Way slower than the Arduino can read it.

Quote
although it does take away the surprise factor.

You say that like that's a bad thing.  8)
Title: Re: Problem with Serial.read and bigger numbers
Post by: pbrouwer on Oct 07, 2013, 09:19 pm
Quote
So? Data is still sent, and received, one character at a time. Sssslllloooowwwwllllyyyy. Way slower than the Arduino can read it.

Try it, you'll be surprised! (I guess there's some buffering going on, make sure the loop function has something to do or build in a delay)

Quote
You say that like that's a bad thing.  smiley-cool

It is. Writing / testing software that works as specified is really boring. Bugs create some excitement, especially if they come with bangs, flashes, sparks or smoke (or upset marketing people)!

Pieter
Title: Re: Problem with Serial.read and bigger numbers
Post by: lar3ry on Oct 07, 2013, 10:05 pm

Try it, you'll be surprised! (I guess there's some buffering going on, make sure the loop function has something to do or build in a delay)

I did. At 19200, with a fairly small amout of code in loop(), the Arduino Uno, at 16 MHz, goes through the check for serial data 54 times between two characters, and that's at 19200 baud. And of course it goes through twice that number at 9600 baud.

Sure, you can do a whole lot of things in the loop, including adding totally useless delays, but why would you bother, when it's so easy to actually do it right, guaranteeing you get all the data you need?

Going ahead with multiple reads when you see Serial.available() > 0 is just foolish.
Title: Re: Problem with Serial.read and bigger numbers
Post by: PaulS on Oct 08, 2013, 11:09 am
Quote
Bugs create some excitement

Personally, I think you misspelled stress/unwanted attention/grief. Either that or you are one weird dude.
Title: Re: Problem with Serial.read and bigger numbers
Post by: Raavgo on Oct 14, 2013, 03:18 pm
I read around quite a bit and figured out how to input 5 digits ( at least up to 32767, which is enough for my needs).

Code: [Select]

int frequenz;     
char Data[7];     
int i = 0;       

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

void loop()
{
  if( Serial.available())     
  {
    char ch = Serial.read();   //read serial
    if(i < 6 && isDigit(ch) )   //check if it is a digit
    {
      Data[i] = ch;                    //store it in data
      i++;
    }
    else
    {
      Data[i] = 0;                        //create end of string
      frequenz = atoi(Data);  //convert it to int
      i = 0;                                   
    }
  }
//do with the int whatever you want here.
// Max value = 32767



anyways thanks for the help
Raavgo
Title: Re: Problem with Serial.read and bigger numbers
Post by: pbrouwer on Nov 20, 2013, 07:42 pm

Quote
Bugs create some excitement

Personally, I think you misspelled stress/unwanted attention/grief. Either that or you are one weird dude.

You can add frustration/despair/fear and quite a few other things to that, excitement comes in many disguises. I might have been a bit sarcastic here (and that could be the result of tracking down too many bugs).
Point I was trying to make is that it is really easy to make flawed code that seems to work fine, but then all of a sudden doesn't. It can create really weird behavior. And really: bugs should cause some commotion. If they don't, it means there's too many of them, or no-one cares about them being there.