Introduction
J'ai régulièrement besoin de communiquer avec des périphériques via une liaison série (type UART). Ce mode de communication bas level est en effet courant dans le domaine de l'informatique industriel (automobile, aéronautique, bancaire, transport, etc). Cependant il n'est pas forcement aisé de faire des tests sans le périphérique communiquant en UART sous la main.
C'est ici que l'Arduino peut venir nous aider pour simuler un client dialoguant en UART. En effet on peut utiliser le port USB ou les GPIO pour établir une liaison série avec un ordinateur. La carte Arduino pourra donc se faire passer pour notre périphérique UART auprès de notre logiciel. On peut commencer avec un simulateur assez simple (envoyer la même commande en boucle). Puis améliorer le simulateur en variant les commandes envoyées selon la requête, stocker des données, etc. Le but de ce simulateur est de pouvoir vérifier le comportement de notre logiciel avec un équipement réel communiquant via la liaison série.
Selon le besoin, on établira la liaison série via le port USB de l'Arduino ou via les GPIO. Dans le cas des GPIO, il sera nécessaire d'ajouter un convertisseur USB entre les GPIO et l'ordinateur. Attention l'UART est un terme générique, il convient ensuite d'utiliser le bon protocole selon votre périphérique. Veillez donc à utiliser le bon convertisseur. Voici quelques exemples :
- RS-232 (tension de -12 V à +12 V)
- TTL-3.3V (tension de 0 V à 3.3 V)
- TTL-5V (tension de 0 V à 5 V)
De plus entre le RS-232 et le TTL, il ne s'agit pas uniquement d'une différence de plage de tension. La manière de représenté les bits 0 et 1 est également différente.
Paramètres de communication
Il est également nécessaire de définir les paramètres de communication de la liaison série :
- Vitesse de transmission (4800, 9600, 57600, 115200, ...)
- Bits de données (4, 7, 8, ...)
- Bit de parité (No, Even, Odd) No = aucune, Even = paire, Odd = impaire
- Bit de stop (1, 2)
La configuration la plus classique étant 9600/8-N-1. C'est à dire :
- Vitesse de 9600 bauds (9600)
- 8 bits de données (8)
- Pas de bit de parité (N)
- 1 bit de stop (1)
Dans notre exemple nous allons augmenter la vitesse de transfert pour être en 115200/8-N-1 bauds.
Exemple de trame série
Nous allons prendre l'exemple d'un périphérique qui envoie via l'UART une commande quand on appuie sur un bouton physique. Puis une deuxième commande quand on relâche le bouton. La trame comporte 4 octets. Elle est délimitée par un champ de start et un champ de end. Un octet de command permet d'indiquer la nature de la trame. Un octet de value permet de transmettre une information. Pas de CRC, checksum ou autre champ de contrôle ici pour garder l'exemple simple.
Octet | Nom | Valeur | Description |
---|---|---|---|
1 | start | 0x25 | Début de trame |
2 | command | 0x91 | Commande de type bouton |
3 | value | 0x01 ou 0x02 | État bouton (0x01: pressé, 0x02 relâché) |
4 | start | 0x0D | Fin de trame |
Voici les deux commandes traduites en code C pour l'Arduino :
byte msg_switch1_pressed[] = {
0x25, // byte 1 : start
0x91, // byte 2 : command
0x01, // byte 3 : value
0x0D // byte 4 : end
};
byte msg_switch1_released[] = {
0x25, // byte 1 : start
0x91, // byte 2 : command
0x02, // byte 3 : value
0x0D // byte 4 : end
};
Communiquer via le port USB
A noter que la communication se fait via le port USB (qui sera détecté comme un port COM série virtuel) mais également simultanément sur les pins 0 et 1. La section suivante indiquera comment utiliser d'autres pins GPIO que 0 et 1 pour établir une liaison série.
Pour établir une communication série via le port USB de l'Arduino, on utilise l'object Serial
dont les principales fonctions sont :
Serial.begin()
permet d'ouvrir le port série et de définir la vitesse de communication.Serial.write()
écrit des données sur le port série.Serial.read()
lit des donées sur le port série.Serial.available()
envois le nombre d'octets disponible pour la lecture.
Dans l'exemple ci-dessous, on ouvre le port série à 115200 bps dans le méthode setup()
. On envoie ensuite une commande "bouton pressé" puis une commande "bouton relâché" en boucle.
void setup() {
Serial.begin(115200);
}
void loop() {
delay(2000);
Serial.write(msg_switch1_pressed, sizeof(msg_switch1_pressed));
delay(1000);
Serial.writes(msg_switch1_released, sizeof(msg_switch1_released));
delay(1000);
}
Communiquer via les GPIO
Pour utiliser des pins de GPIO spécifiques pour notre liaison série nous devons utiliser la bibliothèque SoftwareSerial
. Attention : certaines cartes Arduino ont des limitations en termes de vitesse et de pins utilisables. Il n'est pas toujours possible d'utiliser n'importe quelles pins. Dans l'exemple suivant nous allons utiliser la pin 10 pour RX et la pin 11 pour TX.
#include <SoftwareSerial.h>
int rxPin = 10;
int txPin = 11;
SoftwareSerial serialUart(rxPin, txPin);
void setup() {
serialUart.begin(115200);
}
void loop() {
delay(2000);
serialUart.write(msg_switch1_pressed, sizeof(msg_switch1_pressed));
delay(1000);
serialUart.write(msg_switch1_released, sizeof(msg_switch1_released));
delay(1000);
}
Recevoir et afficher les trames sur PC linux
Une façon simple de tester notre liaison série Arduino est d'utiliser l'outil linux minicom
. Une fois l'Arduino branché au PC, il faudra trouvé son nom de périphérique (device name). La commande dmesg
affichant les messages kernel peut être utile pour trouver cette information. Exemple classique de nom de périphérique série sous linux :
- /dev/ttyACM0
- /dev/ttyUSB1
N'oubliez pas d'indiquer la même vitesse (115200 bps) que celle initialisée coté Arduino. L'option -H
permet d'afficher les trames en héxadécimal et non en ASCII.
# -D: device
# -b: baudrate
# -H: hexadecimal display
# -w: wrap lines
minicom -D /dev/ttyUSB1 -b 115200 -H -w