doh! Serial.read() question

This is a a really basic question @ using Serial.read(). I've been digging around and trying different things but am stumped.

I am used to sending data out of the Arduino - and sending in simple control chars but now I need to send in some large numbers. So - if I want to send in 15000 - and have Arduino use that as 15000 - how the heck do I do that?

Using the serial monitor control panel 'send' to send the values - it seems to be sending ascii (1 = 49) - so I just can't do a siimple:

   while (Serial.available() > 0)
      val = Serial.read();
      total = total +  val;
  }

I've tried casting to int() along with other stuff- no luck. Can't believe I got snagged by this (rather than what I expected to get snagged on...)

tx,

--Roy

You've got to build it one digit at a time. Here's some code that assumes you get a number followed by a CR.

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1197287770/1#1

-j

thanks! I sorted out the ‘isdigit’ and ‘crlf’ stuff by reading other posts but I can’t get it working (using ‘send’ in the serial monitor window). Is there something I am doing wrong?

#define isdigit(X) (((X) >= '0') && ((X) <= '9'))

char crlf[] = "\r\n"; 

int LED = 13;
long total = 0;

void setup(){

  pinMode(LED, OUTPUT);
  Serial.begin(115200);
  Serial.print("!");
  Serial.println("*");
}


void loop(){
  if (Serial.available() > 0) {
    digitalWrite(LED, HIGH);
    int n;
    n = read_int();
      Serial.print("n ");
      Serial.println(n);
      
    if (n != -1){
      total = total + n;
      Serial.print("total ");
      Serial.println(total);
    }
  }
  delay(500);
  digitalWrite(LED, LOW);
}

int read_int()
{
  byte c;
  int i;

  i = 0L;
  while (1)
  {
    while (!Serial.available())
    {
      ;
    }

    c = Serial.read();
    //  Serial.print(c, BYTE);

    if (c == '\r')
    {
      //   Serial.print(crlf);
      return i;
    }
    if (isdigit(c))
    {
      i = i * 10 + c - '0';
    }
    else
    {
      Serial.print("\r\nERROR: \"");
      Serial.print(c, BYTE);
      Serial.print("\" is not a digit\r\n");
      return -1;
    }
  }
}

I don't use serial monitor much (I'm an old phart, so I immediately fall back to kermit for terminal I/O, since that's what I learned on my C64), plus I designed this as a configuration screen for a device that would be configured by any random RS232 terminal (anybody got a vt100 lying around?). I don't know if Arduino's serial monitor sends a CR or an LF, and I don't have a way of checking here at work.

You may try checking for a newline instead of carriage return: change the '\r' ot '\n' in this line: if (c == '\r')

What are the symptoms: does it hang, generate an error, etc?

-j

Hi-

I’ve been poking at it all day and it’s like it almost is working… (I’ve changed some stuff which is probably not good - but I am flying blind). It is working for some numbers - and not for others- hard to see a pattern. I’m not sending any line feeds or return chars - just ‘x’ - then the number, digit by digit, and then the stop char I am using ‘*’

Thanks for any tips!

–Roy

#define isdigit(X) (((X) >= '0') && ((X) <= '9'))

char crlf[] = "\r\n"; 

int LED = 13;


void setup(){

  pinMode(LED, OUTPUT);
  Serial.begin(115200);
  Serial.print("!");
  Serial.println("*");
}


void loop(){
  if (Serial.available() > 0) {
    digitalWrite(LED, HIGH);
    int val;
    long num;
    val = Serial.read();
    if (val == 'x'){
      num = read_int();
      Serial.print(num);
      Serial.print('*');
    }
    delay(50);
    digitalWrite(LED, LOW);
  }
}

int read_int()
{
  byte c;
  int i;

  i = 0L;
  while (1)
  {
  
 //   while (!Serial.available())
  //   {
  //   ;
  //   }
    
    if (Serial.available() > 0){
      c = Serial.read();
      if (c == '*')
      {
        return i;
      }
      if (isdigit(c))
      {
        i = i * 10 + c - '0';
      }
      else
      {
      //  return -1;
      }
    }
  }
}

I sure don't see anything wrong.

I see you set the baud rate to 115k. Does the arduino serial monitor work at that speed?

looks like your code will skip characters until it gets an x, build an integer out of the following characters until a * is read, skipping all non-digit characters.

Haven't had a chance to run your code, but it looks OK to me...

-j

Ooops, one thing:read_int() resturns an int, but you're assigning it to num, which is a long. Make num an int and see what happens.

If num is an int, keep the values less than 32768, else bad things will happen (i.e. integer overflow and garbage results).

-j

If num is an int, keep the values less than 32768, else bad things will happen (i.e. integer overflow and garbage results).

thanks j -

yeah, I've been discovering all the bad things that can happen :-/ yikes (and initially having no idea why, double yikes). The baud rate was another gotcha - I'd seen some sketches using higher (than 9600) baud rates so I was trying it - and was getting erratic results - but thought it was the routines, and didn't think of the connection rate until I traced all the values sent and received - and saw missed bytes.

Ended up using the routine below. It's working up to 12 places. Thanks for you help and follow up patience!

--Roy

(for completeness, in the event someone else stumbles upon this - to receive a large number on the Arduino side the routine below expects the number to be broken down into 4 bytes using this algorithm from Geoff Smith of physicalbits.com, followed by a '*' char to indicate end of message.

byte1 = integer(number/16777216)
number=number-(byte116777216)
byte2 = integer(number/65536)
number = number-(byte2
65536)
byte3 = integer(number/256)
byte4 = number-(number*256)

data = [byte1,byte2,byte3,byte4]
-- to reassemble
number = (byte116777216)+(byte265536)+(byte3*256)+byte4

. .

long getInput(){
  long total = 0;
  int byteCount = 1;
  long val;
 
  while(1){
    while (Serial.available() > 0) {
      val = Serial.read();
      if (val == '*'){
        return total;
      } 
      else {
        switch(byteCount){
        case 1:
          total = total + (val * 16777216);
          byteCount++;
          break;
        case 2:
          total = total + (val * 65536);
          byteCount++;
          break;
        case 3:
          total = total + (val * 256);
          byteCount++;
          break;
        case 4:
          total = total + val;
          break;
        }
      }
    }
  }
}

Glad you got it working. Hope I didn’t miss something in the original question, as that last solution looks like you’re reading 32 bit binary values instead of printable ASCII decimal representations. The solutions are quire different. |:

You could also do the same thing with some bit shifting, but I’d bet the compiler boils down the multiplies to the same thing.

-j

I'm sending in values between 0-30000 but couldn't get the ascii decode method to work, so I break the number down into 4 bytes and rebuild it on the arduino side. Maybe not so efficient but I just needed to keep the project moving.

--Roy