Go Down

Topic: Serial Arduino (Read 1 time) previous topic - next topic

Xalos

Hello people...I am a newbie to arduino and I was just trying out the serial communication technique. The problem is that, the arduino accepts data as characters, not in numbers. So I couldn't send in a number like '15' to it, as it saw it as 1 followed by 5, i.e; two characters. I use Ubuntu. Arduino Deumilanove. What do I do about it i.e; how do i send two digit number?

Anachrocomputer

You'll have to accept characters into an array, and then stop when you get a delimiter of some sort (e.g. a return). Use 'atoi' to get the integer value of that character array:

Code: [Select]
int ival;
ival = atoi (str);

Xalos

Code: [Select]
void setup()
{
  Serial.begin(9600);
  pinMode(9,OUTPUT);
}

void loop()
{
  int i=0;
  int in;
  int input=0;
  if(Serial.available())
  {
      int j=Serial.read();
      while(j!=10)  //ASCII for Enter
      {   
      int in=j-'0';
      input+=in*pow(10,i);
      i++;
      j=Serial.read();  //Reading another character
      }
           
  }
 
  analogWrite(9,input);
  delay(3000);
  analogWrite(9,0);

}


This is supposed to change LED brightness according to the input I give. The LED seems to be On for as much as a millisecond(perhaps shorter?) and then switches off. Logically, doesn't this have to work?

Xalos

Ok, actually the LED doesn't switch on at all. Turns out it was the reflection from the Tx LED.   :smiley-slim:

Graynomad

#4
Aug 05, 2011, 06:29 pm Last Edit: Aug 05, 2011, 06:41 pm by Graynomad Reason: 1
Quote
So I couldn't send in a number like '15' to it


You can send binary if you like

Serial.print (15, BYTE);

will send a single byte with a value of 15.

Apart from that your variables are local to loop() and will be initialized every time loop is called and there are other problems with the basic placement of the LED code, for example it's writing to the LED pin every time loop runs.

Try

Code: [Select]
void loop()
{
  static int input=0;
 
  if(Serial.available())
  {
      int j=Serial.read();
      if(j!=10)  //ASCII for Enter
{   
  input *= 10;
  input += j-'0';
} else {
  analogWrite(9,input);
  delay(3000);
  analogWrite(9,0);
  input = 0;
}
  }
}


______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

Xalos

Solved! Thank you for the tipoff Anachrocomputer! Now I should type it like '015' instead if just '15' coz i need to include 3 digit ones as well. I could edit this further to include that as well, but, what the heck, it works!  :)

Code: [Select]
void loop()
{
  int i=2,input=0;
  int j[3]={0};
 
  while(Serial.available())
  {
      j[i]=Serial.read()-'0';
      input+=j[i]*pow(10,i);
      i--;
      delay(5);
  }
while(Serial.available()==0)
analogWrite(9,input);
}
 

PaulS

Code: [Select]
      input+=in*pow(10,i);
The pow() function takes two arguments, both floats, and returns a float. The float may not be exactly what you expect.

Since what you want to do is multiply input by 10 and add in, why not just do that.

If the string being received is 12846, for instance, input is initially 0.

When the 1 is received, input gets multiplied by 10 (still 0) and 1 gets added, so input is 1.
When the 2 is received, input gets multiplied by 10 (now 10) and 2 gets added, so input is 12.
When the 8 is received, input gets multiplied by 10 (now 120) and 8 gets added, so input is 128.
When the 4 is received, input gets multiplied by 10 (now 1280) and 4 gets added, so input is 1284.
When the 6 is received, input gets multiplied by 10 (now 12840) and 6 gets added, so input is 12846.

No pow() calls are needed.

Xalos

Quote
Apart from that your variables are local to loop() and will be initialized every time loop is called


Yes, I actually want to them to be reset everytime loop is called. But, yeah I can set that right, that's not much of a problem is it?

Quote
it's writing to the LED pin every time loop runs.

I've fixed that in my new code. :)


Xalos

Modified code according to advice given by PaulS and Greynomad! Thanks!

Code: [Select]

int input=0,i=2, j[3]={0};

void setup()
{
  Serial.begin(9600);
  pinMode(9,OUTPUT);
}

void loop()
{
  i=2;
  input=0;
  j[0]=j[1]=j[2]=0;
 
  while(Serial.available())
  {
      j[i]=Serial.read()-'0';
      input=input*10;
      input+=j[i];
      i--;
      delay(5);
  }
 
while(Serial.available()==0)
analogWrite(9,input);
}
 

Graynomad

You don't need j or i if you have a delimiter (the LF), and I don't see how that works anyway but if it does it does :)

_____
Rob
Rob Gray aka the GRAYnomad www.robgray.com

PaulS

Quote
I don't see how that works anyway

If a 3 digit value, 125 is sent, the values that are stored in the array will be 5, 2, and 1 (in
  • , [1], and [2]). The variable input will be set to 0, then 10*0 (0), then 0+1 (1), then 10*1 (10), then 10+2 (12), then 10*12 (120), and finally 120+5 (125).

    There is, of course, no need to store the values in an array, especially backwards. Doing so limits the size of the number, as a string, that can be sent, to exactly 3 digits. The approach I defined allows for sending 1 digit, 3 digit, or 5 digit numbers (up to the limit if an int). Changing the type of input to long will allow for reading much larger number from the serial port.

    There are some flaws in the code. It will happily try to process "ten" sent to the serial monitor, though the resulting value in input won't be anywhere near correct.

    It also operates on the assumption that the 3 values will be received with 10 milliseconds, and takes all 10 milliseconds to read the values, even if they arrive much faster than that.

    Finally, it assumes that only three values will be received. One could send 128765boo to the serial port, and that code would read all of the data, and try to process it.

    Writing the same value to the PWM pin on every pass through loop doesn't hurt anything, but it isn't necessary, either. The check for serial data before writing to the PWM pin is silly, since the previous while loop did not terminate until there was no serial data available.

Xalos

Quote
It will happily try to process "ten" sent to the serial monitor, though the resulting value in input won't be anywhere near correct.
Uh...i've sent 10,100 and it worked correctly.

Quote
There is, of course, no need to store the values in an array, especially backwards. Doing so limits the size of the number, as a string, that can be sent, to exactly 3 digits.

Well, they are actually stored forwards correctly. And I want my number to maximum 3 digits, in fact 255 is the max. In fact I also could have used constrain function to enforce that, but thats a bit trivial.

Quote
It also operates on the assumption that the 3 values will be received with 10 milliseconds, and takes all 10 milliseconds to read the values, even if they arrive much faster than that.

Well, any faster, or even that wouldn't make a difference to human eye, would it? I'll see if delay(1) works in any case. It should, perhaps.

Quote
One could send 128765boo to the serial port, and that code would read all of the data, and try to process it.

I'm pretty sure that a three digit array wont accept any more elements, and they'll simply be ignored, as in earlier versions of C.

Quote
Writing the same value to the PWM pin on every pass through loop doesn't hurt anything, but it isn't necessary, either. The check for serial data before writing to the PWM pin is silly, since the previous while loop did not terminate until there was no serial data available.

Yeah, thats right. I'd have to include another condition for while(), then.

Graynomad

Quote
I'm pretty sure that a three digit array wont accept any more elements, and they'll simply be ignored, as in earlier versions of C.

Only if that's how you write the code, C will happily trash the entire RAM no matter what size the array is. As it is if you get > 3 chars you start trashing memory.

But as we've said you don't need the array in the first place.

Using that delay() makes the code dependent on the bit rate of the serial line. Not good practice. If for some reason the characters come at a different rate or with some time between them you exit loop(). Then when you come back you reset i to 2 and start again, despite the fact that you may be half way through receiving your numbers.

______
Rob


Rob Gray aka the GRAYnomad www.robgray.com

PaulS

Quote
Uh...i've sent 10,100 and it worked correctly.

Might just be me, but I see a big difference between "10" and "ten".

Quote
Well, they are actually stored forwards correctly.

If you send "125", the first value received ('1') is stored in array position 2, the next value received ('2') is stored in array position 1, and the next value received ('5') is stored in array position 0. If that meets your definition of being stored "forwards" correctly, I'm happy for you.

Quote
I'm pretty sure that a three digit array wont accept any more elements, and they'll simply be ignored, as in earlier versions of C.

I don't live in the same fantasy world you inhabit, apparently.

Quote
Yeah, thats right. I'd have to include another condition for while(), then.

Why? If you are going to write to the pin on every pass through loop, why not just do that?



Xalos

Quote

Using that delay() makes the code dependent on the bit rate of the serial line. Not good practice.


I agree, but in fact it was the delay that made the whole thing work. If I sent '125' , it would otherwise output '1' , '2' , '5' one after the other so fast that you couldn't see anything but the resulting '5' output. It was too fast to receive the next character. Hence the delay.

Quote
Might just be me, but I see a big difference between "10" and "ten".
Oh. u meant 'ten'. :P

Quote
If that meets your definition of being stored "forwards" correctly, I'm happy for you.
Oh yeah, i missed that. :o

Quote
Why? If you are going to write to the pin on every pass through loop, why not just do that?

Not really. I'd want to reset the value of 'input' every time i send in a new number, which is on every pass to the loop. So i'd have to include a second loop, in this case 'while' , so as to compute 'input'.


Go Up