Pages: 1 2 [3] 4   Go Down
Author Topic: protocole de communication série bi-directionnel entre carte  (Read 3886 times)
0 Members and 1 Guest are viewing this topic.
Made in Belgium
Offline Offline
God Member
*****
Karma: 1
Posts: 756
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Je pense qu'au final il est beaucoup plus simple et rapide de manipulé des chiffres, octets, plutôt que des caractères qu'il faut parser, décoder et convertir ... (tout ça pour ça ...)
Pour développez un protocole simple à partir d'un tableau d'octet tu peux t'inspiré de ce que j'ai fais, déjà basé sur de l'existant.
Une petite description en fin du post http://arduino.cc/forum/index.php/topic,80422.msg612293.html#msg612293, facilement adaptable à différent cas .
Ici il faudra plutôt apprendre à manipuler les valeurs en base 10 (décimal) et 16 (hexadécimal), les tableaux simple, qu'est qu'un octet, qu'est qu'un bit, les types (char, int, byte, signé, non signé, ...), enfin les véritable bases de la base quoi.
Logged


Offline Offline
Full Member
***
Karma: 0
Posts: 113
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

J'ai vue ton code Osaka, franchement c'est très proche de ce que j'ai besoin de faire.

Je vais me limité à deux octets, donc déclenchement en interruption sur rx, réception des deux octets puis charger les variables. Ensuite revenir sur le programme principal, qui lui boucle toute les 18 à 20 ms max.

Si je puis me permettre, j'ai volontairement virer le start et le stop ainsi que le lenght. Tout dois passé par deux octets.

En espérant que ça reste réalisable, je ferais un début de code en m'inspirant du tien si tu me le permet.

Merci  smiley-mr-green
Logged

France
Offline Offline
Faraday Member
**
Karma: 39
Posts: 3610
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Si je puis me permettre, j'ai volontairement virer le start et le stop ainsi que le lenght
Ces informations ne sont pas là pour la décoration.
Il faut bien comprendre qu'une liaison série n'est pas fiable à 100%. on peut recevoir un caractère erroné voir même perdre un caractère. Dans ce cas le buffer de réception contient un message complètement faux et tu n'as aucun moyen de t'en apercevoir. Pire si tu perds un caractère dans une trame et que ton code attend de recevoir un caractère de plus pour avoir le bon compte de caractères  qu'il attend tu va te retrouver avec un caractère de la trame suivante et tu n'auras aucun moyen de le savoir et même si tu le savais comme tu n'as rien qui te dise où se trouve le début de ton message jamais tu n'arrivera à te recaler.

Lorsqu'on crée un système de messagerie il faut toujours envisager le cas où un caractère est perdu ou corrompu et estimer l'impact que cela peut avoir sur le programme et surtout trouver un moyen de retomber sur ses pieds une fois l'erreur détectée.
Logged

France
Offline Offline
Faraday Member
**
Karma: 39
Posts: 3610
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Roôôoo  .... un ptit tuto sur les pointeurs ?  smiley-mr-green 

Merci fdufnews   smiley-lol

Je vous suggère de lire cet article qui (à mon sens) présente clairement les pointeurs et leur fonctionnement. Et pourrait servir de base à une discussion.


Je crois qu'il est impossible d'échapper à l'utilisation des pointeurs car c'est entre autre un bon moyen d'échanger des variables entre des fonctions qui sont déclarées dans des librairies distinctes ou bien de passer des variables locales à d'autres fonctions pour qu'elles soient modifiées. Les fonctions de manipulation de chaine de caractères définies dans string.h reposent pratiquement toutes sur ce mécanisme.

Une analogie dans votre vie de tous les jours:
Pour donner (ou prendre) une information à M. X vous notez son adresse sur un papier , vous allez chez lui et vous donnez/prenez cette information.
Le papier (qui vous appartient c'est une variable locale) c'est le pointeur vers M. X (il contient son adresse) et tant que vous ne brulez pas le papier vous pourrez retourner chez lui.
Si vous voulez envoyer un copain chez cette même personne vous lui donner l'adresse, il la note sur un papier (variable locale au copain) et il peut à son tour aller chez M. X et lui donner/prendre des informations.
Du coup si, vous retournez chez M. X les informations qu'il aura à vous donner seront peut être différentes car elles auront pu être modifiées par votre copain s'il est allé le voir entre temps.

Si on étend ce raisonnement on peut dire qu'un carnet d'adresse est un tableau de pointeurs. Chaque ligne du carnet d'adresse contient une information qui permet de contacter une personne.
Logged

Offline Offline
Full Member
***
Karma: 0
Posts: 113
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok !

Donc si je comprend bien lenght et start + stop obligatoire...

Pour les pointeur je comprend parfaitement ce qui est mis. Mais en code ?
À la création d'un pointeur * est utilisé. Parfois on retrouve & . C'est austère.

Je ne fais pas la différence entre * et * et entre * et &. Mais il doit y avoir moyen de s'y retrouver. Particulièrement s'il y a plusieurs pointeurs.

M'enfin j'ai pas peur de demander. Et surtout d'apprendre. Donc à ce stade je propose de faire un post spécifique pour la question pointeur. Ceci évitera le mélange avec le parsing. L'un employant l'autre.

Merci d'y penser.
Logged

France
Offline Offline
Faraday Member
**
Karma: 39
Posts: 3610
There is an Arduino for that
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Donc si je comprend bien lenght et start + stop obligatoire...
Je dirais qu'à minima start est indispensable car c'est lui qui te confirme que tu tiens bien le début de ton message.
length et start c'est plutôt des sécurités qui te permettent de savoir que tu as reçu le nombre de caractères attendus lorsque tu arrives à la fin du message.

De toute les façons, un protocole de communication c'est toujours un compromis entre la sécurisation de la transmission et la garantie d'un débit.
Il y a des choix à faire:
   1) puis-je garantir qu'une erreur ne va pas me planter complètement mon logiciel ou bien risquer de détruire le matériel?
   2) est-ce que les sécurités que j'ai mis en place afin de robustifier ma liaison ne vont pas faire chuter mon débit et limiter la quantité d'informations utiles que je veux émettre.

Donc avant toutes choses il faut:
   1) évaluer la quantité d'informations que l'on veut récupérer à l'arrivée. Combien d'octets pour chaque message, récurrence des messages
   2) avoir une bonne idée du débit que l'on peut obtenir sur la liaison que l'on va utiliser. Cela dépend du support physique (fils simples, paires torsadées, paires torsadées blindées, ...), des niveaux électriques  (RS232, RS422, TTL,...) et de la distance
   3) criticités des informations transportées (l'allumage d'un voyant n'est pas être pas aussi important que l'activation d'une sécurité par exemple)
   4) capacités de traitement des informations à l'émission comme à l'arrivée (il faudrait pas non plus que ton processeur soit saturé par la gestion de la liaison de données et ne puisse plus rien faire à coté)

Avec ces informations tu peux estimer combien d'octets de contrôle tu peux ajouter à tes messages afin de sécuriser la liaison sans pour autant compromettre la bonne marche de ton application.
Logged

Offline Offline
God Member
*****
Karma: 5
Posts: 688
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Salut @ tous
Merci fdufnews pour ton lien , ça serai bien de l'integrer soit dans la rubrique TUTOS ou le Guide Arduino  ,je ne sais pas ce que vous en pensez ??
@+
William

P.S: je suppose qu'il y a sur ce site d'autres explications sur des questions posées sur le Forum ?  smiley-wink
Logged

The truth is elsewhere !!

Offline Offline
Full Member
***
Karma: 0
Posts: 113
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, donc je pense faire ceci:

Tout étant constituer d'octets, j'aurais la trame suivante:
[Start][Lenght][Data 1][Data 2][Data x][End]

1 - Cas ou j'ai des PWM: 3 octets.
2 - Cas ou j'ai des tout ou rien: 2 octets.

Principe de fonctionnement:
Au démarrage, je force chaque sorties avec des valeurs de base leurs correspondant. Ici c'est des PWM allant de 1 à 2ms.
On entre dans la boucle et toute les 18 à 20ms on prends chaque sorties les une derrières les autres et on écrit ce que l'on a dans les variables.

A partir de là, si on reçois quelque-chose sur RX, on passe en mode interruption, et on y reste le temps qu'on a pas reçu toute la trame de start + lenght à stop.
0x01 = Start
0x02 = Stop
Attention, un timer est quand même mis par sécurité afin de ne pas rester sur une erreur d'envoie. Charger la variable avec la donnée reçu. Revenir de l'interruption vers le programme principal.

Je pense codé sur 3 octets mes pulses. En effet, un octet pour choisit la sortie, un octet pour le premier chiffre, et un octet pour se second chiffre. Ainsi: si j'ai 1ms, 0x01 0x03 0x01 0x01 0x00 0x02.
Si j'ai 1,5ms, 0x01 0x03 0x01 0x01 0x05 0x02.
Et pour 2 ms : 0x01 0x03 0x01 0x02 0x00 0x02.

Soit une trame (S)(L)(var1)(var2)(var3)(E) donc varPwm = var2,var3 donc sortie var1 (varPwm). Je me trompe peut-être en mettant ça. C'est très théorique pour le moment afin de m'organiser. Je veux dire par la que je cherche à comprendre comment je vais faire pour que ce soit compréhensible. En même temps, là, il n'y a plus qu moi qui comprends.. Non ?

Pour mes lights c'est beaucoup plus simple bien sûr. Grâce au lenght, je peux lui dire je te place tel sortie à 0x01 ou 0x00. En 2 octets... Comme ceci:
0x01 0x02 0x08 0x01 0x02 soit (S)(L)(var1)(var2)(E) avec var1 la pin light et var2 la valeur 1 ou 0. Ici on allume la light.

Un détail me chagrine! Avons nous besoin d'un caractère d'espacement entre chaque valeurs d'octet ?  smiley-roll-sweat

Et bien maintenant, je vais commencer à travailler une une ébauche de tableau correspondant à mes varX, un tableau par sorties à affectés. En espérant que ce soit faisable sans trop de cafouillage.

AlienArea51, je suis bien d'accord avec toi. D'autant plus que c'est pas si compliqué mais que la représentation que l'on en fait dans le code peut-être difficile. Comme j'ai dit même si appeler Paul pour savoir ce que contient Jack est facile à comprendre, je ne sait toujours pas faire la différence entre * Paul et *. Peut être que si titi * fait référence à Jack alors titi * peut aussi faire référence à Martin, pour peu que l'on ai mis aussi un *Martin quelque-part. C'est ça qui me bloque et je pense ne pas être le seul smiley-wink

Merci en tout cas pour votre aide à la fois sur la compréhension de pointeur et pour ce qui est de ma communication entre carte.  smiley-lol
« Last Edit: April 07, 2012, 07:34:46 am by Geeks » Logged

Made in Belgium
Offline Offline
God Member
*****
Karma: 1
Posts: 756
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Donc si je comprend bien lenght et start + stop obligatoire...

C'est comme fdufnews l'indique, tout dépend du niveau de sécurité dont tu as besoin, il ne sera pas identique si ton arduino doit gérer un aquarium ou une centrale nucléaire.
start et stop permettent de "détecté" un début de trame et ajoute une petite sécurité sur la validité de la trame, je te garanti que rien n'est plus incertain que la bonne transmission et réception de donnée quelque soit le support.
Dans mon cas j'ai ajouter un crc16 qui a mon grand étonnement ne demande pas énormément de ressource, j'ai mesuré entre 400 et 500 micro seconde pour un calcul sur 5 octet.
Length est là pour des trames de longueur variable, s'assurer que la trame est complète mais également bien utile pour situé les données (ou ce trouve l'octet de fin de trame ?, etc), boucler cette trame rapidement hormis à la déclaration et réservation difficile de connaître la taille d'un tableau, etc, etc, ...  

Pour les pointeur je comprend parfaitement ce qui est mis. Mais en code ?
À la création d'un pointeur * est utilisé. Parfois on retrouve & . C'est austère.

Je ne fais pas la différence entre * et * et entre * et &. Mais il doit y avoir moyen de s'y retrouver. Particulièrement s'il y a plusieurs pointeurs.

il y a deux signification possible à * elles se situent soit à la déclaration soit à l'utilisation.

Code:
char unChar = 'a';
char *uneVariablePointeur; //Je déclare une variable de type pointeur de char
char *uneAutreVariablePointeur = &unChar; //je déclarare une variable de type pointeur de char et je l'initialise en lui donnant comme valeur l'adresse (&) de la variable unChar qui doit être de type char. (un pointeur pointe une adresse).
uneVariablePointeur = uneAutreVariablePointeur; //Je donne la valeur (une adresse) contenue dans uneAutreVariablePointeur (la valeur contenue dans mon pointeur étant l'adresse de unChar) à un autre pointeur de type pointeur de char uneVariablePointeur.Donc mes deux pointeur pointe sur la même variable unChar.
char unAutreChar = *uneAutreVariablePointeur ; //Je déclare une autre variable de type char et je l'initialise à la valeur situé à l'adresse contenue dans ma variable uneAutreVariablePointeur.


pour les fonctions, on reprend les même variable qu'au dessus.
Code:

maFonction(uneVariablePointeur); //je lui donne en paramètre la valeur contenue dans ma variable de type pointeur, donc l'adresse de ma variable de type char.
maFonction(&unChar); //je lui donne en paramètre l'adresse de ma variable de type char

char* maFonction(char* unPointeur) // Le paramètre est de type pointeur donc la valeur qui doit lui être passer est une adresse, s'il avait été de type int par exemple on aurais du lui transmettre un entier.
{
    *unPointeur = 'b'; //je modifie la valeur de la variable situé à l'adresse contenue dans mon pointeur
    return unPointeur; // je retourne un pointeur contenant l'adresse d'une variable
}

Dans les deux cas ma fonction demande une adresse

Citation du site du zero adapté:
Quote
   Sur une variable, comme la variable "unChar" :
        "unChar" signifie : "Je veux la valeur de la variable unChar".
        "&unChar" signifie : "Je veux l'adresse où se trouve la variable unChar".
    Sur un pointeur, comme "uneVariablePointeur" :
        "uneVariablePointeurr" signifie : "Je veux la valeur de uneVariablePointeur" (cette valeur étant une adresse).
        "*uneVariablePointeur" signifie : "Je veux la valeur de la variable qui se trouve à l'adresse contenue dans uneVariablePointeur"

« Last Edit: April 07, 2012, 03:57:21 am by osaka » Logged


Offline Offline
Full Member
***
Karma: 0
Posts: 113
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah wai, on comprends nettement mieux ainsi.

Bon, le CR16. J'avoue je ne connais pas  smiley-roll-sweat
On à l'air de dire que c'est rapide et facile, je suis loin d'être d'accord avec ça, d'autant plus qu'on a du mal à trouver ne serais-ce que quelques sources parlant d'un transfert fiable. a mon sens, l'I2C est bien plus simple d'autant plus que l'ack confirme la réception.
Logged

Made in Belgium
Offline Offline
God Member
*****
Karma: 1
Posts: 756
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Bon, le CR16. J'avoue je ne connais pas  smiley-roll-sweat

Et pourtant tu l'utilises tous les jours et même il y a 5 seconde, sur le protocole tcp/ip.
http://fr.wikipedia.org/wiki/Transmission_Control_Protocol#Somme_de_contr.C3.B4le
C'est une des principale différences entre le protocole tcp et udp.

On à l'air de dire que c'est rapide et facile, je suis loin d'être d'accord avec ça, d'autant plus qu'on a du mal à trouver ne serais-ce que quelques sources parlant d'un transfert fiable.

Il faut chercher du côté des protocoles domotiques (knx, plcbus, ...), automates (modbus, ...) , etc ...

a mon sens, l'I2C est bien plus simple d'autant plus que l'ack confirme la réception.

Ca a été le sujet de nombreuse discutions, la conclusion c'est que le choix ce fera selon le besoin,préférences et possibilités: longueur de bus, simple ou half et full duplex, maître-esclaves, vitesse, fiabilité, etc ...
Logged


Offline Offline
Full Member
***
Karma: 0
Posts: 113
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ah ben oui... Forcément !

J'avais pas capté que tu était parti sur un protocole déjà établi. Oh ben alors... il n'y a plus qu'à cherché  smiley-mr-green

Je pensait que c'étais arbitraire moi  smiley-roll-sweat et galères !

Bon, donc si je résume, je cherche un protocole qui me va bien, je me débrouille pour que ça puisse être réalisable avec mon rov, et puis go code. C'est peut-être plus simple que de se basé directement sur ton code. A moins de vouloir choisir autre chose.

Si je puis me permettre de renommé le sujet en "protocole de communication série bi-directionnel entre carte"... Ça me semble bien plus parlant désormais  smiley-wink
Logged

Made in Belgium
Offline Offline
God Member
*****
Karma: 1
Posts: 756
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

J'avais pas capté que tu était parti sur un protocole déjà établi. Oh ben alors... il n'y a plus qu'à cherché  smiley-mr-green

Je pensait que c'étais arbitraire moi  smiley-roll-sweat et galères !

Oui je me suis basé sur des protocoles existant dans le domaine de la domotique, automation, etc et d'ailleurs ils sont souvent similaire sur plusieurs points (logique le but et le développement est le même, tous gérer via µc, bus de terrain, ...).
Donc pas besoin de réinventé la roue, j'ai fais un mix de ce dont j'avais besoin et je l'ai adapté.
De loin tout ça peut paraître compliqué quand on a pas l'habitude, mais en y réfléchissant c'est totalement enfantin.  

Si je puis me permettre de renommé le sujet en "protocole de communication série bi-directionnel entre carte"... Ça me semble bien plus parlant désormais  smiley-wink

Je pense aussi après ce virage à 180° .  smiley-mr-green
Logged


Offline Offline
Full Member
***
Karma: 0
Posts: 113
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Il a été renommé  smiley

Bon, alors en fait, j'ai regardé un peu ce qui se faisait. Le plus approprié que j'ai scruté était une liaison par xbee pour 2 servo moteur. Mais j'aime pas bien l'idée du code que j'ai vue donc je l'ai ejecté.

Je m'interroge sur un point. Est-ce que on met une pause entre chaque octet ?

Dans ce cas, start / pause / lenght / pause / data 1 / pause / data 2 / pause / data 3 / pause / stop.

J'ai pas trouvé d'exemple encore de cr16 donc je ne l'ai pas inclue. Je pense que 2µs devrais être suffisant entre chaque octets.

Est-ce que quelqu'un saurais me dire ou me renseigner pour le cr16 ?

Merci d'y pensé.
Logged

Made in Belgium
Offline Offline
God Member
*****
Karma: 1
Posts: 756
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Je m'interroge sur un point. Est-ce que on met une pause entre chaque octet ?

Dans ce cas, start / pause / lenght / pause / data 1 / pause / data 2 / pause / data 3 / pause / stop.
Je pense que 2µs devrais être suffisant entre chaque octets.

Pourquoi une pause ?  smiley-confuse
A la transmition ou la réception ?

Est-ce que quelqu'un saurais me dire ou me renseigner pour le cr16 ?

Il y a un exemple ici dans mon code, voir les fonctions checkData et writeData.

http://arduino.cc/forum/index.php/topic,80422.msg720673.html#msg720673
http://arduino.cc/forum/index.php/topic,80422.msg723240.html#msg723240
« Last Edit: April 08, 2012, 07:42:33 am by osaka » Logged


Pages: 1 2 [3] 4   Go Up
Jump to: