Go Down

Topic: Problem reading serial port (Read 676 times) previous topic - next topic

Gilles Plante

Sep 21, 2010, 05:33 pm Last Edit: Sep 21, 2010, 05:49 pm by planteg Reason: 1
Hi,

I need someone to open my eyes :o. I have a problem and just can't figure out what's wrong. The Arduino will get commands via the serial port (in fact an Xbee module) and execute the commands. This goes well. But this morning I changed the code to detect timeouts. The fisrt command is OK, but then it get a timeout on each caracter received.

This is what I wish to do:
  • each command ends with '#'
  • as sson as the fisrt character is received, I checked if receiving times out


Here is the code:

Quote

void setup()
{
int i;

#ifdef MEGA
  Serial.begin(57600);
#else
  Serial.begin(57600);
#endif

  strCmd[0] = '\0';  
  ptCmd = 0;
  fComp = false;
  Commande.Cmd = 255;
  for (i = 0; i < 5; i++)
    Commande.Par = 0;
  Commande.NbPar = 0;
  
  fProc = true;
  
  fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);

  // The uart is the standard output device STDOUT.
  stdout = &uartout;
  
}

void loop()
{
char  Car;  // un caractère
char nCmd[3];  // numéro de commande
char fStr[15];
long lStart;   // lecture au départ du compteur de timeout

// Pointeurs

int i;  // dans strCmd
int j;  // dans nCmd[] et strPar[]
int k;  // dans Commande.Par[]
char strPar[6];  // un paramètre (chaîne)

  //  1 - read serial port

  if (fProc == true)  // true the process characters
    {
     
    // If at least 1 char. received, check timeout
      
    if ((ptCmd > 0) && ((millis() - lStart) > 5000))  
      {

#ifdef MEGA
      printf("  pt = %d - tout ---\n   ", ptCmd);
      for (i = 0; i < ptCmd; ++i)
        printf("%c", strCmd);
      printf("\n");
#endif  
      ptCmd = 0;  
      strCmd[0] = '\0';

      }
    else      // carry on
      {
      if (Serial.available())  // at least one char. received
        {
        Car = (char)Serial.read();
        
        if (Car != FIN_CMD)  // '#' not received
          {
          strCmd[ptCmd++] = Car;
          lStart = millis();  // restart timeout counter        
          }
        else                // '#' received
          {
          fComp = true;    // Command complete
          strCmd[ptCmd] = '\0';
          ptCmd = 0;
          fProc = false;
          // Serial.flush();
          }
        }  // if caractère reçu        
      }  // else de if timeout  
    }   // if (fProc == true)

  // remining of loop cut, process command
}
  



One more information. At this time the software is develloped on a MEGA board, and I communicate with the board via serial monitor.

Thanks for your help

AWOL

It's better if you include ALL the sketch, and use the "#" icon, instead of the quote.
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Gilles Plante

#2
Sep 22, 2010, 06:16 pm Last Edit: Sep 22, 2010, 06:25 pm by planteg Reason: 1
I changed the the part that reads the serial port, and still have problems. Please note that I was unable to publish the entire sketch because it was bigger than the maximum number of characters allowed. Sorry for the comments in French, this is my language.

I use the console to do the debugging (breakpoints would be nice  :-/), and here is what I get for the first command sent (10#):

[font=Courier New]Cmd = 10
Par[0] =  0.000
Par[1] =  0.000
Par[2] =  0.000
Par[3] =  0.000
Par[4] =  0.000
Nb de param. = 0
00#
 pt = 2 - tout ---
  10
[/font]

The command executes OK (it returns 00#), but right after a timeout is declared (pt = 2 - tout ---).

Note this code:

 //  2 - Préparation de la commande dans la structure
 
 delay(20);    // needed but why ???

If this delay is not there, then it does not work at all. Here is what I get on the console:


Nothing at all  :-?. When the last character is received, I set fComp to true. Then this should execute:

 if (fComp == true)
   {
   ...
   }

But it does not without the call to delay().

I am quite puzzled:
  • the comands complete OK, but then there is a timeout. Note that the iidea is to strart timeout check only once a first character is received
  • when you have to insert delays, you're in big trouble  ;).

I have had strange problems with the other micro connected to an Xbee, a Rabbit module, because only the baud rate was set. With the Arduino, one can only set the baud rate. I have read on the site that everything else is set to 8, n, 1. But I wonder.

Here is the code:

Code: [Select]
#include <Servo.h>

#include <MsTimer2.h>
#include <stdio.h>
#include <stdlib.h>

#define MEGA  // Lorsque défini, indique que c'est un board MEGA
             // non défini, board FIO

// create a FILE structure to reference our UART output function

static FILE uartout = {0} ;

// create a output function
// This works because Serial.write, although of
// type virtual, already exists.
static int uart_putchar (char c, FILE *stream)
{
   Serial.write(c) ;
   return 0 ;
}

#define  VER 6    // La version

#define FIN_CMD '#'  // caractère de fin de commande
#define FIN_PAR ';'  // caractère de in de paramètre

typedef struct
 {
 int Cmd;     // la commande (son numéro)
 float Par[5];  // 5 paramètres
 int NbPar;   // nb de paramètres  
 } Cmd;
 
Cmd Commande;  // Structure qui contient le no de commande et les paramètres

typedef struct
 {
 int mini;     // largeur d'impulsion minimale
 int centre;   // largeur d'impulsion centre moteur continu
 int maxi;     // largeur d'impulsion maximale
 int cont;     // true, moteur continu
 float temps;  // temps en sec. pour atteindre 60 deg. moteur angulaire
 } SPar;
 
SPar ServoP;  // structure qui contient les paramètres  

typedef struct
 {
 int ang;              // angle où amener le bras
 float temps;          // temps pour y aller ou revenir
 unsigned char aller;  // true c'est un aller, false un retour
 int count;            // le nb de fois
 } aPulse;

aPulse angP;  // structure qui contient les paramètres

#define SERVO_PIN 9  // pin Arduino où est relié le moteur

// Les commandes

#define ATTACH_SERVO    1
#define SET_ANGLE       2
#define SET_ROTATION    3
#define DETACH_SERVO    4
#define RUN_CONT_MSEC   5
#define SERVO_ATT       6
#define RUN_ANG_NB      7
#define STOP_CONT       8
#define VERSION         9
#define PING           10

//  Les messages de retour

#define CMD_OK        "00#"
#define CMD_ER_PAR    "01#"  // erreur validation des paramètres
#define CMD_NB_PAR    "03#"  // nb. de paramètres incorrect
#define CMD_NO_ATT    "04#"  // pas de servo attaché

int fComp;  // true, alors commande complète
Servo Moteur;  // objet pour le servo
char strCmd[30];  // comamnde reçue à traiter
int ptCmd = 0;  // pointeur dans Cmd
int fProc;  // true, lire les caractères
long lTimeOut;

void SendResp(char Resp[]);
void StopCont(unsigned char);
void StopCont2();

void setup()
{
int i;

 fdev_setup_stream (&uartout, uart_putchar, NULL, _FDEV_SETUP_WRITE);

 // The uart is the standard output device STDOUT.
 stdout = &uartout;

#ifdef MEGA
 Serial.begin(9600);
#else
 Serial.begin(57600);
#endif

 strCmd[0] = '\0';  
 ptCmd = 0;
 fComp = false;
 Commande.Cmd = 255;
 for (i = 0; i < 5; i++)
   Commande.Par[i] = 0;
 Commande.NbPar = 0;
 
 fProc = true;
 
 
 
}

void loop()
{
char  Car;  // un caractère
char nCmd[3];  // numéro de commande
char fStr[15];


// Pointeurs

int i;  // dans strCmd
int j;  // dans nCmd[] et strPar[]
int k;  // dans Commande.Par[]
char strPar[6];  // un paramètre (chaîne)

 //  1 - Lecture des caractères

 if (fProc == true)
   {
   
   if (ptCmd == 0)    // pas de car. reçu
     {
     if (Serial.available() > 0)  // car. reçu(s)
       {
       Car = (char)Serial.read(); // printf("  Recu %c\n", Car);
       strCmd[ptCmd++] = Car;
       lTimeOut = millis() + 1000;  // charge le compteur  
       }
     }
   else    // des car. déjà reçus
     {
     if (millis() > lTimeOut)  // oups timeout
       {
#ifdef MEGA
       printf("  pt = %d - tout ---\n   ", ptCmd);
       for (i = 0; i < ptCmd; ++i)
         printf("%c", strCmd[i]);
       printf("\n");
#endif  
       ptCmd = 0;  
       strCmd[0] = '\0';
       Serial.flush();          
       }  
     else  // pas de timeout
       {
       if (Serial.available() > 0)  // car. reçu(s)
         {
         Car = (char)Serial.read(); // printf("  Recu %c\n", Car);
         
         if (Car == '#')  // commande finie
           {
           fProc = false; // printf("  # recu\n");
           fComp = true; // printf("fComp = %d\n", fComp);
                       
           }
         else
           {
           strCmd[ptCmd++] = Car;
           lTimeOut = millis() + 1000;  // charge le compteur
           }  
         }          
       }  // if timeout  
     }    // des car. déjà reçus    
   }      if (fProc == true)  
       
 //  2 - Préparation de la commande dans la structure
 
 delay(20);    // needed but why ???
 
 if (fComp == true)
   {
   
   i = 0;
   
   nCmd[0] = strCmd[i++]; nCmd[1] = strCmd[i++]; nCmd[2] = 0;
   
   Commande.Cmd = atoi(nCmd);
   
   for (k = 0; k < 5; k++)
     Commande.Par[k] = 0;
     
   j = 0; k = 0;
   while (strCmd[i] != '\0')
     {
     Car = strCmd[i++];  
     
     if (Car != FIN_PAR)
       strPar[j++] = Car;
     else
       {
       strPar[j] = '\0';
       Commande.Par[k++] = atof(strPar);
       j = 0;
       }
     }
     
   Commande.NbPar = k;
 
 #ifdef MEGA
 
   // Imprime commande
   
   printf("Cmd = %d\n", Commande.Cmd);
   for ( i = 0; i < 5; ++i)
     {
     dtostrf(Commande.Par[i], 6, 3, fStr);
     printf("Par[%d] = %s\n", i, fStr);
     }
     
   printf("Nb de param. = %d\n", Commande.NbPar);
 
 #endif
 
   //  3 - Exécution de la commande
 
   switch (Commande.Cmd)
     {
       
     case ATTACH_SERVO:
       AttachServo();
       break;  
     case SET_ANGLE:
       SetAngle();
       break;  
     case SET_ROTATION:
       SetRotation();
       break;
     case DETACH_SERVO:
       DetachServo();
       break;  
     case RUN_CONT_MSEC:
       RunContMsec();
       break;
     case SERVO_ATT:
       ServoAtt();
       break;
     case RUN_ANG_NB:
       RunAngNb();
       break;
     case STOP_CONT:
       StopCont(true);
       break;
     case VERSION:
       Version();
       break;
     case PING:
       Ping();
       break;  
     }
 
   Serial.flush();
   fComp = false;
   fProc = true;
   }
}

// There is some more code, not relevant
// removed because the message was over maximum size


Thanks

Gilles Plante

OK,

that was a code 18  :-/. Now works fine.

When coding is OK, results are OK  ;D.

Go Up