Efficient Way of Sending Data via Serial

Hello,

I am trying to establish a method of sending data to my PC (via serial) efficiently. The application includes a complex control system and various sensors - so continuously polling may not be recommended.

I understand that there is a buffer associated with the serial port - and I know that in Atmel Studio you can program the buffer to initiate an interrupt in order to ask for the next byte of data in order to be sent. This, in my opinion, is the best way of doing it because it does’t interrupt the rest of your code. I do not know how to implement and I come here for help and other suggestions.

For now I do:

 if (millis() % 100  == 0) {
    Serial.println(data);
  }

But at faster rates the control system becomes unstable and data packets are never sent periodically. What other efficient ways of sending data serially (without interrupting the rest of the code) can I implement?

Thanks,

I understand that there is a buffer associated with the serial port - and I know that in Atmel Studio you can program the buffer to initiate an interrupt in order to ask for the next byte of data in order to be sent.

You can't "program the buffer". You can program the Arduino.

There are interrupts involved in sending serial data. They get data from a buffer that Serial.print(), Serial.println() and Serial.write() write to. You don't have to do anything to use those interrupts.

But at faster rates the control system becomes unstable and data packets are never sent periodically.

For one thing, that code relies on millis() returning every single value. That's a poor assumption, as millis() returns milliseconds as a whole number, and there are 1024 ticks to make millis() increment. So, periodically, millis() is going to return a value 2 higher, not 1 higher, than last time.

HardwareSerial.cpp has a small buffer that it uses for outgoing data. When you use print() and friends, and the data you are printing does not fit, then the print() blocks until space is available and the data can be sent.

Because your sketch spends some of its time blocked on print(), it misses some of the moments when millis() % 100 == 0. This coupled with the very real likelihood that millis() % 100 of often not zero, even 100ms after a point that it WAS zero, as PaulS points out, is likely what you're seeing.

There is, unfortunately, no way to sense if there is space in the transmit buffer. You can use flush() to wait for everything to be sent, but there is no async way to test if flush() or print() would block. You would have to hack HardwareSerial.cpp to add this feature.

Let's start at the beginning.

How many bytes per second do you need to transmit?

Have you ensured that you are not sending any unnecessary baggage?
Can you provide an example of the sort of data to be transmitted?
If you are sending numbers are you sending them as binary values or as their (much longer) text equivalent?

What is the highest baud rate you have tried? While the Arduino Serial Monitor will only work up to 115200 baud the Arduino should be able to work at 250,000 baud and probably 1,000,000 baud.

I have never tried anything except the normal Serial.print() or Serial.write() and it seems perfectly capable of sending data as fast as you would expect from the baud rate. No amount of clever/complicated coding is going to exceed the baud rate.

...R

The serial buffer is 64 bytes in length, when that gets full any print call will block. Unfortunately there is no mechanism for changing the buffer size or indeed getting a callback when it's empty, these would be nice enhancements IMO.

So I see where you are going with the "send X bytes every 100mS" approach, but where is "data" coming from and how large is it?

You could implement your own FIFO (aka circular buffer) and make it as large as you like then run a custom print function every 100mS, but to do this you have to trick the standard .print() functions to write to your buffer or use sprintf() or trap the low-level function (putchar() IIRC).

Personally I think the serial funcs could do with an overhaul by now.


Rob

I would think delimiting the data packets similar to the below would be fairly efficient as the arduino would be receiving data as fast as it can.

//zoomkat 3-5-12 simple delimited ',' string parse 
//from serial port input (via serial monitor)
//and print result out serial port
//send on, or off, from the serial monitor to operate LED

int ledPin = 13;
String readString;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT); 
  Serial.println("serial LED on/off test with , delimiter"); // so I can keep track
}

void loop() {

  if (Serial.available())  {
    char c = Serial.read();  //gets one byte from serial buffer
    if (c == ',') {
      Serial.println(readString); //prints string to serial port out
      //do stuff with the captured readString
      if(readString.indexOf("on") >=0)
      {
        digitalWrite(ledPin, HIGH);
        Serial.println("LED ON");
      }
      if(readString.indexOf("off") >=0)
      {
        digitalWrite(ledPin, LOW);
        Serial.println("LED OFF");
      }       
      readString=""; //clears variable for new input
    }  
    else {     
      readString += c; //makes the string readString
    }
  }
}