Protocole de communication série simple point à point

J’ai besoin d’un protocole de communication simple entre deux appareils (un PC et un microcontrôleur). Le PC doit envoyer des commandes et des parameters au micro. Le micro doit transmettre un tableau d’octets (données du capteur).

Les données doivent être protégées contre le bruit (en plus du contrôle de parité, je pense avoir besoin d’une autre méthode de correction des données).

Existe-t-il une solution standard pour ce faire? (Je n’ai besoin que d’une idée, pas de la solution complète).

PS Tout conseil est apprécié. PPS Désolé pour toute erreur de grammaire, j’espère que vous comprenez.

Edit 1. Je n’ai pas encore décidé si ce sera le protocole maître / esclave ou si les deux parties peuvent initier la communication. Le PC doit savoir quand le micro a fait un travail et peut envoyer des données. Il peut interroger continuellement le micro si des données sont prêtes ou si le micro peut envoyer des données, lorsqu’un travail est terminé. Je ne sais pas ce qui est meilleur et plus simple.

Edit 2. Protocole matériel et couche physique . Depuis la norme série RS-232 C utilisée sur le PC, je vais utiliser une communication asynchrone . Je n’utiliserai que des signaux RxD, TxD et GND. Je ne peux pas utiliser de câbles supplémentaires car le microcontrôleur AFAIK ne les prend pas en charge. BTW j’utilise la puce AVR ATmega128.

Je vais donc utiliser un débit en bauds fixe, 8 bits de données, 2 bits d’arrêt sans contrôle de parité (ou avec?).

Protocole de liaison de données . C’est ce que ma question concernait principalement. Merci d’avoir suggéré les protocoles HDLC , PPP et Modbus . Je vais faire des recherches à ce sujet.

Je voudrais utiliser HDLC . J’ai eu de la chance avec elle par le passé. Je voudrais un point à point série juste utiliser le cadrage asynchrone et oublier tous les autres trucs de contrôle car il serait probablement excessif.

En plus d’utiliser HDLC pour le cadrage du paquet. Je formate mon paquet comme suit. Voici comment les options sont transmises avec 802.11

U8 cmd; U8 len; u8 payload[len]; 

La taille totale de chaque paquet de commande est len ​​+2

Vous définissez ensuite des commandes comme

 #define TRIGGER_SENSOR 0x01 #define SENSOR_RESPONSE 0x02 

L’autre avantage est que vous pouvez append de nouvelles commandes et si vous concevez correctement votre parsingur pour ignorer les commandes non définies, vous aurez une compatibilité en amont.

Donc, rassembler le paquet ressemblerait à ceci.

  // total packet length minus flags len+4 U8 sflag; //0x7e start of packet end of packet flag from HDLC U8 cmd; //tells the other side what to do. U8 len; // payload length U8 payload[len]; // could be zero len U16 crc; U8 eflag; //end of frame flag 

Le système surveillera alors le stream série pour l’indicateur 0x7e et quand il est là, vérifiez la longueur pour voir s’il s’agit de pklen> = 4 et de pklen = len + 4 et que le crc est valide. Remarque: ne vous fiez pas seulement à la fonction de crc pour les petits paquets, vous obtiendrez beaucoup de faux positifs, mais vous vérifierez également la longueur. Si la longueur ou le crc ne correspondent pas, réinitialisez simplement la longueur et le crc et commencez par décoder le nouveau cadre. S’il s’agit d’une correspondance, copiez le paquet dans un nouveau tampon et transmettez-le à votre fonction de traitement des commandes. Toujours réinitialiser la longueur et le crc lorsqu’un drapeau est reçu.

Pour votre commande, utilisez la fonction cmd et len, puis utilisez un commutateur pour gérer chaque type de commande. J’exige également que certains événements envoient une réponse pour que le système se comporte comme un appel de procédure distante piloté par événement.

Ainsi, par exemple, le dispositif de détection peut avoir une timer ou répondre à une commande pour effectuer une lecture. Il formaterait alors un paquet et l’enverrait au PC et le PC répondrait qu’il a reçu le paquet. Si ce n’est pas le cas, le dispositif de détection pourrait renvoyer un délai d’attente.

De même, lorsque vous effectuez un transfert réseau, vous devez le concevoir comme une stack réseau comme le modèle OSI, car les points Foredecker n’oublient pas les éléments de la couche physique . Mon post avec le HDLC est la couche liaison de données et le traitement RPC et commande est la couche application .

Les protocoles RS232 sont délicats. La suggestion d’utiliser HDLC est bonne, mais ce n’est pas la solution complète. Il y a d’autres choses à décider:

  • Comment le débit en bauds entre les deux appareils sera-t-il déterminé? Autobuad? Prédéfini, ou définir expliquez?
  • Ferez-vous le contrôle de stream dans le logiciel ou le matériel ou les deux? Notez que si vous utilisez le contrôle de stream matériel, vous devez vous assurer que les câbles sont correctement construits.
  • En parlant de câbles, c’est une énorme douleur avec RS233. Selon l’appareil, vous devrez peut-être utiliser un câble direct ou un câble croisé ou une variante.
  • L’utilisation d’un mécanisme de contrôle de stream basé sur un logiciel peut être efficace car elle permet d’utiliser le câble le plus simple – trois câbles seulement (TX, RX et communs).
  • Choisissez-vous un mot de 7 ou 8 bits?
  • HW parité ou vérification des erreurs logicielles.

Je vous suggère de choisir 8 bits de données, aucune parité matérielle, 1 bit d’arrêt et d’utiliser un contrôle de stream basé sur le logiciel. Vous devez utiliser autobaud si votre matériel le prend en charge. Sinon, l’autobaud est difficile à faire dans un logiciel.

Il y a quelques bonnes réponses ici, voici quelques indications utiles:

Même si vos paquets ne sont pas séparés dans le temps, l’octet de synchronisation est un moyen essentiel de réduire le nombre d’endroits dont vous avez besoin pour créer un paquet. Vos appareils devront souvent gérer un tas de données indésirables (c’est-à-dire la fin d’un paquet en vol lorsqu’ils sont activés ou le résultat d’une collision matérielle). Sans octet de synchronisation, vous devrez essayer de créer un paquet à partir de chaque octet que vous recevez. L’octet de synchronisation signifie que seulement 1/255 octet de bruit aléatoire pourrait être le premier octet de votre paquet. Aussi FANTASTIQUE quand vous voulez espionner votre protocole.

Avoir une adresse sur vos paquets ou même juste un peu en disant master / slave ou pc / device est utile lorsque vous regardez les paquets via un outil de type snoop. Vous pouvez le faire en ayant un octet de synchronisation différent pour le PC que le DEVICE. En outre, cela signifie qu’un appareil ne répondra pas à son propre écho.

Vous voudrez peut-être examiner la correction d’erreur (telle que Hamming ). Vous empaquetez 8 bits de données dans un octet protégé de 12 bits. Chacun de ces 12 bits peut être retourné en route et les 8 bits d’origine récupérés. Utile pour le stockage de données (utilisé sur les CD) ou lorsque le périphérique ne peut pas être ré-envoyé facilement (liaisons satellite, RF unidirectionnelle).

Les numéros de paquets facilitent la vie. Un paquet envoyé porte un numéro, les réponses portent le même numéro et un drapeau indiquant “réponse”. Cela signifie que les paquets qui ne sont jamais arrivés (disons synchronisés) sont facilement détectés par l’expéditeur et en mode duplex intégral avec une liaison lente, deux commandes peuvent être envoyées avant la réception de la première réponse. Cela facilite également l’parsing de protocole (un tiers peut comprendre quels paquets ont été reçus sans connaître le protocole sous-jacent)

Avoir un seul maître est une simplification géniale. Cela dit, dans un environnement duplex intégral, peu importe. Il suffit de dire que vous devez toujours le faire, sauf si vous essayez d’économiser de l’énergie ou si vous faites quelque chose à la fin de l’appareil (état de l’entrée modifié, prêt à l’échantillon).

Ma suggestion est modbus. C’est un protocole standard efficace et simple pour la communication avec des appareils dotés de capteurs et de parameters (par exemple un API). Vous pouvez obtenir les spécifications à l’ adresse http://www.modbus.org . Il existe depuis 1979 et gagne en popularité, vous n’aurez aucun problème à trouver des exemples et des bibliothèques.

J’ai lu cette question il y a quelques mois, ayant exactement le même problème, et je n’ai pas trouvé quelque chose d’assez efficace pour un minuscule micro 8 bits avec de minuscules quantités de RAM. Donc, inspiré par CAN et LIN, j’ai construit quelque chose pour faire le travail. Je l’ai appelé MIN (Microcontroller Interconnect Network) et je l’ai téléchargé sur GitHub ici:

https://github.com/min-protocol/min

Il y a deux implémentations là-bas: une en C embarqué, une en Python pour un PC. Plus un petit programme de test “hello world” où le PC envoie des commandes et le firmware allume une LED. J’ai blogué à propos de la mise en place sur une carte Arduino ici:

https://kentindell.wordpress.com/2015/02/18/micrcontroller-interconnect-network-min-version-1-0/

MIN est assez simple. J’ai corrigé la représentation de la couche 0 (8 bits de données, 1 bit d’arrêt, pas de parité) mais j’ai laissé la vitesse de transmission ouverte. Chaque trame commence par trois octets 0xAA qui, en binary, sont 1010101010, un bon pulsetrain permettant de détecter automatiquement le débit si l’une des extrémités veut s’adapter dynamicment à l’autre. Les trames contiennent de 0 à 15 octets de données utiles, avec une sum de contrôle Fletcher de 16 bits, un octet de contrôle et un identificateur de 8 bits (pour indiquer à l’application ce que contiennent les données utiles).

Le protocole utilise le remplissage de caractères afin que 0xAA 0xAA 0xAA indique toujours le début de l’image. Cela signifie que si un périphérique sort de réinitialisation, il se synchronise toujours avec le début de l’image suivante (un objective de conception pour MIN n’a jamais été de laisser passer une image incomplète ou incorrecte). Cela signifie également qu’il n’est pas nécessaire d’avoir des contraintes de synchronisation inter-octets et inter-images spécifiques. Les détails complets du protocole sont dans le wiki de repo GitHub.

Il y a de la place pour des améliorations futures avec MIN. J’ai laissé quelques points de repère pour le passage des messages de bloc (4 bits de l’octet de contrôle sont réservés) et pour la négociation de capacités de plus haut niveau (l’identifiant 0xFF est réservé),

Voici un protocole alternatif:

 u8 Sync // A constant value which always marks the start of a packet u16 Length // Number of bytes in payload u8 Data[Length] // The payload u16 Crc // CRC 

Utilisez RS232 / UART, car le PC (port série) et le processeur (UART) peuvent déjà gérer cela avec un minimum de tracas (juste besoin d’une puce MAX232 ou similaire pour effectuer le décalage de niveau).

Et en utilisant RS232 / UART, vous n’avez pas à vous soucier de maître / esclave si ce n’est pas pertinent. Le contrôle de stream est disponible si nécessaire.

Logiciel PC suggéré: écrivez vous-même ou Docklight pour une surveillance et un contrôle simples (la version d’évaluation est gratuite).

Pour une meilleure vérification des erreurs, la plus simple est la vérification de la parité, ou si vous avez besoin de quelque chose de plus puissant, peut-être un codage convolutionnel .

En tout cas, quoi que vous fassiez: restz simple!

EDIT: L’ utilisation de RS232 avec un PC est encore plus simple qu’auparavant, car vous pouvez désormais importer des convertisseurs USB vers RS232 / TTL. Une extrémité entre dans la prise USB de votre PC et apparaît comme un port série normal; l’autre produit des signaux 5 V ou 3,3 V pouvant être connectés directement à votre processeur, sans aucun changement de niveau.

Nous avons utilisé TTL-232R-3V3 de FDTI Chip, qui fonctionne parfaitement pour ce type d’application.

Ma seule suggestion est que si vous avez besoin de protection contre le bruit, vous pouvez utiliser RS-422/485 en duplex intégral. Vous pouvez utiliser un CI similaire à celui de l’AVR, puis un convertisseur RS-232-> RS-422 côté PC, comme le 485PTBR ici . Si vous pouvez trouver ou fabriquer un câble blindé (deux paires blindées torsadées), vous aurez encore plus de protection. Et tout cela est invisible pour le micro et le PC – pas de changement de logiciel.

Quoi que vous fassiez, assurez-vous d’utiliser un système en duplex intégral et assurez-vous que les lignes d’activation en lecture / écriture sont activées sur le CI.

Vous pouvez regarder la Telemetry et son implémentation de bureau associée en python Pytelemetry

Caractéristiques principales

C’est un protocole basé sur PubSub , mais contrairement à MQTT, c’est un protocole point à point, pas de courtier .

Comme tout protocole pubsub, vous pouvez publier d’un bout à l’autre un topic et être notifié à l’autre extrémité sur ce sujet.

Sur le côté intégré, la publication sur un sujet est aussi simple que:

 publish("someTopic","someMessage") 

Pour les nombres:

 publish_f32("foo",1.23e-4) publish_u32("bar",56789) 

Cette façon d’envoyer des variables peut sembler limitée, mais la prochaine étape consiste à append une signification supplémentaire à l’parsing du sujet en procédant comme suit:

 // Add an indexing meaning to the topic publish("foo:1",45) // foo with index = 1 publish("foo:2",56) // foo with index = 2 // Add a grouping meaning to the topic publish("bar/foo",67) // foo is under group 'bar' // Combine publish("bar/foo:45",54) 

C’est bien si vous avez besoin d’envoyer des tableaux, des structures de données complexes, etc.

En outre, le modèle PubSub est génial en raison de sa flexibilité. Vous pouvez créer des applications maître / esclave, périphérique à appareil, etc.

Bibliothèque C Version GitHub

La bibliothèque C est très simple à append sur tout nouveau périphérique à condition que vous disposiez d’une bibliothèque UART décente.

Il vous suffit d’instancier une structure de données appelée TM_transport (définie par Telemetry ), et d’affecter les 4 pointeurs de fonction readable write writeable .

 // your device's uart library function signatures (usually you already have them) int32_t read(void * buf, uint32_t sizeToRead); int32_t readable(); int32_t write(void * buf, uint32_t sizeToWrite); int32_t writeable(); 

Pour utiliser la télémésortinge, il suffit d’append le code suivant

 // At the beginning of main function, this is the ONLY code you have to add to support a new device with telemetry TM_transport transport; transport.read = read; transport.write = write; transport.readable = readable; transport.writeable = writeable; // Init telemetry with the transport structure init_telemetry(&transport); // and you're good to start publishing publish_i32("foobar",... 

Bibliothèque Python Version PyPI

Du côté du bureau, il y a le module pytelemetry qui implémente le protocole.

Si vous connaissez python, le code suivant se connecte à un port série, publie une fois sur le sujet foo , imprime tous les sujets reçus pendant 3 secondes puis se termine.

 import runner import pytelemetry.pytelemetry as tm import pytelemetry.transports.serialtransport as transports import time transport = transports.SerialTransport() telemetry = tm.pytelemetry(transport) app = runner.Runner(transport,telemetry) def printer(topic, data): print(topic," : ", data) options = dict() options['port'] = "COM20" options['baudrate'] = 9600 app.connect(options) telemetry.subscribe(None, printer) telemetry.publish('bar',1354,'int32') time.sleep(3) app.terminate() 

Si vous ne connaissez pas Python, vous pouvez utiliser l’interface de ligne de commande

Pytelemetry CLI Version PyPI

La ligne de commande peut être démarrée avec

 pytlm 

Vous pouvez ensuite vous connect , traiter les rubriques reçues, print données reçues sur un sujet, publier (publier) sur un sujet ou ouvrir un plot sur un sujet pour afficher les données reçues en temps réel.

entrer la description de l'image ici

entrer la description de l'image ici

En ce qui concerne les contrôles de parité (comme cela a été fait plusieurs fois ici):

Ils sont pour la plupart inutiles. Si vous craignez qu’un seul bit ne soit modifié par erreur, il est fort probable qu’un deuxième bit puisse également changer et vous obtiendrez un faux positif lors du contrôle de parité.

Utilisez quelque chose de léger comme le CRC16 avec une table de consultation – il peut être calculé à mesure que chaque octet est reçu et est essentiellement un XOR. La suggestion de Steve Melnikoff est excellente pour les petites micros.

Je suggère également de transmettre des données lisibles par l’homme, plutôt que des données binarys brutes (si la performance n’est pas votre première priorité). Cela rendra le débogage et les fichiers journaux beaucoup plus agréables.

Vous ne spécifiez pas exactement comment le microcontrôleur se comporte, mais tout ce qui est transmis depuis le micro sera-t-il une réponse directe à une commande du PC? Si c’est le cas, il semble que vous puissiez utiliser un protocole maître / esclave quelconque (ce sera généralement la solution la plus simple). Si les deux parties peuvent initier une communication, vous avez besoin d’un protocole de couche liaison de données plus général. HDLC est un protocole classique pour cela. Bien que le protocole complet soit probablement excessif pour vos besoins, vous pouvez par exemple au moins utiliser le même format de trame. Vous pouvez également consulter PPP pour voir s’il y a des parties utiles.

Peut-être que cette question peut être complètement stupide, mais est-ce que quelqu’un a envisagé d’utiliser l’un des protocoles X / Y / Z MODEM ?

Le principal avantage de l’utilisation de l’un des protocoles ci-dessus est la grande disponibilité des implémentations prêtes à l’emploi dans divers environnements de programmation.

SLIP et UDP. Sérieusement.

Tous les PC et appareils similaires le parlent.

Il y a un bon livre et des exemples de TCP Lean

Jeremy Bentham a sournoisement réussi à faire fonctionner un PIC / IP par un PIC. Un AVR est-il aussi bon qu’un PIC?

Je recommande plutôt UDP, c’est plutôt facile.