Problem with Arduino Delay Reading From Serial Port

I have a problem with my Arduino code,

I'm trying to read from a Serial and Sending this data trough serial Monitor.

Everything works well with this code:

if (Myserial1.available()) {


String data = Myserial1.readStringUntil('\n'); // Read from external port

Serial.print("Datas: ");
Serial.println(data);


}

And this is the output:

12:45:16.426 -> Datas: +      16.80g 

12:45:17.415 -> Datas: +      16.80g

12:45:18.437 -> Datas: +      16.80g

But I need to read this values every 1 or 5 seconds, and when I try to add a simple delay in this way:

if (Myserial1.available()) {


String data = Myserial1.readStringUntil('\n'); // Read from external port

Serial.print("Datas: ");
Serial.println(data);

delay(1000);

}

This is the output in my Serial Monitor:

12:45:16.426 -> Datas: +      16.8+      16.80g  

12:45:17.415 -> Datas: +      16+      16.80g  

12:45:18.437 -> Datas: +      16.�+      16.80g  

That doesn't make sense, you need to read the data when it comes in, not at some arbitrary interval. Have you read this:

If not, I suggest you do, it is an excellent tutorial on how to do serial communications.

On a more general note using delay is asking for trouble because nothing else can happen while delay is delaying. Nothing. No reading a button, no updating a display, no turning an LED on or off. There are tutorials for this too.

2 Likes

Sorry, I explained myself badly.
I need to send data through another function every 1/5 seconds.
and when I save the variable or call the function at a specific time interval those are the data I see.

Nothing I can say will be half as good as the information in the tutorial I linked to, please start there.

Or maybe someone else can be more helpful than I can.

even if it follows the tutorial perfectly, since I add a little delay before sending the data to the server I get the same output

If you add delays you run the risk of buffer overflows. I think that thay is what is happening.

The correct way to approach this is to always read the incoming data but only send the latest received data when it's time; that implicates use of millis() or another clock source.

Question: how did you manage to get exactly the same timestamps in serial monitor?

I tried this approach too but I have the same problem.



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

void loop() {

  

  bool stable = false;

    if (MySerial1.available()) {


    String data = MySerial1.readStringUntil('\n'); // Read data 

    }
  
unsigned long lastRequestTime = 0;
unsigned long requestInterval = 1000; //time delay
unsigned long currentMillis = millis();

if (currentMillis - lastRequestTime >= requestInterval) {
    
    String datatosend = data;
    datatosend.replace(" ", "");

    if(datatosend){
    Serial.println(datatosend);
    lastRequestTime = currentMillis;
    }
    
    
  }
    
}



The lines of code that you have posted are not the complete sketch.
Your code is badly formatted.
please do these things:

  1. use to auto-formatting feature by pressing ctrl-t
  2. delete the empty lines so that maximum one empty line is in your code between statements
  3. post your complete sketch from the very first to the very last line
  4. run your code and then mark, copy & paste the very actual output from the serial monitor as a code-section

EDIT

declaring a variable inside an if-condition makes this variable local to the scope of the if-condition

    String data = MySerial1.readStringUntil('\n'); // Read data

which results in a compiler-error
exit status 1
'data' was not declared in this scope

In general using variables of type String on a microcontroller does often cause problems.
Each time you assign a new value to a variable of type String some new RAM is occupied. In many cases this leads to eating up all memory and then corrupting RAM that is used by other variables.

As an alternative you can use SafeString. The name is program.

best regards Stefan

Several things wrong with your sketch.

data is a local variable, it ceases to exist at the end of the if statement where it is declared.

lastRequestTime is also a local variable, it gets set to 0 every time loop() executes, so the if statement checking for the time interval will always be false.

Using readStringUntil() can be a problem, that function will wait for a newline character before returning, which can slightly interfere with the timing of the send portion of the code (even worse if no newline is received, in which case the function returns when it times out). The use of String can also cause memory problems over the long term. Better to use the receive code in the Serial Input Basics linked to previously, and read the text into a char buffer.

1 Like

look this over

output

                    something to send: 1000
                    something to send: 2000
                    something to send: 3000
                    something to send: 4000
hi
                    something to send: 5000
                    something to send: 6000
                    something to send: 7000
                    something to send: 8000
                    something to send: 9000
how are ya
                    something to send: 10000
                    something to send: 11000
                    something to send: 12000
                    something to send: 13000
fine
                    something to send: 14000
                    something to send: 15000
                    something to send: 16000
                    something to send: 17000

code


unsigned long lastRequestTime = 0;
const unsigned long Interval = 1000;


void loop()
{
    unsigned long currentMillis = millis();

    if (Serial.available()) {
        String str = Serial.readStringUntil('\n');
        Serial.println (str);          // echo
    }

    if (currentMillis - lastRequestTime >= Interval) {
        lastRequestTime = currentMillis;

        Serial.print   ("                    something to send: ");
        Serial.println (currentMillis);
    }
}

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

The usual not explained hard to understand = hard to use non-blocking timing
.
.

commented more structured code with self-explaining names for everything
It uses the SafeString-library which you can install with the Arduino-IDE librarymanager

#include <SoftwareSerial.h>
#include <SafeString.h>
#include "SafeStringReader.h"

// adapt the software-serial Rx/Tx pins to match your hardware
SoftwareSerial MySerial1 (4, 5);

// create a non-blocking Serial-Read-In-object
// buffersize 32 byte
// terminating characters carriage return "\r"  
createSafeStringReader(sfReader, 32, "\n");
//sfReader does the same as MySerial1.readStringUntil('\n')
// but in a non-blocking way

boolean stringComplete;
boolean newData = false;

unsigned long myDataSendTimer; // variable used for NON-blocking timing

// create a SafeString with name "data_SS" 
// that can hold 32 characters
cSF(data_SS, 32); 

void setup() {
  Serial.begin(9600);
  MySerial1.begin(9600);
  Serial.println("Serial begin & mySerial1 begin done");
  Serial.println("waiting for characters to be received...");
  
  //sfReader.connect(MySerial1); // make sfReader receive from MySerial1
  sfReader.connect(Serial);      // make sfReader receive from Serial
}


void loop() {

  // sfReader.read() results in true when the terminating character is received
  // and you call sfReader.read() for the FIRST time
  // all following up calls to sfReader.read() result in false
  // until a NEW string is received which means it is the FIRST call
  // for the new received string
  stringComplete = sfReader.read();

  if (stringComplete) {
    newData = true; // new data arrived set flag to true

    data_SS = sfReader;
    myDataSendTimer = millis(); // store actual time in variable myDataSendTimer
  }

  if (newData) {
    // check if 1005 milliseconds have passed by since last sfReader.read(); resulted in true
    if ( TimePeriodIsOver(myDataSendTimer, 1005) ) {
      // when REALLY 1005 millisconds HAVE passed by
      Serial.println(data_SS);
      newData = false; // data has been printed reset flag to false
    }
  }
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}

best regards Stefan

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.