Rs232 string int combinations

Hi guys, am quite new here, but i have “some” basics…
I got this task to make, am seeking for your help.

arduino send cmd over rs232, example 01 01
arduino recive msg back, example: 12 12 00 00 05 00 00 00 06 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 12 12
loop send command every 10 seconds to get new numbers

The goal is after receive info back to do multiple operations as;
print on serial monitor

print byte 1-4 as Info: 12 12
print byte 6-10 as Digit1: 000005 - execute led blink 5 times
print byte 10-14 as Digit2: 000006 - execute led blink 6 times
print byte 14-20 as Digit3: 000010 - execute led blink 10 times

As poll goes every 10 seconds, increment digit1 will be example 10 so then will
have to remember old value 000005, compare to current 000010 and turn led for 5 times only…
Think would be wise to hold value in eeprom for each digit1,digit2,digit3 just in case power lose.
For testing am using serial monitor in arduino.

This is my code so far trying with single byte/digit1

String inputString = "";
boolean stringComplete = false;
const int ledPin = 13;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  inputString.reserve(200);
}

void loop() {
  if (stringComplete) {
    inputString = "";
    stringComplete = false;
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = (char)Serial.read();
    inputString += inChar;

    if (inChar == '\n') {
    stringComplete = true;
    String id = inputString;

    int Int0 = id.charAt(0) - '0';
    int Int1 = id.charAt(1) - '0';
    int Int2 = id.charAt(2) - '0';
    int Int3 = id.charAt(3) - '0';
    int Int4 = id.charAt(4) - '0';

    int Int5 = id.charAt(6) - '0';
    int Int6 = id.charAt(7) - '0';
    int Int7 = id.charAt(8) - '0';
    int Int8 = id.charAt(9) - '0';
    int Int9 = id.charAt(10) - '0';

    Int0 += Int1, Int2, Int3;

    Serial.println(Int0);
 //   led(ledPin,30,Int0);

  }
 } 
}



void led (int ledPin, int stayon, int times)
    {
    for (int x=0; x<times; x++) {
        digitalWrite(ledPin, HIGH);
        delay(stayon);
        digitalWrite(ledPin, LOW);
        delay(100);
    }
}

i’ve been using some examples i found on forum :slight_smile:

You use a String object, but it can also be done with a simple character array. I think in this case it is easier with a character array. I would receive everything, also the spaces in between, and afterward check all the data.

Do you know the exact data that is received ?
No start byte ?
Are they hex numbers or BCD numbers ?
Normal spaces in between ?
Always the same number of bytes ?
No space after the last digit ?
Only a '\n' at the end and no '\r' ?
The example you give does not match your description of the bit numbers.

Which Arduino board do you use ?
Are you using SoftwareSerial ?

Peter currently am trying putting into array then printing [digit] which i need but not going well.

I’ll try be more specific.
The msg beeing reciving is this type: 1F 1F 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
where:
bytes 7-10 is digit1
bytes 11-14 is digit2
bytes 15-18 is digit3

Msg starts always the same 1F 1F.

No start byte ?

  • starts with 1F 1F
    Are they hex numbers or BCD numbers ?
    -decimals?
    Normal spaces in between ?
  • yes
    Always the same number of bytes ?
  • yes
    No space after the last digit ?
  • no
    Only a ‘\n’ at the end and no ‘\r’ ?
  • yes only \n

As for now its just arduino uno, soft 1.6.1.
Latter i’ll make pcb with max232 to connect to pc rs232 and then send msg from pc rather then from arduino serial monitor.

thanks for reply

When not using a String object, I think the Serial.readBytesUntil() is the most simple.
It has a timeout of default 1 second. Is it okay that your sketch is waiting for a second when the serial data is going wrong ?

Those are about 90 bytes ?

I would like to know how the number is encoded in the string.
Would 105 be like this : "01 05" ?
And would 99 be : "00 00 99" ?
I have serious doubts about that.
I don't know what to do with the new byte descrition. I don't even know if you start with index zero or one.
Could you write the data on a piece of paper, and make a drawing to show which digits form which numbers ?
You can make a photo of that and attach it to a post (click on the REPLY button and then there are extra options to attach a photo (on the left side below the text input field)).

char buffer[100];
...

  // Clear receive buffer before sending command.
  while (Serial.available() > 0)
    Serial.read();

  // Send command
  Serial.println("01 01");

  // read data with timeout
  Serial.readBytesUntil( '\n', buffer, sizeof(buffer));

  // A small check for valid start bytes.
  if( strncmp( buffer, "1F 1F ", 6) == 0)
  {
     // Get the data from the string
     int ledCount1 = getTheNumber(7);      // 7 is wrong
     int ledCount2 = getTheNumber(11);    // 11 is wrong
     int ledCount3 = getTheNumber(15);    // 15 is wrong
  }

...
// The 'index' is the index in 'buffer'.
// it is the start byte to retrieve the number from the data string.
int getTheNumber( int index)
{
  int i;

  i  = (buffer[index+0] - '0') * 100000;      // this is wrong
  i += (buffer[index+1] - '0') * 10000;    // this is wrong
  i += (buffer[index+3] - '0') * 1000;    // this is wrong
  i += (buffer[index+4] - '0') * 100;    // this is wrong
  i += (buffer[index+6] - '0') * 10;    // this is wrong
  i += (buffer[index+7] - '0') * 1;    // this is wrong
  return (i);
}

Peter, numbers inside strings looks like this for example...

digit1 digit2 digit3
1F 1F XX XX 00 00 01 00 00 20 00 50 40 XX XX XX XX XX...etc

Where 00 00 01 is integer 1
Where 00 00 02 is integer 2
Where 00 50 40 is integer 5040

Am looking at your code, trying to make progress.
thanks

Thanks ! Now I see it.
Could the first two digits be used ? for example 99 99 99. Then a long should be used instead of a normal integer.

The indexes are 12, 21, 30. Those are the starting positions for the numbers. The index of an array in the 'c' language starts at zero.

ledCount1 = GetTheNumber[12];
ledCount2 = GetTheNumber[21];
ledCount3 = GetTheNumber[30];

The function GetTheNumber() could accept a pointer to a string. That is a more common way to do this. But it is more important that you understand it.

Yes Peter, that is correct. When it starts counting it will go up … up… 99 99 99 (999999)
I tried to find this function, but no info? Do you have link maybe or your thinking writing own func() to get it…

The function name “GetTheNumber()” is something I made up.

Let’s use unsigned long to be able to go up to 999999.

The numbers 100, 1000, 10000 and so on are the so called weight of that digit.
It is possible to force the compiler to see those number as unsigned long by adding “UL”, so they will become 100UL, 1000UL, 10000UL and so on.

The variabled ‘LedCount1’ should be : unsigned long ledCount1
And the “GetTheNumber” function should use a unsigned long instead of “int i” and return an unsigned long of course.

Could you make a start with a sketch with these pieces of information ?

I see, i make mod, but... sending 1F 1F 11 11 11 11 11 11 11 11 11 11 ...
gets respond:

4930
32341
-19961

and its looping in monitor ...

char buffer[100];

unsigned long ledCount1;
unsigned long ledCount2;
unsigned long ledCount3;

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

void loop() {
  Serial.readBytesUntil( '\n', buffer, sizeof(buffer));
  if( strncmp( buffer, "1F 1F ", 6) == 0)
  {
      ledCount1 = getTheNumber(7);      // 7 is wrong
//      ledCount2 = getTheNumber(11);    // 11 is wrong
//      ledCount3 = getTheNumber(15);    // 15 is wrong
  }
}

int getTheNumber( unsigned long index)
{
  int i;
  i  = (buffer[index+0] - '0') * 100000;      // this is wrong
  i += (buffer[index+1] - '0') * 10000;    // this is wrong
  i += (buffer[index+3] - '0') * 1000;    // this is wrong
  i += (buffer[index+4] - '0') * 100;    // this is wrong
  i += (buffer[index+6] - '0') * 10;    // this is wrong
  i += (buffer[index+7] - '0') * 1;    // this is wrong
  return (i);
  Serial.println(i);
}

Good thing you PM me. I use the "Update Topics" in the upper-right of this forum, but I didn't see your new post.

The indexes are 12, 21, 30 and the GetTheNumber() should return a unsigned long. The parameter 'index' can stay an integer.
I fixed it for you:

char buffer[100];

unsigned long ledCount1;
unsigned long ledCount2;
unsigned long ledCount3;

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

void loop() {
  // readBytesUntil returns the number of characters received. 0 means nothing received.
  int n = Serial.readBytesUntil( '\n', buffer, sizeof(buffer));

  // For debugging
  // strcpy( buffer, "1F 1F 00 00 00 00 01 00 00 20 00 50 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00");

  // Do a few small checks.
  if( strncmp( buffer, "1F 1F ", 6) == 0 && n > 50 && buffer[11] == ' ' && buffer[20] == ' ' && buffer[20] == ' ')
  {
    ledCount1 = getTheNumber(12);
    ledCount2 = getTheNumber(21);
    ledCount3 = getTheNumber(30);
    
    Serial.print(ledCount1);
    Serial.print(", ");
    Serial.print(ledCount2);
    Serial.print(", ");
    Serial.println(ledCount3);
  }
}

unsigned long getTheNumber( int index)
{
  // The 100, 1000, 10000 are the so called "weight" of that digit.
  unsigned long ul;
  ul  = (buffer[index+0] - '0') * 100000UL;  // UL means "unsigned long"
  ul += (buffer[index+1] - '0') * 10000UL;
  ul += (buffer[index+3] - '0') * 1000UL;
  ul += (buffer[index+4] - '0') * 100UL;
  ul += (buffer[index+6] - '0') * 10UL;
  ul += (buffer[index+7] - '0') * 1UL;
  return( ul);
}

And I also fixed a bug: I forgot to check the return value of Serial.readBytesUntil().
We are getting closer to good results :stuck_out_tongue:

I used this (readable ascii) test string: "1F 1F 00 00 00 00 01 00 00 20 00 50 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00".
First I wrote it in the sketch, then I copied it in the serial monitor.

A “if ( Serial.available ( ) > 0 )” should be added before the Serial.readBytesUntil().