Comment configurer une communication point à point de type RS232 ?

NIVEAU 2

Objectifs

  • Mettre en œuvre une liaison RS232 bidirectionnelle entre le microcontroleur et l’ordinateur

Pré-requis

Protocole RS232

Utilisation et définition

Le protocole RS232 a longtemps été utilisé pour piloter des périphériques d’ordinateur (Modem, GBF, Oscilloscope…).

Il est encore utilisé pour sa simplicité de mise en oeuvre par la plupart des systèmes embarqués pour discuter avec un PC. La console Série d’Arduino par exemple passe par ce protocole, tout comme la discussion entre le PC et la carte Nucléo (voir tutoriel Déboguer son programme et utiliser l’affichage série).

C’est un protocole asynchrone de transfert de données point à point, c’est à dire pour que deux noeuds puissent discuter. Les échanges se font en Full-Duplex grâce à deux signaux distincts RX (réception) et TX (transmission).

Les débits maximaux admissibles sont d’environ 100 kbits/s pour des distances de l’ordre de 10 m maximum. Le taux de transfert doit être paramétré de manière identique entre l’émetteur et le récepteur, puisque la liaison est asynchrone (i.e. le signal d’horloge n’est pas transmis). La vitesse de transfert est souvent donné en baud (ou symbole par secondes). Dans le cas d’une liaison RS232, 1 baud = 1 bit/s.

Trame de données

Voici une trame RS232 :

Lorsqu’aucun message n’est transmis, le bus est à l’état de repos (ou IDLE STATE en anglais). Le signal TX est à l’état ‘1’.

Lors de l’envoi d’un message, un START bit (‘0’) débute la transmission. De la même façon, un STOP bit la termine. La donnée utile est composée d’un octet. Pour transmettre plusieurs données, il faut reproduire ce motif autant de fois que nécessaire.

Dans la transmission des données, le protocole impose de transmettre du bit de poids faible (LSB) jusqu’au bit de poids fort (MSB).

Mise en oeuvre avec une carte Nucléo

La carte Nucléo L476RG est équipée de 3 liaisons Série différentes, nommées Serial1, Serial2 et Serial3. Chacune de ces liaisons est équipée des signaux TX – transmission – et RX – réception.

La liaison Serial2 semble toutefois être la liaison principale, utilisée notamment par le cable USB (par l’intermédiaire d’un convertisseur vers RS232 simulé). Ainsi les broches Serial2_TX et Serial2_RX correspondent respectivement à USB_TX et USB_RX. Elles se trouvent sur les broches D1 et D0 (qui ne sont alors pas utilisables comme sorties numériques standard).

Connexion RS232 sur la carte Nucleo L476RG

Chacune des liaisons série proposées précédemment possède 2 fils :

  • TX : Broche de transmission – sortie
  • RX : Broche de réception – entrée

Pour pouvoir relier les deux noeuds ensemble via le protocole RS232, on peut réaliser le cablage suivant (quelque soit le bus série utilisé) :

On peut noter que la sortie TX d’un noeud est branchée à l’entrée RX de l’autre noeud. Les deux canaux de communication sont (presque) indépendants. Les données peuvent donc aller dans les deux sens en même temps (Full-Duplex).

RS232-LOGIC vs RS232 standard

La représentation précédente ne tient pas compte de la vraie norme RS232, qui impose également des niveaux de tensions particulier sur les lignes RX et TX.

Lorsqu’un ‘0’ est traduit par une tension de 0V et qu’un ‘1’ est traduit par une tension de 5V (par exemple, ou 3.3V dans le cas de la carte Nucléo), on parle d’une liaison logique. Vous trouverez aussi par exemple RS232-TTL (TTL étant une norme également de circuit logique dont la tension d’alimentation est de 5V).

Pour gagner en immunité aux bruits et par le fait en qualité de transmission des données, la norme RS232 impose des tensions positives et négatives comprises entre 3V et 25V (en valeur absolue). Un niveau logique ‘0’ est représenté par une tension de +3V à +25V et un niveau logique ‘1’ par une tension de -3V à -25V. Souvent, des niveaux de +12V et -12V sont utilisés.

Oscillogramme de la transmission du caractère K (01001011), avec un bit de départ et un bit d’arrêt – Wikipedia / RS232

Il est donc souvent nécessaire pour discuter avec un élément de type RS232 d’un composant permettant l’adaptation de tension entre la partie logique (celle qui sort réellement d’un microcontroleur) et le bus. On trouve des composants déjà intégrés de type MAX232.

Configuration des broches

L’ensemble des classes et des fonctions permettant de réaliser des opérations avec les modules du microcontroleur se trouvent dans la bibliothèque “mbed.h (ou “mbed-os.h”). Il est donc indispensable d’avoir au préalable inclut cette bibliothèque :

#include "mbed.h"

Déclaration des entrées/sorties

La première étape est la déclaration des broches utilisées pour la liaison RS232. Il faut la placer après la déclaration des ressources externes (bibliothèques) et avant toute définition de fonction (voir tutoriel Tester mon premier programme sur Nucléo – Code d’exemple /* Déclaration des entrées/sorties */).

Serial my_pc(USBTX, USBRX);

Pour cela, on déclare, à l’aide du constructeur de la classe Serial, le nom de la liaison dans le reste du programme (ici la variable my_pc) et les broches TX et RX à utiliser sur la carte.

N.B. Dans l’exemple précédent, on utilise les broches TX et RX associées à la liaison USB (ce n’est en fait qu’une version simulée d’une liaison RS232 via le protocole USB). Il s’agit en fait des broches Serial2_TX et Serial2_RX (qui ne sont alors plus utilisables pour d’autres signaux).

Pour pouvoir visualiser les signaux, il faut se connecter sur les broches indiquées ci-dessous :

Il existe d’autres broches qui permettent la communication RS232 sur la carte Nucléo :

  • Serial 1 : A4 (TX) / A5 (RX)
  • Serial 4 : A0 (TX) / A1 (RX)

Configuration de la vitesse de transmission

Avec le compilateur MBED, il est possible de changer la vitesse de transmission, à l’aide de la fonction baud de la classe Serial.

my_pc.baud(115200);

Dans l’exemple ci-dessus, on paramètre la liaison pour qu’elle émette à 115200 bauds. Il faut penser à adapter cette valeur en fonction de la vitesse de transmission qu’est capable d’utiliser le noeud associé.

Remarque Il existe également une fonction format de la classe Serial qui permet de configurer d’autres paramètres (nombre de bits transmis, utilisation d’un bit de parité…).

Envoi d’un message depuis la carte Nucléo

On va pouvoir transmettre un message de deux façons différentes (les fonctions sont liées à la classe Serial) :

  • un seul caractère (ou donnée sur 1 octet) à la fois : fonction putc
  • une chaine de caractères formatée : fonction printf
  • un ensemble d’octets stockés dans un tableau de données : fonction write (non abordée ici)

Dans les deux exemples ci-après, un message est transmis au PC par l’intermédiaire du cable USB. Sur le PC, il faut penser à ouvrir un terminal série (type Teraterm) et le paramètrer pour écouter la liaison correspondante.

Envoi caractère par caractère

Dans cet exemple, on envoie caractère par caractère l’ensemble du message par l’intermédiaire de la fonction putc de la classe Serial.

#include "mbed.h"

Serial pc(USBTX, USBRX);
char i;

int main() {
    i = 0;
    pc.baud(115200);
    pc.putc('I');
    pc.putc('o');
    pc.putc('G');
    pc.putc('s');
    pc.putc('\r');
    pc.putc('\n');
    
    while(1){
        i++;
        pc.putc(i);
        pc.putc(' ');
        wait(0.1);
    }
}

Cet exemple permet d’afficher l’ensemble des caractères ASCII dans la console de l’ordinateur connecté à la carte Nucléo. Attention, certains ne sont pas affichables…

Envoi d’une chaîne de caractères formatée

Dans cet exemple, on envoie une chaine de caractère formatée par l’intermédiaire de la fonction printf de la classe Serial.

#include "mbed.h"

Serial pc(USBTX, USBRX);
int i;

int main() {
    i = 0;
    pc.baud(115200);
    pc.printf("Bienvenue a l'IOGS - 2019-2020 \r\n");
    
    while(1){
        i++;
        pc.printf("i = %d \r\n", i);
        wait(0.5);
    }
}

Dans cet exemple, on affiche la valeur d’un compteur i qui s’incrémente toutes les 500 ms.

Remarque Il existe une autre fonction permettant d’envoyer une chaîne de caractères (stockée sous forme de tableau de caractères) qui est la fonction puts de la classe Serial. Elle prend un argument qui est un tableau de caractères. Ce tableau doit nécessairement contenir le caratère de fin de chaine (‘\0’). Elle s’utilise par exemple en complément des fonctions strcpy ou sprintf.

Réception d’un message depuis la carte Nucléo

De la même façon que pour émettre une donnée sur la liaison série, il existe des fonctions permettant de récupérer des données (dans la classe Serial) :

  • scanf : pour récupérer une chaine de caractères formatée
  • gets : pour récupérer une chaine de caractères
  • getc : pour récupérer un caractère

Il existe également deux façons de récupérer une information sur une liaison série :

  • par scrutation, par le biais de la fonction readable de la classe Serial qui permet de savoir quand une donnée est prête (liaison asynchrone)
  • par interruption, par le biais de la fonction attach de la classe Serial, qui permet d’associer à un évènement de réception une fonction spécifique de récupération des données

Réception par scrutation

Dans l’exemple suivant, on va récupérer successivement un entier, une valeur réelle et 5 caractères (maximum).

#include "mbed.h"

Serial pc(USBTX, USBRX);

int main() {
    double rc;
    int rx_receive;
    char data[5];
    pc.baud(115200);
    
    while(1){
        if (pc.readable()) {
            pc.scanf("%d %lf", &rx_receive, &rc);
            pc.scanf("%s", data);
        }
    }
}

La fonction readable de la classe Serial permet de savoir si une donnée est prête (reçue).

Réception par interruption

Dans l’exemple suivant, une routine d’interruption va venir récupérer un caractère (getc) et le renvoyer (putc) sur la même liaison.

#include "mbed.h"

Serial pc(USBTX, USBRX);
 
void rx_getData() {
    pc.putc(pc.getc());
}
 
 
int main() {
    pc.baud(115200);
    pc.attach(&rx_getData);
    pc.printf("Echoes back to the screen anything you type\n");
 
    while(1) {}
}

Tutoriel lié

MInE Prototyper Prototyper avec Nucleo et MBED

Nucléo – Configurer une communication point à point de type RS232