1

I am receiving about 90 bytes on the serial port. But Arduino has a serial buffer of 64 bytes only. Because of this limitation I am unable to receive further bytes.

char c;

void read_response() {
  while(Serial.available > 0) {
    c=Serial.read();
    Serial.print(c,HEX);
    Serial.print(",");
  }
}

I tried using the above function to read the serial data, but it is able to read only 64 bytes.

Another approach I tried as follows:

char rxdata[]={};

void read_response() {
  while(Serial.available > 0) {
    int len= Serial.readBytes(rxdata, 90)
  }
}

With this approach too, I was receiving only 64 bytes.

Serial.flush() also doesn't work as it waits for current transmission to finish. And I do not have control on transmission. The transmitter is sending 90 bytes continuously.

Please give me some suggestions.

  • 1
    what baud rate? if you read the response without any delay after sending the request the Atmega should be fast enough to read the bytes from the buffer before it overflows – Juraj Apr 18 '18 at 10:55
  • 1
    That read_response() function should work fine as it is - however you probably have a delay() before it that overflows the buffer. Read this: hackingmajenkoblog.wordpress.com/2016/02/01/… – Majenko Apr 18 '18 at 12:40
  • 1
    Also asked at: forum.arduino.cc/index.php?topic=542236 If you're going to do that then please be considerate enough to add links to the other places you cross posted. This will let us avoid wasting time due to duplicate effort and also help others who have the same questions and find your post to discover all the relevant information. – per1234 Apr 18 '18 at 12:54
3

But Arduino has a serial buffer of 64 bytes only. Because of this limitation I am unable to receive further bytes.

This assertion is nonsense. Certainly there is a buffer, but that lets you receive up to 64 bytes (put there by the serial interrupt service routine) before you retrieve a single one.

All you need to do is expeditiously retrieve the data (that is, do a Serial.read()) fast enough that you remove the data from the buffer and store it into memory.

You need to post a Minimal, Complete, and Verifiable Example (MCVE) that demonstrates your problem. For example, are you doing delay(1000) before attempting to read serial data?

See my post about receiving serial data without blocking and also Async (Serial) peripheral interface - for Arduino .

| improve this answer | |
1

You will need to adjust your concept of serial communication so that you don't rely on the complete 90 bytes of data to be transferred to the serial input buffer before you read it into RAM.

Instead you need to continually empty the hardware buffer into RAM as often as you run through loop(), and avoid using delay(), which will stop your program from being able to drain the buffer.

To know when you have reached the end of the transmission, you should either ensure that the incoming serial stream has a marker at the end (such as a '\n' character) or is always a fixed length (such as always exactly 90 bytes.)

As an example, here is a program that looks for '\n' as the end-of-data marker:

#DEFINE MAX_INPUT 90

char inputBuffer[MAX_INPUT+1]; // Handles up to 90 bytes in a c-style string, with a null character termination.

void setup() 
{
  Serial.begin(115200); // initialization
  inputBuffer[0] = '\0'; //Initialize string to emtpy.
  Serial.println("Begin:");
}

void loop() {

  if (Serial.available()>0)
  {
    char input = Serial.read();
    static int s_len; // static variables default to 0
    if (s_len>=MAX_INPUT) {
      // Have received already the maximum number of characters
      // Ignore all new input until line termination occurs
    } else if (input != '\n' && input != '\r') {
      inputBuffer[s_len++] = input;
    } else {
      // Have received a LF or CR character

      // INSERT YOUR CODE HERE TO PROCESS THE RECEIVED DATA //
      // YOU COULD COPY TO A NEW VARIABLE WITH strncpy() OR //
      // SET A FLAG TO SAY TO START SOME OTHER TASK         //
      Serial.print("RECEIVED MSG: ");
      Serial.println(inputBuffer);

      memset(inputBuffer, 0, sizeof(inputBuffer));
      s_len = 0;             // Reset input buffer here if you
                             // have already copied the data.
                             // If you don't reset here, then
                             // you can't start receiving more
                             // serial port data. This is your
                             // 'software' serial buffer, contrast
                             // with the hardware serial buffer.
    }
  }
}
| improve this answer | |
  • 1
    Good answer, but note that: 1. Storing s_len statically is simpler and more efficient than calling strnlen() on each received character. 2. You don't need to NUL-terminate on every received character, only once per full message. 3. Flushing the input buffer is not needed, and that could discard the beginning of the next message. – Edgar Bonet Apr 18 '18 at 17:48
  • 1
    Ok on point 1. For point 2, my preference is to not leave unterminated strings laying around. For point 3, the code snippet is from my personal cache where I want to be able to signal EOL on CR+LF by detecting the first and discarding all the rest, but you have an excellent point. I will update my sample code. – jose can u c Apr 18 '18 at 18:19
  • 2
    This new version (2018-04-18 19:11:50Z) is prone to a buffer overflow, as the condition s_len==MAX_INPUT is only tested when input is either CR or LF. – Edgar Bonet Apr 18 '18 at 20:13
  • 1
    Fixed that buffer overflow error. My original sample may have been inefficient, but it worked ;-) – jose can u c Apr 18 '18 at 20:30
  • 1
    @gilhad: The buffer is all zeros to start width, as with any global (or local static) variable that is not explicitly initialized. – Edgar Bonet Apr 19 '18 at 8:34
0

I think your second approach using readBytes() was on the right track. If you send 1 to 90 characters using the serial monitor, readBytes() seems to continue reading the hardware buffer and writing into "your" buffer until the hardware buffer is empty, the 90 char limit is reached or the default timeout (1000ms) is reached.

const byte BufferSize = 90;
char Buffer[BufferSize + 1];

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

void loop(){

  if(Serial.available() > 0){

    while(Serial.available() > 0){
      // "readBytes" terminates if the determined length has been read, or it
      // times out. It fills "Buffer" with 1 to 90 bytes of data. To change the
      // timeout use: Serial.setTimeout() in setup(). Default timeout is 1000ms.
      Serial.readBytes(Buffer, BufferSize);
    }

    // Print out "your" 90 char buffer's contents.
    Serial.print(Buffer);
    Serial.println("");

    // You can use Serial.peek() to check if more than 90 chars
    // were in the serial buffer and "your" buffer has truncated data.
    // This should never happen because you know what the max length of
    // the incoming data is and you have adequately sized your input buffer.
    if(Serial.peek() != -1){
      Serial.print("90 byte Buffer Overflowed. ");
    }

    // Clear out "your" buffer's contents.
    memset(Buffer, 0, sizeof(Buffer));
  }
}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.