Serial communication with Bluetooth module and delays

Hi,

Unfortunately I can't figure out why do I need delay in the following example.

My Arduino: Leonardo
My Arduino IDE: 1.6.3
My operating system: Description: Ubuntu 14.04.2 LTS; Release: 14.04; Codename: trusty

Wiring:
PIN0 = RX <-> TX of CZ-HC-05 gomcu
PIN1 = TX <-> RX of CZ-HC-05 gomcu
+3V <-> VCC of CZ-HC-05-gomcu and LVcc of voltage adapter
+5V <-> HVcc of voltage adapter
GND <-> GND of voltage adapter and CZ-05-gomcu

Voltage adapter alters voltage levels from 5 V to 3.3 V level.

My task is to control Arduino Leonardo from PC terminal, basically minicom, by pressing cursor keys. Minicom by default emulates VT100 terminal, where each cursor are in fact series of 3 bytes.

I can't explain by myself why the following code works only if in loop there is delay (50) present. Without that line there is printed out Buffer2 correctly, but none of strcmp takes place.

Here is my code:

/*
  Author: mslonik
  Date: 2015-04-27
  License: GNU GPL 3.x
*/

const char EndOfString = '\0';               

const char CursorUp [] = { 0x1B, 0x5B, 0x41, 0x00 };    
const char CursorDown [] = { 0x1B, 0x5B, 0x42, 0x00 };   
const char CursorLeft [] = { 0x1B, 0x5B, 0x44, 0x00 };   
const char CursorRight [] = { 0x1B, 0x5B, 0x43, 0x00 };  

const char BufferSize = 64;        
char Buffer2 [BufferSize] = "";   
unsigned char BufferIndex2 = 0;   

unsigned long int GomcuDefault = 38400;



void setup () // put your setup code here, to run once:
{
  Serial1.begin (GomcuDefault);                 
  while (!Serial1);                             
  Serial1.println ("Beginning...");
//  PrintCharTable (CursorUp);
//  Serial1.println ();
//  PrintCharTable (CursorDown);
//  Serial1.println ();
//  PrintCharTable (CursorRight);
//  Serial1.println ();
//  PrintCharTable (CursorLeft);
//  Serial1.println ();
//  ZeroInputBuffer (Buffer2);                  
}


void loop () // put your main code here, to run repeatedly:
{
  WaitForAnswerFromBT ();                                       // Get answer from Bluetooth module
  PrintCharTable (Buffer2);
  delay (50);              // Here is a problem.
  
  if ( strcmp (Buffer2, CursorUp) == 0 )
    {
      Serial1.println ("Up");
    }
     
  if ( strcmp (Buffer2, CursorDown) == 0 )
    {
      Serial1.println ("Down");
    }    

    if ( strcmp (Buffer2, CursorRight) == 0 ) 
      {
        Serial1.println ("Right");
      }

    if ( strcmp (Buffer2, CursorLeft) == 0 ) 
      {
        Serial1.println ("Left");
      }

  ZeroInputBuffer (Buffer2);                          // Empty input buffer.
  BufferIndex2 = 0;                                    // Zero buffer index.
}

// 1 -----------------------------------------------------------------------------------
/*
  Print out a char table, byte by byte.
*/
void PrintCharTable (const char *CharTable)
  {
   unsigned char i = 0; 
   
   while ( CharTable [i] != EndOfString )
     {
       Serial1.print ( CharTable [i], HEX);
       i ++;  
     }
  }


// 2 -----------------------------------------------------------------------------------

void ZeroInputBuffer ( char * tablica)
  {
    unsigned char i = 0;
  
    for (i; i < BufferSize; i++)
      {
        tablica [i] = EndOfString;
      }
  }

// 3 -----------------------------------------------------------------------------------

void EmptyInputBuffer (void)
  {
    while (Serial1.available () > 0)                         // Dopóki liczba znaków dostępnych w pierwszym buforze jest większa od zera.
      {
        Serial1.read ();
      }
  }    


// 4 -----------------------------------------------------------------------------------

void WaitForAsnwerFromBT ()
  {
    char ReadByteSerial2 = 0;         
    while ( Serial1.available () > 0 )
     {
       ReadByteSerial2 = Serial1.read ();                 
       if ( BufferIndex2 < BufferSize - 1 )               
         {
           Buffer2 [BufferIndex2] = ReadByteSerial2;      
           BufferIndex2 ++;                               
         }    
      else                                                
         {
           Serial1.println ("Input buffer overrun!");  
           EmptyInputBuffer ();                         
           ZeroInputBuffer (Buffer2);                   
           BufferIndex2 = 0;                            
         }
    }
  }

Kind regards,
mslonik

void WaitForAsnwerFromBT ()

Strange way to spell Answer.

    char ReadByteSerial2 = 0;         
    while ( Serial1.available () > 0 )
     {
       ReadByteSerial2 = Serial1.read ();

Shouldn't that be ReadByteSerial49?

I can't explain by myself why the following code works only if in loop there is delay (50) present. Without that line there is printed out Buffer2 correctly, but none of strcmp takes place.

Serial data arrives ssslllooowwwlllyyy. The delay() allows time for the next packet to arrive before you try reading it.

It is, of course, completely unnecessary, and is scaled for one bad rate.

Send an end-of-packet marker, and read and store data until that end of packet marker arrives. Relying on delay() to "ensure" that the whole packet arrives is not a robust solution.

Have alook at the examples in serial input basics. They are simple reliable ways to receive data. The second example is probably what you need.

...R

Thank you very much for prompt reply. Let me explain in more detail what's going here:

  1. Without the delay I get full cursor sequence displayed on minicom screen, what in my opinion means that the whole sequence is read correctly:
Welcome to minicom 2.7

OPTIONS: I18n 
Compiled on Jan  1 2014, 17:13:22.
Port /dev/rfcomm0, 19:25:09

Press CTRL-A Z to get help

Beginning...
1B5B411B5B431B5B421B5B44
  1. With the delay I get full cursor sequence correctly and also strcmp comparison are checked correctly:
Welcome to minicom 2.7

OPTIONS: I18n 
Compiled on Jan  1 2014, 17:13:22.
Port /dev/rfcomm0, 19:25:09

Press CTRL-A Z to get help

Beginning...
1B5B43Right
1B5B42Down
1B5B44Left
1B5B41Up

So my function PrintCharTable (Buffer2) for both cases show that correct sequence is read to Buffer2 but for some mysterious reason without delay strcmp doesn't work. Why?

I've read mentioned article about serial communication - very helpful. Before posting my questions I've checked several examples based on termination character. This time I decided to try out something more advanced - without terminating character. My idea is to use cursors for control of small robot.

Kind regards,
mslonik

Get rid of the while. Read one char per call of loop() (but only if its available ).

Mark

mslonik:
This time I decided to try out something more advanced - without terminating character.

That is LESS advanced. Not more advanced. The ideal would be using a start and an end character.

Have you tried using any of the examples in serial input basics? I am not going to spend time writing another version of the same thing.

...R

@Robin2 and others:
Thank you for your reply. I've read again your great article about serial input basics. I think now I know what I'm making wrong: my function doesn't read one character at a time. Let me now improve it by myself.

Thank you again for your patience. Unfortunately sometimes after few hours of lonely fight it's easier to frustrate myself then to read carefully again. Sorry for that.

Kind regards,
mslonik

Ok. Now I've finally shed some light what was wrong. I've changed some code:

void PrintCharTable (const char *CharTable)
  {
   unsigned char i = 0; 
   
   while ( CharTable [i] != EndOfString )
     {
       Serial1.print ( CharTable [i], HEX);
       Serial1.print (i);                 // Additional line.
       i ++;  
     }
  }

With this additional line now it's clear that Arduino is damn fast. Every time when main loop is finished only one character was printed out in minicom:

1B05B04301B05B04201B05B04301B05B04201B05B0430

So indeed my example was 'how not to read serial character'. Thanks for help. This thread may be closed now.

Solution of my problem is presented below, but please be careful. Definitely better idea of this kind of problem was presented by Robin2. My solution shows some overhead.

/*
  Author: Maciej Słojewski
  Date: 2015-04-27
  License: GNU GPL 3.x
*/

const char EndOfString = '\0';               

const char CursorUp [] = { 0x1B, 0x5B, 0x41, 0x00 };    
const char CursorDown [] = { 0x1B, 0x5B, 0x42, 0x00 };   
const char CursorLeft [] = { 0x1B, 0x5B, 0x44, 0x00 };   
const char CursorRight [] = { 0x1B, 0x5B, 0x43, 0x00 };  

const char BufferSize = 64;        
char Buffer2 [BufferSize] = "";   
unsigned char BufferIndex2 = 0;   

unsigned long int GomcuDefault = 38400;



void setup () // put your setup code here, to run once:
{
  Serial1.begin (GomcuDefault);                 
  while (!Serial1);                             
  Serial1.println ("Beginning...");
}


void loop () // put your main code here, to run repeatedly:
{
  WaitForAsnwerFromBT ();                                       // Get answer from Bluetooth module
//  PrintCharTable (Buffer2);
//  delay (50);              // Here is a problem.
  
  if ( strcmp (Buffer2, CursorUp) == 0 )
    {
      Serial1.println ("Up");
      ZeroInputBuffer (Buffer2);                          // Empty input buffer.
      BufferIndex2 = 0;                                    // Zero buffer index.
    }
     
  if ( strcmp (Buffer2, CursorDown) == 0 )
    {
      Serial1.println ("Down");
      ZeroInputBuffer (Buffer2);                          // Empty input buffer.
      BufferIndex2 = 0;                                    // Zero buffer index.
    }    

    if ( strcmp (Buffer2, CursorRight) == 0 ) 
      {
        Serial1.println ("Right");
        ZeroInputBuffer (Buffer2);                          // Empty input buffer.
        BufferIndex2 = 0;                                    // Zero buffer index.
      }

    if ( strcmp (Buffer2, CursorLeft) == 0 ) 
      {
        Serial1.println ("Left");
        ZeroInputBuffer (Buffer2);                          // Empty input buffer.
        BufferIndex2 = 0;                                    // Zero buffer index.
      }

}

// 5 -----------------------------------------------------------------------------------
/*
  Print out a char table, byte by byte.
*/
void PrintCharTable (const char *CharTable)
  {
   unsigned char i = 0; 
   
   while ( CharTable [i] != EndOfString )
     {
       Serial1.print ( CharTable [i], HEX);
       i ++;  
     }
  }


// 1 -----------------------------------------------------------------------------------

void ZeroInputBuffer ( char * tablica)
  {
    unsigned char i = 0;
  
    for (i; i < BufferSize; i++)
      {
        tablica [i] = EndOfString;
      }
  }

// 2 -----------------------------------------------------------------------------------

void EmptyInputBuffer (void)
  {
    while (Serial1.available () > 0)                         // Dopóki liczba znaków dostępnych w pierwszym buforze jest większa od zera.
      {
        Serial1.read ();
      }
  }    


// 3 -----------------------------------------------------------------------------------

void WaitForAnswerFromBT ()
  {
    char ReadByteSerial2 = 0;         
    while ( Serial1.available () > 0 )
     {
       ReadByteSerial2 = Serial1.read ();                 
       if ( BufferIndex2 < BufferSize - 1 )               
         {
           Buffer2 [BufferIndex2] = ReadByteSerial2;      
           BufferIndex2 ++;                               
         }    
      else                                                
         {
           Serial1.println ("Input buffer overrun!");  
           EmptyInputBuffer ();                         
           ZeroInputBuffer (Buffer2);                   
           BufferIndex2 = 0;                            
         }
    }
  }