Read 32 ints Arduino Serial

How can I read 32 or 64 int, with a space in-between instantaneously?
I have been working on it for days, and with all of my attempts I have loses on byte 63 or after or before, the frequency of loses isn't periodic. I have tried multiple Serial.read() I have implemented Serial Basics recvWithStartEndMarkers 4 different times, and I cant have 100% of the data, that I need instantaneously

Come back when you have figured out the reality of serial data speed. Do you have any device that can send 32 or 64 integers instantaneously by serial?

the word "serial" says you wish is nonsense

I have managed to receive 138 byte data from the InputBox of Serial Monitor in 115 ms (almost instantaneously!).

Output:

138
12 23 34 45 56 67 78 89 91 92 93 94 95 96 97 98 89 87 
86 85 84 83 82 12 23 34 45 56 67 78 89 91 92 93 94 95 
96 97 98 89 87 86 85 84 83 82 

Amazing!
All I need is a data the CLOSEST to 100% accuracy, for every inputs which are happening really fast. And it is sometimes for the 2nd, the 9th or the 13th attempt that it will miss a space or a character

Are you and the original poster (OP} working together on the same project?

@raf1, your topic has been moved to a more suitable location on the forum. Installation and Troubleshooting is not for problems with (nor for advise on) your project :wink: See About the IDE 1.x category.

What is your sending device? Which board are you using?

Show your attempt(s).

While it has been suggested by @GolamMostafa , the OP should clarify whether he’s sending the ‘numbers’ as ASCII, or as binary in his messages.

The concept of 32 bit numbers suggests binary, but where does a ‘space..’ fit in with that ?

  • Yes I work with [rafprojet]

  • Thanks for moving the forum location [sterretje]

  • With an Arduino Uno I can send via the Serial Monitor in Arduino IDE with ctrl+v and enter sent every 0.02 sec

  • So with the recvWithStartEndMarkers found in Serial Input Basics
    I see in another function :

if(newData){
    newData = false;

And I look at receivedChars but the big issue is that I can send (ASCII I think)
<1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 > And I will work than I send it again, it works, but at random attempts (1st or 11th or 19th), it will not get a space or an integer, and it will mess with all the data.

  • This problem of random data loses is the same when I tried myself a succession of if Serial.available() => Serial.read(); But it will also loose data at some point
  • I have tried the Serial.parseInt() but it will wait like 0.3 sec before processing
  • All those tests are in the pure Loop() function, with 0 other code.
  • The perfection should be 64 ints, because I have an array of 64 values and the goal is to say that each int in Serial go in my array. And when I tried with 8 values it was 'quite' ok
  • Changing Serial.begin(115200); or Serial.begin(9600); don't change anything
  • What is weird is that on wokwi.com a simulation of Arduino, I have the same issue
  • The bug is before, but after the code, I use isDigit() on the j receivedChars[j]
    then j+1 then and that's how I get 16 integer

a)
show the output of your sending device as ASCII - or if it is binary - in HEX.
We need ONE complete message and we must be able to put that data in any other serial sender because we don't have your still unknown sending device.

b)
explain in detail - based on the above example message - how the content of your variable should look like after processing of that data

a) what I have is 5 lines of Python :

time.sleep(0.1)
autoit.send("^V")
time.sleep(0.1)
autoit.send("{ENTER}")

And I have <1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 > this line sent on Arduino IDE Serial Monitor
B) I need to be able to send 64 of those numbers in that form
<x x x x x x x x > where x is can be 1 or 2 or 3 digits long. After I check multiple isDigit() to get for example 1 1 0 and then I know that I have a 2 digit number.
After I do my_int = receivedChars[j] - '0'; to get the integer.

you are confusing me with the given 16 numbers, writing about 64 numbers, and than giving a 8 x example.

b)
based on an incomming message like

<1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 >

What content should be in which variable.
be precise.
I need the definition of your variable and the content in each array based on your example.

if
<1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 >
is not what you get - revise your example.

Thanks for trying to help, so for a test with
<1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 > I get this with the receivedChars of recvWithStartEndMarkers of [Serial Input Basics].
From then in an other function, I check if there is new data

if(newData){
    newData = false;

And if there is, I go throw each receivedChars and do isDigit() to know if it is one or two or three digit; In the example the space would return 0 at isDigit so if there is one 1 before the 0, I do
my_int = receivedChars[j] - '0';
If there was two 1 before the 0, I do

my_int = receivedChars[j] - '0';
my_int = my_int*10 + (receivedChars[j+1] - '0');

So after I have an int, and I can use it to, in this example, the first value [0] of my array of int is 1 the second one, 2 the third one 3.
But if there is <2 2 104 0 0 6 7 8 9 10 11 12 13 14 15 16 >
Then the first value of my array should be 2, the second 2, the third 104 ...
I am trying 16 values before 32 or 64 to be sure that it worked on a smaller scale.
But my problem is before all this, the receivedChars is not always accurate. With 8 values it was like 97% but with 16 values I drop at 85-86% of accuracy

so from

<2 2 104 0 0 6 7 8 9 10 11 12 13 14 15 16 >

you want your
int value[16] look like
value[0]= 2
value[1] = 2
value[3] = 104
value[4] = 0
value[5] = 0
value[6] = 7
value[7] =8
value[8] = 9
value[9] = 10
value[10] = 11
value[11] = 12
value[12] = 13
value[13] = 14
value[14] = 15
value[15] = 16

is that correct?

Try the following sketch with necessary adjustment to suit your requirements:

char myData[200];

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

void loop() 
{
  byte n = Serial.available();
  if(n != 0)
  {
    byte m = Serial.readBytesUntil('\n', myData, 200);
    Serial.println(m);
    myData[m] = '\0';
    Serial.println(myData);
  }
}

Note: The InputBox of the Serial Monitor always sends ASCII-codes. If you are sending 1234 (an int-type data to you), then the IDE transfer the following codes in bit forms (the hex form and the spaces are shown for clarity).

0x30 0x31 0x32 0x33

If you want to send/receive natural binary number, then use another Arduino as a Simulator for test purpose. Add 3-byte (known pattern) preamble (for synchronization) at the beginning of the frame and add a Checksum byte at the end of the frame. You may use the following code to receive the frame. Don't forget to validate the Checksum byte.

Serial.readBytes(myData, n);  //n=number of data bytes to receive excluding sync
1 Like

You missed the value[2] but yes thats the idea

Thank you everybody for your help, GolamMostafa
you are a lifesaver !

Just tell me if you are receiving natural binary data or ASCII-coded data.

I am receiving ASCII-coded data

1 Like

this example parses already parts of messages, separated by blank.

/*
   Serial Receive Example

   start tag
   blank separated values
   end tag
   <1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 >

   by noiasca
   2022-04-19 https://forum.arduino.cc/t/read-32-ints-arduino-serial/982416/
*/

constexpr int dataSize = 16;   // size of data array

class Receiver {
  protected:
    static const byte numChars = 36;   // receiver buffer size ( we process just <+integer+blank so a short buffer is ok
    char receivedChars[numChars];      // an array to store the received data
    byte ndx = 0;                      // length of received message
    boolean newData = false;           // flag to indicate when new data is complete
    Stream &stream;                    // a reference to the serial interface
    void (*cbOnNewData)();             // gets called after we received a full message

    byte cnt = 0;                      // counter of array
    
    void delBuffer()
    {
      memcpy(receivedChars, "", sizeof(receivedChars));
      ndx = 0;
    }

    void debugDataHex()
    {
      for (size_t i = 0; i < ndx; i++)
      {
        if (receivedChars[i] < 0x10) Serial.print('0');
        Serial.print(receivedChars[i], HEX);
        Serial.print(' ');
      }
      Serial.println();
    }

    void parseData()                   // parse data and store to internal variables
    {
      receivedChars[ndx] = '\0';
      int result = atoi(receivedChars);
      if (cnt < dataSize)
      {
        data[cnt]=result;
      }
      delBuffer();
      cnt++; // increase array index for next call
    }

  public:
    // payload data
    int data[dataSize];

    Receiver (Stream &stream) : stream(stream)
    {
      delBuffer();
      for (auto &i : data) i = 0; // init data with 0
    }

    void setOnNewData(void (*cbOnNewData)())     // set a callback function. Gets called when new data was received
    {
      (*this).cbOnNewData = cbOnNewData;
    }

    void update()                                // run this member function in loop()
    {
      constexpr byte startMarker = '<';          // start flag
      constexpr byte endMarker = '>';            // end flag
      constexpr byte delimiter = ' ';            // data delimiter
      if (stream.available() > 0) {
        char rc = stream.read();
        if (rc == startMarker)
        {
          delBuffer();
          ndx = 0;
          cnt = 0;
        }
        else if (rc == delimiter)
        {
          receivedChars[ndx] = rc;
          ndx++;
          parseData();  // parse data after each delimiter
        }
        else if (rc == endMarker)
        {
          if (cbOnNewData) cbOnNewData();  // optional call callback when we have received a full message
        }
        else if (ndx < numChars)
        {
          receivedChars[ndx] = rc;
          ndx++;
        }

        // sanity check
        if (ndx >= numChars) delBuffer();
      }
    }
};

// create the sensor object and hand over the Serial interface to use:
HardwareSerial &mySerial = Serial;
Receiver device(mySerial);                  // use Hardware Serial (for example for testing with the PC)

//#include <SoftwareSerial.h>               // on an Uno you can use SoftSerial
//SoftwareSerial mySerial(2, 3);            // RX, TX
//Receiver device(mySerial);                // on an UNO you will need SoftSerial to connect to the device

// On a Mega you can simply use
// a Reference to an existing HW Serial:
//HardwareSerial &mySerial = Serial1;
//Receiver device(mySerial);

void output()                           // simple output of data
{
  for (int i = 0; i < dataSize; i++)
  {
    Serial.print(i);
    Serial.print(" ");
    Serial.println(device.data[i]);
  }
}

void timerOutput()                     // a timer to output data to serial
{
  static uint32_t previousMillis = 0;  // time management
  const uint16_t interval = 3000;      // interval to display data
  if (millis() - previousMillis >= interval)
  {
    previousMillis = millis();
    output();
  }
}

void setup() {
  Serial.begin(115200);
  mySerial.begin(115200);
  //device.setOnNewData(output);  // register a callback function which gets called when a new telegram was received
}

void loop() {
  device.update();                // you must call the .update() method in your loop()
  timerOutput();
}

the output is called each three seconds, but that is for debugging only.

gives
0 2
1 2
2 104
3 0
4 0
5 6
6 7
7 8
8 9
9 10
10 11
11 12
12 13
13 14
14 15
15 16

on the given example