Go Down

Topic: Arduino <== RS232 ==> Arduino (Read 20712 times) previous topic - next topic

osaka

#15
Apr 04, 2012, 12:04 am Last Edit: Apr 04, 2012, 12:13 am by osaka Reason: 1
Yop yop,


Si quelqu'un à une idée pour mes if, je suis preneur bien sûr ;)


Code: [Select]
if(Buffer=="[ON]")

valeur decimal du code ascii '[' == 91, ']' == 93
L'échange de trame sous forme de chaine je suis pas un grand fan, c'est lourd pour pas grand chose.
Un exemple simple de trame que je met en pratique http://arduino.cc/forum/index.php/topic,80422.msg616576.html#msg616576


Geeks

Oui, c'est ce que j'ai fait  :smiley-fat:
Code: [Select]

if(Buffer=="[ON]") {
      digitalWrite(13, HIGH);
    }
 
    if(Buffer=="[OFF]") {
      digitalWrite(13, LOW);
    }

osaka

#17
Apr 04, 2012, 12:18 am Last Edit: Apr 04, 2012, 12:23 am by osaka Reason: 1
Arf ce n'est pas aussi simple de comparé deux chaine ...

Par facilité utilisé la classe String http://arduino.cc/en/Reference/StringObject ou alors http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html

Dans le cas ici soit http://arduino.cc/en/Reference/StringEqualsIgnoreCase , soit http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html#ga60b6f90e97d0574c5f5725d9db15cd9d

Mais bon comme dans mon edit, utilisé les chaines de caractères (traitement lourd, mémoire, ...) pour de simple échange n'est pas ce qui ce fait de mieux quand on est sur µc.

Microbulle

Ben, oui, mais alors on est en désaccord avec le précédent code, sauf si après avoir constitué le Buffer, je le traduit en string.

1) créer le buffer en char
2) Buffer(char) to Variable(String)
3) Tester sur Variable(String)

Si c'est bon, comment transcrire du char en string ?

osaka

#19
Apr 04, 2012, 12:42 am Last Edit: Apr 04, 2012, 12:44 am by osaka Reason: 1
Tu n'est pas obligé de construire ton buffer en char mais directement un String, enfin je sais plus si la clase string peux prendre un tableau de char en paramètre constructeur.
Normalement ceci devrait marché
Via la classe String
Code: [Select]

   String str = "";
   while(Serial.available())
   {
       str+=(char)Serial.read();
   }
   
   if(str.equals("[ON]") )
   {
   }


sinon via la lib avr

Code: [Select]

 char Buffer[10];

   int x=0;
   while(Serial.available())
    {
     Buffer[x]=(char)Serial.read();
     x++;
   }
   
   if(strncmp(buffer, "[ON]", 4))
   {
   }


Pas vérifier mais ça devrait être quelque chose comme ça.
Attention avec ta boucle while(Serial.available()) rien ne dit que tu recevras bien toute la trame en 1 coup.

Geeks

Plop,

Bon , je viens d'essayer ceci :
Code: [Select]

//Carte Uno sous-marin

void setup() {
 
  Serial.begin(9600); //Lancer le mode série
 
  pinMode(13, OUTPUT);
 
  delay(50);
}

void loop() {
 
  String str = "";
 
  if(Serial.available()){
   
    delay(20);
   
    while(Serial.available()) {
     
      str+=(char)Serial.read();
    }
   
    if(str.equals("[ON]")) {
      digitalWrite(13, HIGH);
    }
 
    if(str.equals("[OFF]")) {
      digitalWrite(13, LOW);
    }
  }
}

Pourquoi je me suis lever les bras en l'air en criant "Ça marche ! Ça marche !"...

Merci pour le coup de pouce :)

A partir de là, je pense faire ceci:
- Si on a bien un signal -> if(Serial.available()){
- Si on a bien reçu le premier caractère "<"
- Boucler tant que l'on a pas reçu le dernier caractère ">"
- Récupérer la chaîne, parser les commandes "organe:numéro/option:valeur" Si pas d'option, se laisser la possibilité de mettre "organe:numero"

D'une manière générale, je vais faire un code tournant, c'est à dire passé commande par commande, plutôt que tout à la fois. Ainsi, j'aurais:
<Mot1:1.5>
<Mot2:1.5>
<Ser1:2>
<Ser2:1>
<Ser3:1.5>
<Pre1:Lock> ou <Pre1:Unlock>
<Lig1:On> ou <Lig1:Off> (pour les lights)

C'est qu'un exemple mais je pense que ça peut se faire, sinon, je part avec des valeurs fixes. Genre on envoie <00000000000000000000> On sait qu'on a une balise entrante, 20 caractères, balise fermante. Si on a une liaison défectueuse, à ce moment là, la uno aquite le défaut et passe en mode sécu. Vidage du ballast, mise en marche des feux d'erreurs.

barbudor

#21
Apr 04, 2012, 08:00 am Last Edit: Apr 04, 2012, 08:03 am by barbudor Reason: 1
Le code ci-dessus ne permet pas de se synchroniser en cas de perte de synchro.

Si les messages sont assez peu réguliers, le temps entre les messages peut suffir à se recaler.
Mais les messages arrivent à un rythme soutenu il faut d'abord chercher la synchro sur le marqueur de début.
Il est bien d'avoir un charactère de début et un différent pour la fin.
Que ce soit '[' et ']' comme ci-dessus ou par exemple '$' et '\n' dans les trames NMEA.

Comme dans beaucoup de cas, une solution propre et fiable passe par l'implémentation d'un automate simple.

Par exemple (code non testé car je suis en déplacement mais l'esprit y est):

Code: [Select]


// Variables globale
enum E_State { ATTENTE_SYNCHRO, LECTURE_MESSAGE } State = ATTENTE_SYNCHRO;

#define CHAR_DEBUT '['
#define CHAR_FIN ']'

String message;
int messageRecu = false;


// fonction a intégrer dans loop() ou dans serialEvent()
reception_serie()
{
 while ( Serial.available() )
 {
char c = Serial.read();
switch ( State )
{
case ATTENTE_SYNCHRO:
// Caractère de début : on commence a recevoir un nouveau message
message = "";
State = LECTURE_MESSAGE;
break;
case LECTURE_MESSAGE:
switch ( c )
{
case CHAR_DEBUT:
// Si on reçoit le caractère de debut, on repart sur un nouveau message
// Si un message était déjà en court de réception mais que l'on a perdu
// le caractère de fin, alors on poubellise le message incomplet car
// il est probablement inexploitable.
// Une autre politique peut être de considérer qu'un caractère de début
// en plein milieu d'une reception en cours agit à la fois :
// - comme un caratère de fin et lance le process de traitement du message
// - et comme un début de nouveau message
message = "";
State = LECTURE_MESSAGE;
break;
case CHAR_FIN;
// on signale a la boucle de traitement qu'il y a un message a traiter
messageRecu = true;
break;
default:
// tout autre caractère est ajouté au message en court
message += c;
}
}
 }
}

// Fonction de traitement des messages, a intégrer dans loop()
traitement_message()
{
if ( message_reçu )
{
// faire le boulot ici d'analyse du message
// notez que les characteres de début et fin ne sont plus dans le message
}
}


Pour info, l'utilisation de la classe String ci-dessus, bien que simplifiant le code n'est pas une bonne idée dans la pratique car le fait d'ajouter caractère par caractère va faire une utilisation abusive d'allocation/re-allocation dynamique de mémoire.
Il est plus efficace d'utiliser un tableau de char dimensionné suffisamment pour les message le plus grand et de gérer le non débordement de ce message.
Si besoin je peux revenir sur le code ci-dessus avec une telle méthode.

Si le code de réception est dans loop() (et non pas dans serialEvent()) alors il est possible d'appeller la fonction de traitement directement depuis le case CHAR_FIN.
Sinon, et si les messages peuvent arriver rapidemment, il peut etre prudent de gérer une FIFO de messages pour éviter que le message en cours de traitement soit effacé par un nouveau arrivant.
Mais comme l'Arduino n'est pas nativement multitâche ca ne devrait pas se produire.

Geeks

Oui, je suis d'accord avec toi. Mais je voulais d'abord validé le fait que la communication fonctionnais.

Maintenant que je sait comment émettre puis recevoir, il faut que je normalise. C'est vrai que Moteur et Light c'est pas le même nombre de caractère. Envoyer des chiffres, berc, incomprehensible alors que l'on peut se permettre mieux.

J'ai regardé ton code, wah, il est lourd et complet. Je voudrais vraiment simplifier.

Ok pour un tableau de char mais alors, il faut régler le souci des if. A propos, je transmet en clair l'ordre afin de soulager la uno, sauf dans certains cas.
Ok aussi pour gérer la perte de signal ou bien, le fait de recevoir plein de trame et de les traiter.

D'une manière générale, il faut moins de 100 ms entre traitement carte 1, liaison et traitement carte 2, exécution. Donc il faut vraiment que ça punch. Peut-être en passant par des fonctions de traitement. Genre, si je reçois quelque-chose j'appel la fonction de récupération de valeur, je retourne la valeur, je transmet la donnée au bon endroit, je passe à la suivante. Mais si entre temps j'ai reçu d'autres trames, c'est mort. L'autre solution, est de mettre en attente les envoies avec un <ack>. A ce moment la, le maître n'enverra la commande que si l'acquittement de réception à été donné par l'esclave.

Geeks

@ barbudor : Bon et bien, ton code ne fonctionne pas !!!!  :smiley-sweat:

Je pense que la logique y est mais pas le code  :smiley-mr-green:

Bon, ce que je vais faire, c'est dans le loop()
- Si pas d'opération, attendre un Serial.available()
-- Appeler la fonction réception, recevoir l'ordre 1 sous la forme "<Led1, on>" ou "<Led1, off>" par exemple.
-- Traiter l'opération par une fonction, Lancer un depuis une fonction Acknowledge "<ACK>"
- Boucler

Geeks

Bon et bien, je suis arrivé à un bout de quelque-chose...
Code: [Select]

//Carte Uno sous-marin

char commande[32];


void setup() {

  Serial.begin(9600); //Lancer le mode série
  pinMode(13, OUTPUT);
}

void loop() {

  if(readCommande() != 0) {
   
    Serial.println(commande);
   
    if(strcmp(commande, "<on>")==0) {
      digitalWrite(13, HIGH);
    }
    if(strcmp(commande, "<off>")==0) {
      digitalWrite(13, LOW);
    }
  }
  delay(20);
}

int readCommande() {
  if(!Serial.available()) {
    return 0;
  }
 
  int i=0;
 
  while(Serial.available()) {
    commande[i]=Serial.read();
    i++;
  }
 
  commande[i] = 0;
  return i;
}



Maintenant, il faut qu'au niveau de mon buffer, on puisse faire ceci:
"<" début de trame
">" fin de trame
"ordre, chiffre ou valeur" entre "<" ">"

Interdire tout autre traitement tant que le traitement en cours n'est pas effectif.

IliasHi

Bonjour a Tous je suis nouveau  , je voudrais avoir un peu d aide pour programmer sur Arduino .J ai un projet qui consiste a espionner des câbles sans modifier les données,pour moi c est la RS232. et j aimerai stocker les données de la liaison série dans un tableau mais je ne sais pas comment m y prendre. Voici ce que j ai fais juste pour lire des données :

#include <SoftwareSerial.h>

#define rxPin 2   // Je definis les broches Rx et Tx
#define txPin 3

SoftwareSerial softSerial =  SoftwareSerial(rxPin, txPin);

void setup()  {

 pinMode(rxPin, INPUT);//Configure les broches pour l entrée et la sortie
 //pinMode(txPin, OUTPUT);
 softSerial.begin(9600);

 Serial.begin(14000);
}

void loop() {

 int data = softSerial.read();
 Serial.println(data); ASCII
}


Go Up