1

A weird is happening which i can't figure out why. First I had issue communicating with SIM800L. So i tried checking the USART Hardware to see what UNO sends to SIM800 using small piece attached below. The sketch is to compares what i send from serial monitor with strings "Hello", "heLLo" and "Hello" expecting to get Found .... or No match found. each line string i send, the serial monitor prints twice WHY?, The first says not found and the second say Received == ........ WHY?

**See the output of serial terminal when i typed "Hello" with quotes.

12:03:46.536 -> Buffer Received= "  No match found
12:03:46.569 ->  
12:03:46.569 -> Buffer Received= Hello"
12:03:46.603 ->     Found Hello
when i typed "HELLO" with quotes. 
12:03:55.855 -> Buffer Received= "  No match found
12:03:55.888 ->  
12:03:55.888 -> Buffer Received= HELLO"
12:03:55.921 ->     Found HELLO**

****when i typed "heLLo" with quotes.

12:04:04.016 -> Buffer Received= "  No match found
12:04:04.049 ->  
12:04:04.049 -> Buffer Received= heLLo"
12:04:04.082 ->     Found heLLo
12:04:04.115 ->****  

When i typed without quotes, all i get No match found

char buffer[100];
uint8_t index=0;

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

void loop()
{
  if(Serial.available()>0)
  {
    index=0;
    while(Serial.available())
    {
      buffer[index++]=Serial.read();
    }
    
    buffer[index]='\0';
    Serial.println(' ');
    Serial.print("Buffer Received");
    Serial.print(buffer);
    Serial.print('\t');
    if(strstr(buffer, "Hello")!=NULL) Serial.println("Found Hello");
    else if(strstr(buffer, "HELLO")!=NULL) Serial.println("Found HELLO");
    else if(strstr(buffer, "heLLo")!=NULL) Serial.println("Found heLLo");
    else Serial.println("No match found");
    Serial.flush();
  }
}

Note: Suspecting my PC hardware and serial driver, so I tried it in my Ubuntu 20.04 and window 10 installed with Arduino IDE 1.8.13 suspecting it may be crystal, i tried two different boards and used even Atmega328P core. I also suspected my keyboard "ENTER" key, so i tried the serial monitor "send" button.
with no difference.

I seems to run short is ideas so i am posting to the community. Let me have your advice and experience too.

Thanks.

7
  • You have a fundamental misunderstanding of how serial communication works. You can't just read "while available" because that will not be true. You need to "read if available and up until the terminating character".
    – Majenko
    Commented Jul 31, 2020 at 11:14
  • 9600 Bd means 1ms per character. If there's no terminating character to rely on, simply waiting a few ms via delay(10); after the first Serial.available()> 0 is an ugly but doable alternative in this case. Commented Jul 31, 2020 at 11:41
  • Hello DataFiddler, You great, your suggestion works. it was just a case of delay which ignored. I actually added delay(10) in-between character reads. and no more print duplication. BUT WHY is that necessary? in eclipse i don't think i have that experience. IT WORTH NOTING WHEN USING ARDUINO IDE!
    – Avong
    Commented Jul 31, 2020 at 11:53
  • Doesn’t matter what IDE you use to write the code the code is the same. The problem is that the serial data doesn’t come all at once. You get one character and read it and then before the next character arrives available is again 0 and you go off to compare your one character you read. While you’re doing that the rest of the string arrives. When you get back around you’ve now got the whole string. With the delay you’re giving the string time to complete arrive one letter at a time on the port.
    – Delta_G
    Commented Jul 31, 2020 at 12:04
  • It’s not necessary to have the delay if you write proper code to handle serial data. Have it look for an end marker before it does the comparison. Or have it wait until available returns the full length of the string before you start reading it.
    – Delta_G
    Commented Jul 31, 2020 at 12:05

1 Answer 1

1

As Majenko and DataFiddler already stated in the comments, you are reading the Serial interface in the wrong way, because you seem to misunderstand a specific point involving the interface.

The Serial (UART) interface knows only of individual bytes, which are send asynchronously over the lines. It does not have any context of a full packet or message. When you type in some data into the Serial Monitor and then press "Send", the data will be send, but not as one big bunch of data. The individual bytes are delayed.

The first delay comes with the nature of the interface itself, as you send with a limited baudrate. With a baudrate of 9600 the Arduino is way faster, than the bytes can arrive. So when you first get a result higher than zero from Serial.available(), the rest of the message is not yet received. Thus with your current code you would only process only the first part of the message.

The second delay comes with the fact, that you and the Serial program on your PC cannot control, when exactly each byte is send. Thats done by the driver. So it might happen, that there is a small gap between 2 bytes somewhere in your message. You cannot mitigate this without writing your own driver and you cannot predict this.

So, what to do now? You should read data, when it is available, and put it into a buffer. And only, when a full message was received, you should process the data. Now you need to know, where the end of a message is. Mostly a delimiting character (like the newline character \n) at the end of the message is used. So you read, if available, and only process the message, when you have read the delimiting character. Something like this:

unsigned int buffer_pos = 0;
char buffer[50]="";

void loop(){
    if(Serial.available()){
        char c = Serial.read();
        if(c == '\n'){
            buffer[buffer_pos] = '\0'; // End the message as C string with a null character
            // process the message here
            buffer_pos = 0;
        } else {
            buffer[buffer_pos] = c;
            buffer_pos++;
        }
    }
}

buffer holds the message. buffer_pos is the current position in the buffer. We terminate the message with the null character, to get a valid C string in the buffer. After processing the message, we set the position back to zero, to receive the next message. When you send data from your PC, you need to make sure, that the message is ended with the newline character.

Now you are independent on when exactly the data is send.


DataFiddler stated in the comments, that without a delimiting character you can simply delay for enough time, so that the data has enough time to arrive. He also stated, that it is ugly. It is a bad coding style. A long delay will impact the responsiveness of your program, while a short delay may give you problems with longer messages. So I suggest, that you directly use the correct way to read the Serial interface. Then you don't have such pitfalls.

2
  • 1
    Dear chris! you guys are great! THANKS ALOTS. got it resolved first from DataFiddler suggest and next Majenko suggestion. Your explanations is explicit. I enjoy all your contribution. JUST that i was abit careless in handling that. Funny as it will sound. I battle with this for about 22hrs. Just as i stated earlier, i will be more caution next to avoid this kind avoidable stress.
    – Avong
    Commented Jul 31, 2020 at 13:01
  • @Avong, please upvote good answers and mark as correct the answer which is best, as this is the best way to thank people for taking the time to write good answers. The upvote button is the little up arrow at the top left of the answer. Commented Aug 30, 2020 at 16:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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