BTS Mesure BTS Mesure
DébutTP 1UARTLED RGBBilanCapteursDataloggingStationUltrasonCAN seriePontRégulationCO2

La liaison série asynchrone

Un UART, pour Universal Asynchronous Receiver Transmitter, est un émetteur-récepteur asynchrone universel.  En voici le principe pour un Arduino :

  • Transmission de données d'un équipement 1 (un microcontrôleur Arduino) à un équipement 2 (PC, GPS, émetteur Bluetooth, microcontrôleur ....) .
  • Données à transmettre existent sous forme parallèle (octet) et sont transmises sous forme série (LSB en premier)
  • Données reçues sous forme série (LSB en premier ...:-) puis reconditionnées sous forme d'octet.
  • Pour permettre une liaison plus rapide les données sont stockées dans un buffer (mémoire tampon) d'une capacité de 64 octets.
  • Entre 2 équipements les fils sont croisés : Tx1 relié à Rx2 et Tx2 relié à Rx1 (voir figure)
  • Les niveaux de tension sont de type TTL soit 0 V pour le niveau bas et +5V pour le niveau haut.
  • Asynchrone car aucune horloge (bit clock) n'est transmise entre l'emetteur et le récepteur. Le recepteur ignore quand il va recevoir une donnée.
  • Afin de faciliter l'interopérabilité entre périphériques  des vitesses de transmission sont normalisées par multiples et sous-multiples de 9600 baud,
  • l'unité baud correspondant à une vitesse de transmission de un bit par seconde.

 Avantages :         standardisée, universelle, pas cher
                               3 fils suffisent (émission Tx, réception Rx, masse GND) et souvent l'alimentation + 5 V  

Inconvénients : Assez lent. (maximum pour un Arduino : 115200 bauds)
                              Une liaison UART ne permet que de relier 2 équipements.

Constitution d'une trame UART Arduino :

  • un bit de start toujours à 0 : servant à la synchronisation du récepteur
  • les données : pour un code Ascii étendu 8 bits (un octet)
  • et un bit de stop toujours à 1

Le niveau logique de repos est le 1.

 

Test de la liaison UART

Nous avons voulu savoir comment fonctionnait physiquement la liaison UART.

Pour cela nous avons transmis le caractère "a" et observé à l'oscilloscope la patte Tx d'un Arduino Uno.

                         

Le code ASCII du caractère a est 97, soit 0x 61 en hexadécimal, soit 0b 0110 0001 en binaire.
                                                          0b 0110 0001 = 0x 61 = 6*161+ 1*160 = 96 + 1 = 97

Commentaire de l'oscillogramme obtenu :

  • A : Bit de Stop de la trame précédente
  • B : Bit de start de la nouvelle trame  a = (MSB)0110 0001(LSB),
                                                soit à l'envers (LSB)1000 0110(MSB)
  • les 4 bits de poids faible : C (LSB=1)  D (0)  E (0)   F (0)
  • les 4 bits de poids fort :     G (0)  H (1)   I (1)   J (MSB=0)
  • K : Bit de Stop de la trame étudiée

1-a) Pour réaliser ce test, copier le programme ci-dessus. Puis téléversez-le sur un Arduino uno.
        Visualiser à l'oscilloscope la transmission du caractère x

1-b) En déduire son code ASCII  et vérifier ce résultat dans la table ASCII ci-dessus.

Le baudrate de 8000 bit/s n'est pas standard.
Mais la durée de transmission d'un bit est alors de 1/8000 = 125 µs  ce qui correspond à une demi-division de l'oscilloscope (calibre 250 µs/div).

// Visualisation d'une trame série à l'oscilloscope

void setup() {
 Serial.begin(8000);
// Oscilloscope entre Tx->1 et GND calibre : 250 µs:div
}
void loop() {
  //Nous envoyons le caractère "a" code ASCII : 97 soit 0x61 soit 0b01100001
  // suivi d'un caractère nul pour bien isoler le "a" à l'oscilloscope
  Serial.write(97); // idendique à Serial.print("a"); ou à Serial.write(0x61);
  // Trame de  10 bits : Start : 0/LSB:1/0/0/0/0/1/1/MSB:0/Stop:1
  // durée de transmission d'un bit : 1/8000 = 0,125 ms = 125 µs soit 1/2 div
  // durée de la trame : 10*0.125ms = 1,25 ms   pour un octet soit 800 octets à la seconde
  Serial.write(0);
  }

Un capteur à sortie UART : le GPS

Pour visualiser des trames plus complexes l'oscilloscope n'est pas adapté.

 Un analyseur logique  et son logiciel associé Saleae permettent d'analyser tous les signaux numériques TTL (0 - 5 V).

Un capteur GPS UART utilise principalement 4 pattes :

  • VIN : alimentation + 5 V ;
  • GND : la masse ;
  • Rx : pour la réception de donnée, facultatif si on utilise les paramètres par défaut du GPS ;
  • Tx : transmission des données GPS, par défaut 9600 bit/s (baudrate), rafraichissement  des coordonnées 1 Hz.

Nous avons alimenté un capteur GPS entre GND et VIN=5V. Puis nous avons relié sa patte TX à notre analyseur logique  pour obtenir ce signal :

Dans une liaison UART pour transmettre un caractère Ascii (codé sur 1 octet) il faut  : 1 bit de start puis le code ASCII sur 8 bits (1 octet)  et un bit de stop soit 10 bits.
Une liaison 9600 bit/s transmet donc 960 caractères par seconde.

Pour plus de précisions sur le capteur GPS, consulter la page projet ballon 2016.

Le Bluetooth

On utilisera aussi la liaison série pour communiquer avec le microcontrôleur du HC06 qui est un émetteur Bluetooth. Et ainsi commander un Arduino avec un téléphone Android par liaison Bluetooth.

U=RI | Arduino Ep.17 - Application Android avec le module Bluetooth HC-06

Hello World !

Nous allons observer le temps de transmission nécessaire pour afficher un message : Hello world !

Réaliser le montage permettant d'observer à l'analyseur logique la sortie Tx (patte 1 ) d'un Arduino uno.

Téléverser sur cet Arduino Uno le programme ci-contre.

Ce message comporte 13 caractères + \r \n = 15 caractères Ascii

2-a) En théorie il faut combien de temps pour transmettre 15 caractères à 9600 bauds ?
       Mesurer ce temps sur l'Analyseur logique (penser à compter le dernier bit de stop (1)...)
       Temps de transmission = ......... ms

2-b) D'après la fenêtre série quel est le temps d'éxécution de Serial.println("Hello world !") ?

       Temps de transmission = ............ ms   
       Temps d'éxécution        = ............ ms

      
Comment expliquer cette différence ?

2-c) On ajoute la fonction Serial.flush()  juste après.
       Que devient le temps d'éxécution ?
       Comparer ce temps au temps de transmission ?
       Que fait la fonction Serial.flush()  ?

2-d) Augmenter la vitesse de transmission à 115200 baud.     Serial.begin(115200);
       Penser à changer aussi la vitesse sur le moniteur série !

    Est-ce que le temps d'éxécution change ?   (avec et sans la fonction Serial.flush();)
    Mesurer sur l'analyseur logique le temps de transmission = .... ms

unsigned long t0,t;

void setup() {
  // Initialisation
  Serial.begin(9600);  
}

void loop() {
  t0=micros(); // Top départ
  Serial.println("Hello world !");
  // Serial.flush();  // A quoi sert cette fonction ?
  t=micros()-t0;  // temps d'éxécution de Serial.println("Hello world !");
  delay(100);
  Serial.print("Temps d'execution =");
  Serial.print(t);Serial.println(" us");
  delay(1000);  
}

Les fonctions de la bibliothèque Serial

Pour utiliser la liaison série d'un Arduino nous allons utiliser la  bibliothèque (en anglais: librarie )  intégrée  Serial :

Fonctions

Description

Paramètres

 

  

Serial.begin(debit);

 

Fixe le débit de communication en nombre de caractères par seconde (l'unité est le baud) pour la communication série.

En cas d'utilisation du terminal série, IL FAUDRA FIXER LE MEME DEBIT dans la fenêtre du Terminal !

Cette fonction est placée dans le Setup.

int debit: debit de communication en caractères par seconde (ou baud).

 Pour communiquer avec l'ordinateur, utiliser l'un de ces débits : 300, 1200, 2400, 4800, 9600,
                14400, 19200, 28800, 38400, 57600, or 115200.

 

Serial.print(val)

 Serial.print(val, format)

 Serial.println(val)

 

 

Affiche les données sous le port série sous forme lisible pour les humains (texte ASCII).

Serial.println() ajoute un retour de chariot CR (code ASCII : 13) et un saut de ligne LF (10).

val: la valeur à afficher. N'importe quel type de données.

 

format : spécifie la base utilisée (pour les nombres entiers) ou le nombre de décimales (pour les nombres de type float)

  

Serial.write(val)

 

Ecrit des données binaires sur le port série. Ces données sont envoyées comme une série d'octet; pour envoyer les caractères correspondants aux chiffres d'un nombre, utiliser plutôt la fonction print().

 

val : une valeur à envoyer sous forme d'octet simple (code ASCII)

 

 Serial.available();

Renvoi le nombre d'octet disponible pour lecture dans la file d'attente (buffer) du port série, ou 0 si aucun caractère n'est disponible.
Si une donnée est arrivée, Serial.available() sera supérieur à 0.

La file d'attente du buffer peut recevoir jusqu'à 64 octets voir 128 ou 256 octets si l'on change les paramètres par défaut (ceci au détriment de la mémoire disponible).

 

 Aucun

 

 Serial.parseInt()

Retourne le premier entier (format unsigned long : de 0 à 4 294 967 295  = 232 - 1 ) contenu dans le buffer série. Les caractères qui ne sont pas des chiffres (notamment le signe -) sont ignorés. Serial.parseInt()  arrête de lire le buffer série au premier caractère qui n'est plus un chiffre.

 

 Aucun

Mise en application

Objectif : apprendre à utiliser la bibliothèque Serial en duplex.
                 Le moniteur série envoie des consignes à l'Arduino à 9600 bauds.
                 L'Arduino lui répond en confirmant avoir bien reçu la consigne.

3-a)

  • Si n < 1 alors n =1
  • Si n > 10 alors n = 10
  • affiche sur le moniteur série : "Nombre reçu : n"
  • puis fait clignoter n fois la led, période de 500 ms

Vous avez du mal à commencer ?

Les fonctions utiles pour ce cahier des chages :

pinMode(broche, mode) //mode: soit INPUT (entrée en anglais) (=0) ou OUTPUT (sortie en anglais) (=1) 
Serial.begin(debit); // le plus souvent on prend débit = 9600 bauds
Serial.available(); // renvoie le nombre d'octet disponible pour lecture dans la file d'attente (buffer) du port série, ou 0 si aucun caractère n'est disponible. 	  
Serial.print("Message ");
Serial.println("Message + retour ligne ");
n=Serial.parseInt(); // lit le premier entier disponible dans le buffer série
delay (ms); // ms : le nombre de millisecondes que dure la pause 
digitalWrite(broche, valeur)  // valeur : HIGH ou LOW (ou bien 1 ou 0) 
// Les structures de contrôle : 
if (uneVariable > 50){ // début du bloc d'instructions à éxécuter
  // faire quelque chose
} // fin du bloc d'instructions à éxécuter
for (initialisation; condition; incrementation) { // initialisation : i=0; condition : i<n; incrémentation : i++
//instruction(s)à exécuter n fois;
}
while(expression){ // tant que l'expression est vraie
  // instructions à effectuer
}
while (Serial.available()) Serial.read();   // Exemple pour Vider le buffer Serial
c=Serial.read(); // lit (et retire)le premier octet de donnée entrant disponible dans le buffer 

Arduino pour les nuls : affiche la structure du programme avec des commentaires.

Toujours en difficulté ?  Le corrigé.

3-b) Avec l'analyseur logique faites une capture des échanges entre le PC et l'Arduino sur les pattes Rx(0) et Tx(1) de l'Arduino
       Combien de temps s'écoule-t-il entre la réception de l'ordre sur la patte Rx et la transmission de la réponse de l'Arduino sur la patte Tx.

        Sauver votre capture de Saleae Logic des pattes Rx et Tx avec un analyseur Async Serial.      

Vous avez fini ? Comment utiliser un GPS avec un Arduino uno ?

4-a) Relier un GPS à un Analyseur logique.
        Pour cela alimenter le GPS en reliant Vin (GPS)  à 5V (Arduino)
                                                                    GND (GPS) à GND (Arduino)
        Une inversion d'alimentation entraine la destruction du GPS !
        Puis relier Tx à Ch1 de l'analyseur logique et observer.

Quel est le temps mis pour transmettre les coordonnées GPS ?

Les coordonnées sont rafraichies à quelle fréquence ?

4-b) On souhaite visualiser le message transmis par le GPS sur le moniteur série.

Réaliser un programme qui :

  • vérifie si un caractère est disponible sur le port série ;           Serial.available();

  • lit le caractère disponible sous forme de code ASCII  (a) ;      a=Serial.read();

  • affiche le caractère sur le moniteur série.                               Serial.write(a);        

 

Téléverser votre programme puis relier le Tx du GPS au Rx de l'Arduino.

Attention :  à chaque téléversement il ne faut pas que le Tx du GPS soit relié
                     sinon il y a un conflit entre le GPS et l'ordinateur qui se retrouvent reliés ensemble à la patte Tx de l'Arduino.

Dans la salle de classe, il faut ajouter une antenne au GPS et la placer à la fenêtre pour recevoir le signal.
Il faut aussi attendre que le fix soit fait (diode clignote rapidement : fix non réalisé)
Sur la fenêtre du moniteur série ci-contre, le fix n'est  pas encore réalisé (pas de coordonnées GPS transmises).

Analyser les trames NMEA reçues et déterminer les coordonnées GPS transmises.

Utiliser par exemple une trame RMC

Une autre trame très courante pour les bateaux est la RMC, qui donne l'heure, la latitude, la longitude, la date, ainsi que la vitesse et la route sur le fond mais pas l'altitude.

$GPRMC,053740.000,A,2503.6319,N,12136.0099,E,2.69,79.65,100106,,,A*53

$GPRMC       : type de trame
053740.000   : heure UTC exprimée en hhmmss.sss : 5h 37m 40s
A            : état A=données valides, V=données invalides
2503.6319    : Latitude exprimée en ddmm.mmmm : 25°03.6319' = 25°03'37,914"
N            : indicateur de latitude N=nord, S=sud
12136.0099   : Longitude exprimée en dddmm.mmmm : 121°36.0099' = 121°36'00,594"
E            : indicateur de longitude E=est, W=ouest
2.69         : vitesse sur le fond en nœuds (2,69 kn = 3,10 mph = 4,98 km/h)
79.65        : route sur le fond en degrés
100106       : date exprimée en qqmmaa : 10 janvier 2006
,            : déclinaison magnétique en degrés (souvent vide pour un GPS)
,            : sens de la déclinaison E=est, W=ouest (souvent vide pour un GPS)
A            : mode de positionnement A=autonome, D=DGPS, E=DR
*53          : somme de contrôle de parité au format hexadécimal[3] 

L'analyse des trames peut-être effectuée facilement par un Arduino grâce à la bibliothèque TinyGPS.

Si celle-ci n'est pas disponible sur votre poste, il faut l'importer après l'avoir téléchargée en cliquant sur ce lien.

Pour importer : Croquis/Importer bibliothèque/Ajpouter bibliothèque  puis Téléchargements/TinyGPS.zip

Exemple : un programme mini pour afficher les coordonnées GPS.

4-c) Testez puis modifier ce programme afin d'aficher l'altitude en plus de la latitude et longitude.
        Aidez-vous du descriptif des fonctions de la bibliothèque TinyGPS.

/* Programme mini pour afficher les coordonnées GPS sur un Arduino Uno
Il faut alimenter le GPS : GND(GPS) à GND (Arduino)
                           Vin (GPS) à 5 V (Arduino)
Il faut relier Tx (GPS) à Rx (Arduino)
Attention lors du téléversement il faut débrancher le fil Rx de l'Arduino
sinon il y a un conflit entre le GPS et l'ordinateur qui se retrouvent reliés ensemble à la patte Tx de l'Arduino.
*/

#include <TinyGPS.h> // La bibliothèque TinyGPS va analyser les trames GPS 

TinyGPS gps; // Création de l'objet GPS
int a;
float lat, lon;

void setup() {
  Serial.begin(9600);
 }
 
void loop() {
    if (Serial.available()){
      a = Serial.read();
      // Serial.write(a); // Pour Debuger et voir les trames GPS
      if (gps.encode(a)) lireGPS();   // Si TinyGPS a découvert une nouvelle trame, afficher les coordonnées  
          }
  }

void lireGPS() {
      gps.f_get_position(&lat, &lon);   // appel fonction de la bibliothèque TinyGPS
      Serial.println();                // Sauter une ligne
      Serial.print(lat,5);             // voir les coordonnées GPS
      Serial.print(",");Serial.println(lon,5);
    }  // D'autres fonctions sont disponibles : lire la vitesse, la date, l'altitude...