Quand faut-il passer de l'ASCII aux protocoles série avancés?

28

Tous mes périphériques microcontrôleurs qui communiquent avec le PC via UART utilisent des chaînes ASCII pour envoyer des commandes et recevoir des données (comme implémenté dans Arduino). C'est ce que j'ai appris lorsque j'ai commencé à creuser dans l'électronique et j'ai toujours trouvé que l'envoi de chaînes nues était suffisant. Cependant, j'ai remarqué que la plupart des appareils que j'ai rencontrés utilisent des protocoles binaires sophistiqués qui incluent des codes de fonction, des adresses et une vérification des erreurs CRC.

Quand la communication ASCII de base est-elle acceptable et quand devrais-je envisager quelque chose de plus avancé, comme Modbus? Les appareils commerciaux utilisent-ils un tel ASCII? Industriel?

Je n'ai aucune idée de ce que je fais
la source
3
Réponse courte: lorsque votre application en a besoin. Oui, les appareils commerciaux utilisent ASCII. Prenons l'exemple du GPS NMEA. (Et encore une fois, je vais renvoyer ma propre question ici )
Eugene Sh.
1
Modbus a un mode ASCII. Voir le Guide de référence du protocole Modicon Modbus
Tut
@EugeneSh .: Il convient de noter que NMEA possède un champ de somme de contrôle, et la suppression d'une seule rafale d'échantillon en raison d'une défaillance de la somme de contrôle (ce qui se produit plus souvent que vous ne le pensez) n'est généralement pas une défaillance critique. Cela peut très bien ne pas être le cas pour d'autres protocoles ... et il existe de nombreux protocoles GPS binaires (par exemple Garmin) pour les applications dans lesquelles il peut en effet être critique (ou dans lesquels une fréquence d'échantillonnage supérieure à 1 Hz est requis, pour lequel NMEA est trop verbeux). Bien que cela ne fasse que renforcer votre point de vue.
Courses de légèreté avec Monica

Réponses:

28
  1. ASCII et CRC ne s'excluent pas mutuellement. ASCII est un codage et CRC sert à la vérification des erreurs.

  2. N'IMPORTE QUOI peut être envoyé en ASCII. Nous les anciens, nous nous souvenons certainement de UUEncoding, qui transforme n'importe quoi en chaîne ASCII.

  3. A) Pour moi, c'est généralement une question de vitesse et d'efficacité. L'envoi d'un grand nombre 32 bits par ASCII peut prendre beaucoup de temps, mais il ne prend que 4 octets pour l'envoyer en binaire via un protocole série.

    B) L'envoi de NUMÉROS via ASCII signifie que vous devez convertir le nombre en ASCII, ce qui est une étape supplémentaire claire (cela fait partie de ce que fait "printf").

  4. Si vous perdez votre place, visser, perdre le format, obtenir le mauvais endian, etc., un protocole de communication binaire peut certainement bousiller. Si vous envoyez de l'ASCII, il peut être plus facile de récupérer des erreurs en entrant simplement et en REGARDANT le flux de données.

Scott Seidman
la source
12
+1 pour "ASCII est un encodage". Ce n'est pas un protocole; les protocoles peuvent être construits sur ASCII.
Pete Becker
8
La récupération automatique à partir d'une erreur n'est pas intrinsèquement plus facile pour un protocole textuel que binaire, mais l'inspecter et le déboguer est certainement possible.
Nick Johnson
1
@NickJohnson - absolument. Une fois que vous êtes sur le point d'ouvrir un fichier dans un éditeur hexadécimal pour voir ce que vous pouvez récupérer, vous êtes déjà chez FUBAR en ce qui concerne SOP
Scott Seidman
1
@nickjohnson ce n'est pas vraiment vrai. ASCII vous offre de nombreuses options de trame / délimiteur hors bande pour faciliter la synchronisation et la récupération, ce qui nécessiterait un échappement supplémentaire, un bourrage de bits, un intervalle de temps ou d'autres astuces si le canal est utilisé pour des données binaires pleine largeur.
Chris Stratton
2
Je privilégie toujours l'ASCII lors de l'écriture de protocoles pour tous les avantages évidents (lisibilité, logabilité, etc.). Il y a deux cas où le binaire a plus de sens: premièrement, si la vitesse est un problème et que vous avez besoin du binaire pour entasser autant de données que possible dans le flux, et deuxièmement, marginalement, si vous essayez délibérément d'obscurcir ou même de chiffrer les données flux pour entraver ou empêcher la rétro-ingénierie. À cela, j'ai des protocoles binaires d'ingénierie inverse et cela m'a en grande partie plus irrité que réellement empêché l'acte.
J ...
10

Voici quelques réflexions à ce sujet:

  • ASCII est agréable car vous pouvez utiliser un moniteur série pour avoir un aperçu manuel de ce qui est envoyé.
  • si votre connexion n'est pas fiable, vous devez vous attendre à des erreurs de transmission et devez utiliser un CRC pour vérifier l'intégrité de chaque message reçu. Cela peut également être fait sur des messages ASCII.
  • si votre connexion est trop lente, vous pouvez réduire la taille de vos messages en passant au format binaire
  • Un format binaire spécialisé peut être plus facile à décoder du côté récepteur qu'en ASCII
MrSmith42
la source
7

Au niveau le plus simple, on pourrait dire qu'un protocole de communication simple comporte trois couches: physique, transport et application. (Il existe des modèles avec plus comme OSI avec 7 ou TCP / IP avec 4. Le nombre de couches n'est pas très important dans le contexte de cette question.)

La couche application est la couche avec laquelle vous traitez directement dans votre code et le centre de la question. En ce qui concerne la couche transport, l'octet que vous lui avez transmis dans send_data n'est qu'un modèle binaire, mais vous pouvez l'interpréter dans votre code d'application comme la lettre «A». Le CRC ou le calcul de la somme de contrôle sera le même, que vous considériez l'octet comme «A», 0x41 ou 0b01000001.

La couche de transport est le niveau du paquet, où vous avez vos en-têtes de message et la vérification des erreurs, que ce soit CRC ou une somme de contrôle de base. Dans le contexte du firmware, vous pouvez avoir une fonction telle que send_data, où vous lui passez un octet à envoyer. A l'intérieur de cette fonction, il a mis dans un paquet qui dit: "Hé, c'est un message normal, nécessite un accusé de réception, et la somme de contrôle est 0x47, l'heure actuelle est X." Ce paquet est envoyé sur la couche physique au nœud récepteur.

La couche physique est l'endroit où l'électronique et l'interface sont définies: connecteurs, niveaux de tension, synchronisation, etc. Cette couche peut aller de quelques traces exécutant des signaux TTL pour un UART de base sur un PCB à une paire différentielle entièrement isolée comme dans certains POUVEZ .

Au niveau du nœud de réception, le paquet arrive sur la couche physique, est décompressé au niveau de la couche de transport, puis votre modèle binaire est disponible pour la couche d'application. Il appartient à la couche d'application du nœud récepteur de savoir si ce modèle doit être interprété comme «A», 0x41 ou 0b01000001, et quoi en faire.

En conclusion, il est à peu près toujours acceptable d'envoyer des caractères ASCII si c'est ce que demande l'application. L'important est de comprendre votre schéma de communication et d'inclure un mécanisme de vérification des erreurs.

Matt Young
la source
Les protocoles Ascii peuvent également incorporer une somme de contrôle. J'ai rencontré des variations Hex-as-ascii, en utilisant une représentation ascii des nombres.
Eugene Sh.
@EugeneSh. Clarifié ce point
Matt Young
Pas pour faire une piqûre, mais TCP n'est pas quatre couches; il est considéré comme correspondant à la couche quatre du modèle OSI. Les communications série ne correspondent pas vraiment très bien au modèle OSI.
batsplatsterson
@batsplatsterson C'est tatillon, et assez peu pertinent au point que je fais.
Matt Young
5

Un point non encore mentionné est que si l'on utilise ASCII ou un protocole binaire, l'envoi d'un caractère d'effacement avant chaque paquet garantira que même si du bruit de ligne ou des erreurs de trame apparaissent avant le début d'un paquet, tous les caractères après le rub- la sortie sera correctement cadrée en l'absence de bruit supplémentaire. Sinon, si l'on envoie des paquets en continu et n'inclut aucun caractère qui est garanti pour atteindre la resynchronisation, il est possible qu'un problème puisse corrompre tout ce qui suit jusqu'à la prochaine pause de transmission. Le caractère 0xFF est agréable car il garantit que tout destinataire pourra se resynchroniser sur le caractère suivant.

(*) 0xFF - appelé effacement parce que quelqu'un qui tape un caractère erroné en tapant des données sur une bande de papier peut pousser le bouton "step tape backward" et appuyer sur effacement pour remplacer le caractère erronément perforé par 0xFF, qui ignoré par la plupart des destinataires).

supercat
la source
2

L'un des avantages de l'envoi de chaînes ASCII est que les codes de contrôle peuvent ensuite être utilisés pour signaler le début / la fin du message. Par exemple, STX (caractère 2) et ETX (caractère 3) peuvent signaler la transmission de début et la transmission de fin. Vous pouvez également ajouter un simple saut de ligne pour marquer la fin de la transmission.

Lors de l'envoi de données binaires, cela devient plus compliqué car aucun modèle binaire particulier ne peut être réservé à un code de contrôle (sans surcharge ou complexité supplémentaire) car un octet de données valide peut avoir le même modèle.

Transistor
la source
3
De nombreux protocoles binaires réservent un ou plusieurs modèles de bits en tant que codes de contrôle, mais ils incluent également un mécanisme d'échappement pour gérer ces codes lorsqu'ils apparaissent dans les données.
Dave Tweed
Vous pouvez réserver n'importe quel modèle pour marquer tout ce que vous voulez en binaire. Par exemple, je suis sur un projet avec un flux de données rapide et un flux de données lent sortant du même uart. J'ai réservé le plus grand int32 négatif comme indicateur pour mes données lentes, et je viens de saturer mes données négatives au plus grand négatif + 1.
Scott Seidman
D'accord. J'ai clarifié cela dans la réponse éditée, j'espère.
Transistor
2

ASCII est très bien, je l'utilise dans à peu près tous les projets. Cela facilite le débogage pour surveiller le port, et cela ne deviendrait un problème que s'il y avait beaucoup de données à envoyer.

Un autre bonus, j'utilise des appareils radio série pour faire passer des messages entre Arduinos, et je peux utiliser un moniteur série connecté à mon ordinateur portable et injecter des messages pour que certaines choses se produisent. Idéal pour les tests.

De plus, envoyer des choses en binaire n'est pas impossible à déboguer et selon vos outils, vous pouvez faire extraire et convertir le binaire en quelque chose de lisible par l'homme. Ou si vous savez ce que vous recherchez, vous pouvez inspecter visuellement le flux de données et reconnaître les valeurs là où elles devraient être et trouver des défauts de cette façon, mais pas si facilement. c'est-à-dire que vous reconnaîtrez les modèles d'octets et reconnaîtrez les valeurs attendues

Madivad
la source
2

Au lieu de Modbus, envisagez HDLC . Vous obtenez une détection d'erreur (ce qui est important sur les lignes série bruyantes). La synchronisation est robuste, l'échappement est robuste.

J'ai utilisé HDLC dans les réseaux RS-485 sans aucun problème et PPP l'utilise également.

teambob
la source
2
Ce serait bien si vous montriez pourquoi vous le suggérez via Modbus.
Je n'ai aucune idée de ce que je fais
1

ASCII sur l'UART est le plus populaire en partie parce que:

  • Il est lisible par l'homme lors du débogage (je n'ai pas encore vu un analyseur logique qui ne décode pas ASCII).

  • C'est très facile à mettre en œuvre, vous avez une table ASCII via google rapide qui est bien standardisée.

  • Il a intégré la synchronisation avec les bits de démarrage / d'arrêt.

  • À peu près tout le monde hobbyst s'est installé avec ASCII sur série, donc toutes les nouvelles méthodes devront y faire face, et ce n'est pas facile du tout.

Ensuite, vous vous retrouvez dans une situation où vous commencez à envoyer un codage spécifique, tel que l'envoi de la représentation en mémoire d'un flotteur par rapport à la conversion d'un flotteur en ASCII, envoyez-le sur série qui peut être bien plus de 4 octets, puis convertissez-le à nouveau. à une représentation en mémoire sur l'hôte. Au lieu de cela, vous envoyez simplement la représentation à 4 octets à chaque fois. Bien sûr, vous pouvez commencer à gérer l'encodage vous-même, mais vous devez ensuite configurer des balises de début / fin, l'ordre, etc.

Au lieu de cela, des choses comme Protobuf peuvent être utilisées. Cela a été utilisé dans un projet sur lequel je travaillais et c'était extrêmement bénéfique, il fait des messages de longueur variable, gère l'endian pour vous et quelques autres fonctionnalités intéressantes. La taille du code n'est pas aussi grande et vous pouvez spécifier tout ce qui doit être alloué statiquement au démarrage. Vous devrez cependant ajouter vous-même la somme de contrôle si vous en avez besoin.

hak8or
la source