Go Down

Topic: Communication: traitement trame entrante (Read 3156 times) previous topic - next topic

Bonjour,

existe-t-il un exemple de code ou librairie qui permet de décoder une trame comportant plusieurs informations et un controle CRC ?

merci...

Gromain
"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Vincent

Salut,

Peux tu donner plus de détail ? quelle type de trame veux tu décoder ?
Un tableau qui stock la trame avec quelques if et ça peut le faire dans certains cas, à condition de bien connaître le format de la trame.

a+

OK.

Pour être plus précis, l'objectif est d'envoyer et recevoir des trames au format pré-défini type:
<debut de trame><code emetteur><code destinataire><n° commande><parametre><CRC><fin de trame>
le nombre de bit ou d'octet étant à définir, ainsi que les caractères de début et de fin.
L'idée etant d'avoir une trame "standard" qui puisse être transmise par liaison série, I2C, ethernet... et décoder de manière simple par le destinataire.

C'est bien sur dans l'optique de mon projet domotique qui nécessitera de faire communiquer ensemble 1 PC et plusieurs arduino. Merci...
"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

guillaume b

Je pense que le mieux est de mettre la trame dans un tableau. Après, si tu connais le nombre exact de caractères ou d'octets de chacun des bouts de trame, suffit de compter, sinon tu peux utiliser des séparateurs.
Si tu récupère une chaine de caractère, tu peux tester le ou les caractères de début de trame comme ça :
if(strncmp(trame, début de trame, int nombre de caractères du début de trame)) { si c'est bon...}
Après tu peux découper ta chaine en faisant quelque chose du genre :

Quote

message = strtok (trame,"séparateur");
       z = 0;
       while (message != NULL)
       {
         tableau[z]=message;
         message = strtok (NULL, "séparateur");
         z++;
       }

Ceci marche dans le cas où chaque élément de ta trame est un seul octet. Dans ce cas la tableau[0] contient <debut de trame>, tableau[1] contient <code emetteur>.
Sinon ton tableau doit pouvoir contenir dans chaque case un élément entier.
Je ne sais pas si je sui très clair mais sa peut être un début de piste  :)

Vincent

Oui en gros c'est ça l'idée, si tu as un tableau qui contient la trame (trame[octet_dans_la_trame]), tu peux accéder à chaque élément, par exemple trame[0] = début_de_trame, trame[1] = code_emetteur, etc.
Après avec un jeu de if{} tu peux faire ce que tu veux : if(trame[1] == code_emetteur) {ton code}

alex57pupuce

salut, pour ton problème de trame, moi je me suis poser la meme question, et j'ai réussit a bidouiller quelque chose qui devrait t'interesser, le language de l'arduino est un dérivé du C ainsi, et j'ai juste rajouter la bibliothèque,    include <stdio.h>   j'ai pu utiliser sans problème sscanf   qui te permet avec 3 paramètre, (tableau de char, "format", destination) de parser et de récupérer les element de la trame.

une petite piste a explorer  ;)

#6
Aug 28, 2009, 02:04 pm Last Edit: Aug 28, 2009, 02:49 pm by Gromain59 Reason: 1
merci pour vos reponses.

Je fais des tests et je rencontre des problèmes:
lorsque j'envoie une trame depuis la console j'obtiens:

- le 1er octet de la trame isolé du reste
- jusqu'à 15 octets, puis nouveau paquet au delà
- des octets contenant la valeur codé en ASCII (donc pour envoyer une valeur "100", je reçois 3 octets (1,0,0). Donc à priori il me faudra convertir ces octets en valeurs décimale pour être exploitable.
La trame doit commencer par "D" et se terminer par "F".

Code: [Select]
// pour stocker la chaine de caractère envoyée par la liaison série
int tableau[32];
int buffer=0;
int nbrecar = 0;
boolean debut_trame = false; //caractere de debut de trame detecte


void setup() {
 Serial.begin(115200);           // set up Serial library at 9600 bps
 Serial.println("pret !");

}


// enregistre la chaine de caractère et indique le nombre de caractères lus
int readCommande()
{
 if(!Serial.available())
 {
   return 0;
 }

  int i = 0;
 
 // il faut lire chaque caractère 1 par 1

 nbrecar = Serial.available();
 for( i=0; i < nbrecar; i++ )
 {
 
 buffer=Serial.read();
 

 
 switch (buffer) { //debut reception trame
   case 'D':
     debut_trame = true; //flag caractere de debut detecte
     break; //fin de while
     //si debut trame on fait rien

   case 'F':
     debut_trame = false; //raz flag
     break; //fin de while
     break; //fin de boucle  
     
   default:
     if (debut_trame){ // si le debut de la trame a ete detecté
     tableau[i]=buffer; //on range l'octet recu dans le tableau
     }
  } //fin reception trame

 
}
return i;
}

void executeCommande()
{
 Serial.print("nbre de caractere recu: ");
 Serial.println(nbrecar);

int j =0;
for (j=0; j<16; j++){
 Serial.print(tableau[j]);
 Serial.print('/');
}
 Serial.println();

}

void loop()
{
 if (readCommande() != 0)
 {
   // si une commande complète est arrivée, on l'exécute
   executeCommande();
   }
}




alex57pupuce, je vais explorer cette piste... tu as un exemple de code ?
"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

alex57pupuce

salut, j'ai un exemple de code, j'ai un projet en cours, qui est expliquer dasns la section francais et régulation tension

voici le code de mon arduino mega
Code: [Select]
#include <stdio.h>

//valeur de timeout
int tps_max_lecture = 200;      //lecture d'un code, compteur max entre tout les caractère d'un code
int tps_max_carte = 1000;      //compteur max entre reception d'un caractère d'une autre carte arduino


int etatled[70]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int linkd[70]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};


int lecture(){            // lecture d'un code a 4 chiffre transformation d'une ligne de 4 caractère en int
     char buf[5]="    ";
     int timeout=0;
     int i=0;
     int n=0;
     while(i!=4){
           if(Serial.available()>0){
           buf[i] = Serial.read();
           i++;
           }
     timeout++;
     if(timeout>tps_max_lecture)
           return -1;
     }
     if(timeout> tps_max_lecture)
           return -1;
     sscanf(buf, "%d", &n);
     return n;
}


void setup(){            //initialisation de la carte
     int i;
     for(i=38;i<54;i++)            // sortie pour démultiplexeur
           pinMode(i,OUTPUT);
     for(i=2;i<14;i++)            //sortie mode PWM pour regulation tension
           pinMode(i,OUTPUT);
     for(i=20;i<38;i++)
           pinMode(i,INPUT);
     Serial.begin(9600);
     Serial1.begin(9600);
     Serial2.begin(9600);
     Serial3.begin(9600);
}


int changeVoltage(int opt1,int opt2){
     if(opt1<2 || opt1>14){
           Serial.println("erreur la sortie doit etre comprise entre 2 et 13");
           return -1;
     }
     if(opt2<0 || opt2>255){
           Serial.println("erreur la consigne doit etre comprise entre 0 et 255");
           return -1;
     }
     Serial.print("nouvelle consigne de : ");
     Serial.println(opt2);
     digitalWrite(opt1,opt2);
     return 1;
}




int readCard(int n){
     int i=0;
     int val = 0;
     int timeout = 0;
     switch(n){
           case 0 :
                 Serial.print("0 ");
                 for(i=20;i<38;i++)
                 {
                       if(etatled[i]==1){
                             Serial.print(i,DEC);
                             Serial.print(" ");
                       }
                 }
                 for(i=54;i<70;i++)
                 {
                       if(etatled[i]==1){
                             Serial.print(i,DEC);
                             Serial.print(" ");
                       }
                 }
                 Serial.println("99");
           break;
           case 1 :
                 Serial1.print(65,DEC);
                 while(1){
                       if(Serial1.available()>0){
                             break;            //debut emission autre cartes
                       }
                       timeout++;            //si pas de réponse -> erreur
                       if(timeout> tps_max_carte)
                             break;
                 }
                 if(timeout> tps_max_carte){
                       Serial.println("carte non présente ou probleme de connexion");
                       break;
                 }
                 while(1){
                       if(Serial1.available()>0){
                             val = Serial1.read();
                             Serial.println(val,DEC);
                             if(val==99){
                                   break;
                             }
                       }
                 }
           break;
           case 2 :
                 Serial2.print(65,DEC);
                 while(1){
                       if(Serial2.available()>0){
                             break;            //debut emission autre cartes
                       }
                       timeout++;            //si pas de réponse -> erreur
                       if(timeout> tps_max_carte)
                             break;
                 }
                 if(timeout> tps_max_carte){
                       Serial.println("carte non présente ou probleme de connexion");
                       break;
                 }
                 while(1){
                       if(Serial2.available()>0){
                             val = Serial2.read();
                             Serial.println(val,DEC);
                             if(val==99){
                                   break;
                             }
                       }
                 }
           break;
           case 3 :
                 Serial3.print(65,DEC);
                 while(1){
                       if(Serial3.available()>0){
                             break;            //debut emission autre cartes
                       }
                       timeout++;            //si pas de réponse -> erreur
                       if(timeout> tps_max_carte)
                             break;
                 }
                 if(timeout> tps_max_carte){
                       Serial.println("carte non présente ou probleme de connexion");
                       break;
                 }
                 while(1){
                       if(Serial3.available()>0){
                             val = Serial3.read();
                             Serial.println(val,DEC);
                             if(val==99){
                                   break;
                             }
                       }
                 }
           break;
           default:
                 Serial.println("numero de carte inconnu");
           break;
     }
}


int sortie(int n,int t){
     int i = 0;
     int NdemX = 3;      //numero demultiplexeur X
     int NdemY = 3;      //numero demultiplexeur Y
     int NX = 0;            //numero sortie X demultiplexeur
     int NY = 0;            //numero sortie Y demultiplexeur
     int X  = 0, Y = 0;
     Y = n / 64;
     X = n % 64;
     NX = X % 16;
     NY = Y % 16;
     if(X<48)
           NdemX=2;
     if(X<32)
           NdemX=1;
     if(X<16)
           NdemX=0;
     if(Y<48)
           NdemY=2;
     if(Y<32)
           NdemY=1;
     if(Y<16)
           NdemY=0;
     Serial.print("numero de sortie : ");
     Serial.println(n);
     Serial.print("numero demultiplexeur X : ");
     Serial.println(NdemX);
     Serial.print("numero demultiplexeur Y : ");
     Serial.println(NdemY);
     Serial.print("numero sortie X : ");
     Serial.println(NX);
     Serial.print("numero sortie Y : ");
     Serial.println(NY);
     Serial.print("numero colonne X : ");
     Serial.println(X);
     Serial.print("numero ligne Y : ");
     Serial.println(Y);


     //activation sortie Y ***************************************
     if(NY>=8){
           NY=NY-8;
           Serial.println(53);
           digitalWrite(53,HIGH);
     }
     if(NY>=4){
           NY=NY-4;
           Serial.println(52);
           digitalWrite(52,HIGH);
     }
     if(NY>=2){
           NY=NY-2;
           Serial.println(51);
           digitalWrite(51,HIGH);
     }
     if(NY>=1){
           NY=NY-1;
           Serial.println(50);
           digitalWrite(50,HIGH);
     }
     //activation sortie X ***************************************
     if(NX>=8){
           NX=NX-8;
           Serial.println(45);
           digitalWrite(45,HIGH);
     }
     if(NX>=4){
           NX=NX-4;
           Serial.println(44);
           digitalWrite(44,HIGH);
     }
     if(NX>=2){
           NX=NX-2;
           Serial.println(43);
           digitalWrite(43,HIGH);
     }
     if(NX>=1){
           NX=NX-1;
           Serial.println(42);
           digitalWrite(42,HIGH);
     }
     switch(NdemY){ //selection demultiplexeur ************************
           case 3 :
                 Serial.println(49);
                 digitalWrite(49,HIGH);
           break;
           case 2 :
                 Serial.println(48);
                 digitalWrite(48,HIGH);
           break;
           case 1 :
                 Serial.println(47);
                 digitalWrite(47,HIGH);
           break;
           case 0 :
                 Serial.println(46);
                 digitalWrite(46,HIGH);
           break;
     }

     switch(NdemX){
           case 3 :
                 Serial.println(41);
                 digitalWrite(41,HIGH);
                 delay(t);
                 digitalWrite(41,LOW);
           break;
           case 2 :
                 Serial.println(40);
                 digitalWrite(40,HIGH);
                 delay(t);
                 digitalWrite(40, LOW);
           break;
           case 1 :
                 Serial.println(39);
                 digitalWrite(39,HIGH);
                 delay(t);
                 digitalWrite(39, LOW);
           break;
           case 0 :
                 Serial.println(38);
                 digitalWrite(38,HIGH);
                 delay(t);
                 digitalWrite(38, LOW);
           break;
     }            
     for(i=38;i<54;i++)                        //mise de toute les sortie demultiplexeur à 0
           digitalWrite(i, LOW);
}



void loop(){
     int i=0;
     int etat = 0;
     int n = 0;
     int opt1 = 0;
     int opt2 = 0;
     if(Serial.available()>0){
           n = lecture();
           switch(n){
                 case 1:
                       Serial.print("activation sortie : ");
                       opt1 = lecture();
                       Serial.println(opt1);
                       if(opt1 >4095 || opt1 < 0){
                             Serial.println("erreur numero doit etre entre 0 et 4095");
                             break;
                       }      
                       sortie(opt1,200);
                 break;
                 case 2:
                       Serial.print("activation sortie : ");
                       opt1 = lecture();
                       opt2 = lecture();
                       if(opt1 >4095 || opt1 < 0){
                             Serial.println("erreur numero doit etre entre 0 et 4095");
                             break;
                       }
                       if(opt2 > 1000 || opt2 < 0){
                             Serial.println("erreur tps doit etre entre 0 et 1000ms");
                             break;
                       }
                       Serial.print(opt1);
                       Serial.print(" avec temps : ");
                       Serial.println(opt2);
                       sortie(opt1,opt2);
                 break;
                 case 3:
                       Serial.print("lecture entree carte : ");
                       opt1 = lecture();
                       Serial.println(opt1);
                       readCard(opt1);
                 break;
                 case 4:
                       Serial.print("changement de tension , tension numero : ");
                       opt1 = lecture();
                       opt2 = lecture();
                       Serial.println(opt1);
                       Serial.print("consigne : ");
                       Serial.println(opt2);
                       changeVoltage(opt1,opt2);
                 break;
                 default:
                       Serial.println("erreur code inconnu");
                 break;
           }
     }

/*      
     if(Serial1.available()>0){                  // si la carte brancher sur la liaison série 1 transmet quelque chose on la retransmet a l'ordinateur
           Serial.print("1 ");
           Serial.print(Serial1.read(),DEC);
           Serial.println(" 99");
     }
     if(Serial2.available()>0){
           Serial.print("2 ");
           Serial.print(Serial2.read(),DEC);
           Serial.println(" 99");
     }
     if(Serial3.available()>0){      
           Serial.print("3 ");
           Serial.print(Serial3.read(),DEC);
           Serial.println(" 99");
     }
     for(i=20;i<38;i++){      
           etat = digitalRead(i);                  // lecture etat entrée digital
           if(etat==LOW){
                 etatled[i]=0;
           }
           if(etat==HIGH){
                 if(etatled[i]==0){
                       etatled[i]=1;
                       linkd[i]=1;
                 }
           }
     }
     for(i=54;i<70;i++){                        //lecture etat entrée analogique
           etat = analogRead(i-54);
           if(etat<=500){
                 etatled[i]=0;
           }
           if(etat>500){
                 if(etatled[i]==0){
                       etatled[i]=1;
                       linkd[i]=1;
                 }
           }
     }
     for(i=20;i<38;i++){                        //envoie resultat entrée digital
           if(etatled[i]==1 && linkd[i]==1){
                 Serial.println(i,DEC);
                 linkd[i] = 0;
           }
     }
     for(i=54;i<70;i++){
           if(etatled[i]==1 && linkd[i]==1){      //envoie resultat entrée analogique
                 Serial.println(i,DEC);
                 linkd[i] = 0;
           }
     }
*/

}



regarde la fonction lecture plus précisement
en fait j'envoie que des code a 4 chiffre, car je peut actionner 4096 sortie avec le système que je compte connecter a mon arduino.

en gros je te conseillerais d'envoyer un chiffre qui dit a l'arduino la longueur qu'elle doit lire sur la liaison série. tu peux meme reprendre ma fonction. tu fait lire la trame en une seul fois puis tu utilise la fonction sscanf

sscanf( tableau , format, destination1, destination2...);

si tu regarde il y a un int timeout, il sert a compter le nombre de cycle que la carte fait pour recevoir les 4 caractère, si > 200 elle ne recoit plus de caractère donc on sort du while pour eviter de bloquer la carte. j'ai remarquer que la carte fait 3 a 4 cycle entre chaque caractère. donc tu peut estimer le nb de cycle qu'elle va faire pour recevoir la trame

alex57pupuce

exemple de trame : D 23 48 99 F dans un tableau de char : char tram[99];

char car1,car2;
int i1,i2,i3;

sscanf(tram,"%c %i %i %i %c",car1,i1,i2,i3,car2);

j'espère que tu auras compris cette exemple

Merci !

j'ai testé ton code avec succès, c'est tout à fait ce qu'il me faut.

Gromain
"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

alex57pupuce

de rien, quand on peut s'entraider il ne faut surtout pas hésiter ^^

#11
Aug 31, 2009, 03:42 pm Last Edit: Aug 31, 2009, 03:44 pm by Gromain59 Reason: 1
Bonjour,

Voici un code mettant en oeuvre sscanf:

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

//valeur de timeout
int tps_max_lecture = 200;      //lecture d'un code, compteur max entre tout les caractère d'un code
int tps_max_carte = 1000;      //compteur max entre reception d'un caractère d'une autre carte arduino

int consigne[]= {      // consigne niveau de sortie (0=100%)
0, // sortie 0
0, // sortie 1
0, // sortie 2
0, // sortie 3
0, // sortie 4
0, // sortie 5
0, // sortie 6
0, // sortie 7
};


void setup() {                                      // Debut du setup

// initialise la liaison série
Serial.begin(9600);

Serial.println("TRAME ATTENDUE: <espace>'D'/'numero de sortie'/'consigne'/'F'");

}                                                   // Fin du setup


void loop() {                        // Main Loop
 
     int n = 0;
     if(Serial.available()>0){
           n = lecture();
     }
 
}

int lecture(){            // lecture d'une trame type: " D/aaa/bbb/F"
                             // ou "D" caractere de debut de trame
                             // ou "aaaa" n° de sortie dont la consigne est a modifier
                             // ou "bbbb" nouvelle consigne de la sortie (entre 0 et 100%)

     char buf[15]="";
     int timeout=0;
     int i=0;
     int n1=0;
     int n2=0;
     char c1,c2;
     
     while(Serial.available()>0){
           if(i!=14){
           buf[i] = Serial.read();
//            Serial.print(buf[i]);
           i++;
           }

     timeout++;
     if(timeout>tps_max_lecture)
           {Serial.println("T1");
           return -1;
           }
     if(timeout> tps_max_lecture)
           {Serial.println("T2");
           return -2;
           }      
     }
     sscanf(buf, "%c/%d/%d/%c", &c1, &n1, &n2, &c2); //decodage trame
     
     if (c1=='D' && c2 == 'F'){ // on verifie si la trame commence bien par D et termine bien par F
           
           int nouv_cons=n2; // on stocke la nouvelle valeur pour la travailler ensuite
           
           nouv_cons=constrain(nouv_cons, 0, 100); // on borne la nouvelle valeur entre 0 et 100%
     
             consigne[n1]= nouv_cons;

                 Serial.print("sortie ");
                 Serial.print(n1);
                 Serial.print(" , nouvelle consigne de: ");                  
                 Serial.println(consigne[n1]);      
     
     } else // si caractere de debut ou de fin de trame non reconnu
     {
       Serial.print("trame inconnue ou incomplete: <<");
       Serial.print(buf);
       Serial.println(">>");
       }
     
     return i;
     
     }



Lorsque j'envoie une chaine de caractère depuis l'hyperterminal, je suis obligé d'ajouter un <espace> devant la chaine avant de l'envoyer (ex: " D/1/75/F"), sinon elle arrive tronquée.
Du coup, j'ai systématiquement une première trame vide (avec l'espace?) qui arrive avant la chaine de caractère.
Qu'en penses les experts ?

Sinon, ça marche bien.
"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

jeanot1314

Bonjour

Je ne comprends pas pourquoi vous envoyez des lettres dans votre trame... ou est la traduction ASCII ?
De plus, comment envoyez vous et recevez vous la trame? Par l'hyperterminal du programme arduino?
Je cherche à envoyer une trame comprenant les champs suivant :
-Un ID sur 16 bits : 0x0001 et 0x0002
-Un champ sur 8 bits qui correspond au numéro de la trame (il s'incrémente de 1 à chaque trame et retourne à 0 quand le compteur et au bout
-Un bit d'état sur 1 bit (0 ou 1)
-Un cheksum pour vérifier

merci d'avance pour vos réponses! ; )

Je vais tenter d'être clair...

La trame reçue est une chaine de caractère de x octets.
Ainsi, quand tu reçois "98" par exemple, ce sont 2 caractères ASCII, donc 2 octets contenant "9" et "8", et non un octet de valeur "98"
Comment savoir alors si tu as voulu envoyé "9" et "8" ou "98" ? Le séparateur genre "/" entre "9" et "8" permettra à la fonction sscanf de traiter correctement la trame en considérant que "9" et "8" sont 2 valeurs distinctes, et non le nombre "98".
sscanf décode ce que l'émetteur aura codé avec la fonction sprintf avant envoi. Bien sur, il faudra utiliser le même "masque" entre sscanf et sprintf.
Maintenant, si c'est toi l'émetteur, via la console série de l'IDE arduino, tu devras former une trame respectant le masque configuré dans sscanf.
Concernant "D" et "F", c'est pour reconnaitre la trame, ca permet d'ignorer les octets hors normes reçus  (parasites...)

voila.

Gromain
"pour résoudre un gros problème, il est souvent plus facile de le diviser en petits problèmes élémentaires..."

projet domotique xPLDuino
IRC: freenode #xplduino

Jean-François

#14
Feb 11, 2010, 08:06 pm Last Edit: Feb 11, 2010, 08:10 pm by jfs Reason: 1
Dans ce zip, il y a une appli pour arduino avec une liaison entre processing et Arduino, elle comporte un CRC :

http://www.freewebs.com/adub/Slice_Dice_xml_reader.zip
MacBook intel core 2 duo  os X snow Leopard 10.6<br/> eMac PPc G4  os X Leopard 10.5<br/>powerbook G4 os X Leopard 10.5
imac PPC G3 os X Pa

Go Up