Outils pour utilisateurs

Outils du site


tdcom1

TD Bus de communication : Utilisation de la liaison Série Asynchrone sur Arduino

Objectifs

  • Compréhension de la structure d'une trame série asynchrone
  • Génération de trame par Bit-bang via une broche GPIO
  • Utilisation de la librairie SoftSerial pour l'émulation de port série par GPIOs
  • Utilisation de FIFO
  • Compréhension du mécanisme de contrôle de flux matériel
  • Configuration à bas niveau de l'USART de l'Arduino (via les registres de l'ATMEGA328P)

Carte d'extension pour le TD/TP

fichiers eagle: https://bvdp.inetdoc.net/files/iut/td1_capt/carte-arduino-max3232-B-15.sch et https://bvdp.inetdoc.net/files/iut/td1_capt/carte-arduino-max3232-B-15.brd

La carte d'extension utilisé pour ce TD, connecte le port série matériel ainsi qu'un ensemble d'entrées/sorties à deux connecteurs DB-9 mâle et femelle afin que la carte puisse prendre au choix, le rôle de DCE ou DTE. Cette carte propose des cavaliers de configurations permettant d'utiliser le port série en mode intégré “UART HARD” (Jumper RX et TX à droite) ou en mode émulé “UART SOFT” (Jumper RX et TX à gauche). La carte intègre un composant PHY (LIRE LA DOC http://www.farnell.com/datasheets/70989.pdf , surtout la page 5) qui se charge de générer les tensions nécessaires au respect de la norme RS-232 (de l'ordre de +5.5v à -5.5v) à partir de la tension d'alimentation de la carte (5v dans ce cas).

Le composant PHY contient deux convertisseurs de TTL vers RS232 et deux convertisseurs de RS232 vers TTL: - Le niveau logique 1 (5V en niveau TTL) est représenté par une tension négative (entre -3V et -25V) coté RS232. - Le niveau logique 0 (0V en niveau TTL) est représenté par une tension positive (entre +3V et +25V) coté RS232.

Deux convertisseurs sont utilisés pour les signaux de données RX et TX et les deux autres sont utilisés pour les signaux de contrôle de FLUX RTS/CTS.

Les indicateurs RTS et CTS sont câblés sur des ports d'entrées/sorties de la carte et sont également reliés à des LED.

Lors de la programmation de la carte Arduino depuis l'IDE, il est nécessaire de configurer le cavalier RX en mode UART émulé ou bien de l'ouvrir (peut être changé après programmation).

Connectique utilisée pour le RS232

Les 2 figures suivantes montre le cablage d'un connecteur DE9 coté DTE (le PC):

bvdp.inetdoc.net_files_iut_td1_capt_rs232pinout_rs232-pinout.jpg

Dans le TP nous connecterons la carte arduino au PC via un cable droit. Le cablage se fera entre le DTE (PC) et l'arduino coté DCE tel qu'indiqué sur ce schéma:

Les schémas de cablage suivants sont indiqués pour référence: Le premier correspond à un cable croisé permettant de connecter deux DCE en connectique DE9:

Les deux schémas suivants illustrent la connectique DE25:

Les deux schémas suivants illustrent des cables pour relier des connectiques DE9 et DE25:

Exercice 2 : Liaison Série émulée

La librairie Serial fournie dans l'environnement Arduino utilise le périphérique UART intégré de l'Atmega328p. Il est aussi possible de programmer le microcontrôleur pour mimer le comportement d'une liaison asynchrone 1200 bauds, 8N1 en utilisant les entrées/sorties du microcontrôleur.

Construction de la trame série "à la main"

Dans cette exercice nous allons utiliser la sortie 6 de l'Arduino pour envoyer un caractère (TX) en respectant le format d'une trame série à 1200 bauds, 8N1. (start, 8-bit de données en commençant par le bit de poids faible, stop). Pour mimer cette communication, il est nécessaire de respecter les aspects temporels de celle-ci. Pour gérer l'aspect temporel nous utiliserons la fonction delayMicroseconds(delay), et l’interaction avec le port d'entrée sortie se fera avec la fonction digitalWrite(PIN, VAL). Vous devrez configurer la broche TX (pin 6 de l'arduino) en sortie et l'initialiser à la bonne valeur.

Pour la construction de la trame série, vous pouvez vous reporter au premier TD. Dans un premier temps vous devez formaliser la construction de cette trame en complétant la description suivante (on partira du principe que la ligne TX a été initialisée à 1). On considère ici une trame au format 8N1.

Vous veillerez à définir 2 variables:

  1. int TXPIN pour le numéro de la broche utilisée (ici 6).
  2. int DUREEBIT pour la durée du bit en microsecondes.

La séquence à réaliser est la suivante:

  1. Mettre la ligne TX à 0 (bit de start) en utilisant la fonction digitalWrite
  2. Attendre T µs (T étant le durée d'un bit) en utilisant la fonction delayMicroseconds
  3. Pour chaque bit (i ème bit) de l'octet à envoyer, en partant du bit de poids faible, faire
    1. Isoler le bit à la position i de l'octet (pensez à utiliser les masquages et décalages)
    2. Ecrire sur la sortie TX la valeur du bit, en utilisant la fonction digitalWrite
    3. Attendre T µs, en utilisant la fonction delayMicroseconds
  4. Mettre la ligne TX à 1 (bit de stop), en utilisant la fonction digitalWrite
  5. Attendre T µs (T étant la durée d'un bit), en utilisant la fonction delayMicroseconds

A partir de la description, codez la fonction void EnvoieCar(char c), c étant l'octet à envoyer. Une fois la fonction codée, faire un programme principal (fonction loop) qui envoie en boucle le caractère 0x55 ('U'), suivi d'un délai de 100ms. Une fois le code compilé et chargé sur la carte, connectez le câble série (disponible sur la table) au port DTE de la carte d'extension. Lisez la notice d'utilisation de miniterm pour tester. Relever les signaux à l'oscilloscope pour le signal TX de chaque coté du composant PHY MAX3232.

Après avoir vérifié le fonctionnement à 1200Bds, modifier la valeur de DUREEBIT pour obtenir un débit de 19200 Bauds. Configurer miniterm pour ce débit et observer que cela ne fonctionne pas. En analysant la trame à l'aide de l'oscilloscope, proposer une solution et la tester.

Ensuite, vous pouvez modifier la fonction loop pour envoyer les chiffres de 0 à 9 (codes ascii de cette séquence) sur cet UART. L'envoi de chaque chiffre devra être suivi d'un délai de 100ms.

Utilisation du terminal miniterm

Le logiciel miniterm permet de gérer la communication en mode texte sur une liaison série.

Lancer miniterm sur le port série 1 à 1200 Bauds au format 8N1 en tapant dans une console:

miniterm /dev/ttyS1 1200

Si les caractères émis par la carte arduino ne s'affichent pas dans miniterm, tenter de brancher l'autre cable série présent sur la table à la carte arduino.

Les caractères saisis dans la console miniterm sont normalement émis vers le port série. Pour accéder aux options, il faut taper la combinaisons de touches CTRL+t puis la touche de l'option. Pour quitter miniterm, presser successivement et rapidement les touches CTRL+AltrGr+).

Utilisation de la librairie SoftSerial

Le comportement que nous venons de décrire est en fait déjà codé (de manière plus optimisée) dans la librairie Arduino. Cette Librairie permet de créer un port série émulé en utilisant les entrées/sorties numériques 6 et 5 de la carte.

softSerial.ino
#include <SoftwareSerial.h>
 
SoftwareSerial mySerial(5, 6); //Création d'un port Série émulé nommé mySerial avec RX=pin 5, TX=pin 6
 
void setup()  
{
  mySerial.begin(4800); // configuration du baudrate à 4800 bauds
  mySerial.println("Hello, world?"); // Envoi de la chaîne terminée par un saut de ligne
}
 
void loop()
{
  char a ;
  if (mySerial.available()){
     a = mySerial.read();
     mySerial.write(a+1);
  }
}

Exécutez ce programme et expliquer son fonctionnement. Pour tester ce programme, vous devez avoir le câble série connecté au port DTE du shield d'extension et utiliser le terminal miniterm (voir exercice précédent)

Exercice 3 : Mise en oeuvre de Fifo

Dans cet exercice, nous allons utiliser les fifos décrites en cours et programmées en TD pour gérer une communication avec deux hotes pour lesquels le rythme de communication est différent (tant au niveau du baudrate que de la fréquence des échanges).

Cet exercice implique :

  • Le PC connecté à l'Arduino au travers de la liaison USB/Série, 115200 bauds, 8N1. Cette communication utilise la liaison série intégrée.
  • Le PC connecté connecté à l'arduino au travers du shield (côté DCE), 1200 bauds 8N1. Cette communication utilise la liaison série émulée SoftSerial (pensez à configurer les cavaliers du shield en position SOFT).

Dans cet exercice, le PC envoie un caractère 'X' sur la laison USB/Série (connectée à l'UART HARD), et l'arduino doit envoyer la phrase “Le caractère envoyé est X” sur la liaison UART SOFT comme le montre le schéma suivant:

Le trajet des données peux être représenté ainsi:

L'intégralité du code doit fonctionner avec des fonctions d'envoi non-bloquantes,

La fonction setup doit implémenter le comportement suivant :

  1. Configuration de l'UART matériel
  2. Configuration de l'UART logiciel
  3. Initialisation de la fifo
  4. Configuration de l'entrée/sortie A3 en sortie (que l'on visualise sur la led RTS du shield MAX232)

La boucle principale doit implémenter le fonctionnement suivant :

  1. Vérifier si un caractère est disponible sur l'UART matériel
    1. Réception d'un caractère sur l'UART matériel
    2. Écrire dans la fifo la phrase demandée (écriture caractère par caractère), à coder dans la fonction RemplirFifo
      1. Si l'écriture a échouée (débordement de Fifo), allumer la LED RTS
  2. Lire un caractère depuis la fifo, et si la lecture à réussie (fifo non vide):
    1. Écrire le caractère sur l'UART émulé

ATTENTION: veillez à bien configurer la console Arduino en 115200 Bauds et option: Pas de fin de ligne

testFifo.ino
char  inByte = 0;         // incoming serial byte
 
const int rtsPin = 16;
const int ctsPin = 17;
 
#include <SoftwareSerial.h>
 
char ChaineEmission[]="\r\nLe caractere envoye est ";
 
#define FIFOSIZE 32
char FifoBuffer[FIFOSIZE];
////////////////////////////////////////////
 
struct charFifo{
  char * data ;
  unsigned int fifo_size ;
  unsigned int write_index ;
  unsigned int read_index ;
  unsigned int nb_token_available ; 
};
 
struct charFifo myFifo;    // la variable FIFO à utiliser
////////////////////////////////////////////
void char_fifo_init(struct charFifo * pf, char * buf, unsigned int f_size){
   pf -> data = buf ;
   pf -> fifo_size = f_size ;
   pf -> write_index = 0 ;
   pf -> read_index = 0 ;
   pf -> nb_token_available = 0 ;
 }
//////////////////////////////////////////// 
 char write_char_fifo(struct charFifo * pf, const char token){
  if(pf->nb_token_available >= pf->fifo_size) return 0 ;
  pf->data[pf->write_index] = token ;
  pf->write_index = pf->write_index + 1;
  if(pf->write_index >= pf->fifo_size) pf->write_index = 0 ;
  pf->nb_token_available = pf->nb_token_available + 1 ;
  return 1 ;
}
//////////////////////////////////////////// 
 char read_char_fifo(struct charFifo * pf, char * ptr_token){
  if(pf->nb_token_available == 0) return 0;
  *ptr_token = pf->data[pf->read_index]  ;
  pf->read_index = pf->read_index + 1;
  if(pf->read_index >= pf->fifo_size) pf->read_index = 0 ;
  pf->nb_token_available = pf->nb_token_available -1 ;
  return 1 ;
 
}
//////////////////////////////////////////// 
 char peek_char_fifo(struct charFifo * pf, char * ptr_token){
  if(pf->nb_token_available == 0) return 0 ;
  *ptr_token = pf->data[pf->read_index]  ;
  return 1 ;
}
////////////////////////////////////////////
 
 
 
SoftwareSerial mySerial(5, 6); // uart soft avec les broches RX,TX
// http://arduino.cc/en/Reference/softwareSerial
 
//////////////////////////////////////////// 
void setup()
{
  pinMode(rtsPin, OUTPUT);      
  pinMode(ctsPin, INPUT);     
  Serial.begin(115200);  // start serial port at 115200 bps:
  Serial.print("Bonjour");       
  mySerial.begin(1200);  // set the data rate for the SoftwareSerial port
  mySerial.println("Hello, world?");
  char_fifo_init(&myFifo,FifoBuffer, FIFOSIZE);   //initialisation de la FIFO
  digitalWrite(rtsPin, 1);      //éteind la led RTS
}
//////////////////////////////////////////// 
 void RemplirFifo(char c)
 {
  //écrire tous les caractères de la chaine ChaineEmission + le caractère c et mettre RTS à 0 si débordement de la FIFO
  //à implémenter
 }
//////////////////////////////////////////// 
void loop()
{
   int i; 
 
 //réception du nouveau caractère
   if (Serial.available() != 0)
     {
    //à compléter
     }  
   //vidage de la FIFO
   if(read_char_fifo(&myFifo,&inByte)==1)
     {
    //à compléter
     }
 
}
  • Lire le code de la fonction peek_char_fifo(…) et expliquer son fonctionnement
  • Compléter les fonctions void loop() et void RemplirFifo(char c)

Exercice 4 : Prise en main du contrôle de flux matériel

Cet exercice consiste à appréhender le contrôle de flux matériel RTS/CTS. En plus du cours, vous pouvez consulter la page suivante: http://en.wikipedia.org/wiki/RS-232#RTS.2FCTS_handshaking

Nous allons piloter le RTS du PC comme une requête d'autorisation d'envoi au arduino

  1. Le PC active son RTS pour faire une demande d'autorisation d'envoi
  2. L'arduino reçoit sur son CTS la requête du PC
  3. L'arduino active (s'il est prêt, par exemple parce qu'il y a la place dans sa FIFO de réception) son RTS pour indiquer qu'il est prêt à recevoir les données du PC
  4. Le PC reçoit l'autorisation d'envoi sur son CTS et peut alors transférer la donnée

Activer le contrôle de flux sur le PC

Pour piloter finement le port série du PC, nous utiliserons une console texte appelée miniterm. Pour lancer miniterm avec le bon numéro de port série, par exemple pour le port série 1, saisir dans une console:

miniterm /dev/ttyS1 1200

Pour configurer miniterm, il faut tout d'abord utiliser un caractère dit “d'échappement”, qui ne sera pas traité comme tous les autres caractères. Ce caractère spécial est saisi à l'aide de la combinaison CTRL+t. Il suffit ensuite de taper une ou plusieurs autres touches pour les différentes fonctions. Pour obtenir la liste des touches, il faut faire: CTRL+t puis CTRL+h qui conduit à l'affichage suivant:

  1. – pySerial (2.5) - miniterm - help
  2. – Ctrl+] Exit program
  3. – Ctrl+T Menu escape key, followed by:
  4. – Menu keys:
  5. – Ctrl+T Send the menu character itself to remote
  6. – Ctrl+] Send the exit character itself to remote
  7. – Ctrl+I Show info
  8. – Ctrl+U Upload file (prompt will be shown)
  9. – Toggles:
  10. – Ctrl+R RTS Ctrl+E local echo
  11. – Ctrl+D DTR Ctrl+B BREAK
  12. – Ctrl+L line feed Ctrl+A Cycle repr mode
  13. – Port settings (Ctrl+T followed by the following):
  14. – p change port
  15. – 7 8 set data bits
  16. – n e o s m change parity (None, Even, Odd, Space, Mark)
  17. – 1 2 3 set stop bits (1, 2, 1.5)
  18. – b change baud rate
  19. – x X disable/enable software flow control
  20. – r R disable/enable hardware flow control

Pour activer ou désactiver la sortie RTS du PC, tapez CTRL+t puis CTRL+r

Pour activer le mécanisme de contrôle de flux matériel (RTS/CTS), tapez CTRL+t puis SHIFT+r puis vérifier que l'affichage suivant est bien réalisé: — hardware flow control: active

La led CTS sur l'arduino doit s'allumer lorsque la sortie RTS du pc est activé.

Écrire un programme sur l'arduino qui

  1. configure la broche RTS en sortie
  2. configure la broche CTS en entree

puis en boucle

  1. met RTS à 0
  2. attend 1 seconde
  3. met RTS à 1
  4. attend 1 seconde

Compiler et Téléverser ce programme sur l'arduino. La led RTS doit clignoter à la fréquence d'1/2 Hz.

Dans la console miniterm, activer le contrôle de flux matériel puis presser en continu une touche dans la console. Vérifier que la led RX de l'arduino ne clignote que quand la led RTS est active.

Presser une seule touche dans la console miniterm lorsque la led RTS de l'arduino est éteinte, vérifier que la led RX de l'arduino s'allume plus tard lorsque la led RTS de l'arduino s'allume. Quelles conclusions en tirer? Appeler un enseignant pour valider.

Exercice 5 : Utilisation du contrôle de flux matériel

Afin d'illustrer l'intérêt du contrôle de flux et de la FIFO, exécuter ce programme de test TP14COM:

TP14COM.ino
const int rtsPin = 16;
const int ctsPin = 17;
 
#include <SoftwareSerial.h>
 
SoftwareSerial mySerial(5, 6); // uart soft avec les broches RX,TX
// http://arduino.cc/en/Reference/softwareSerial
 
//////////////////////////////////////////// 
void setup()
{
  pinMode(rtsPin, OUTPUT);      
  pinMode(ctsPin, INPUT);     
  mySerial.begin(1200);  // set the data rate for the SoftwareSerial port
  mySerial.println("Hello\r\n");
  digitalWrite(rtsPin, 0);//autorise envoi depuis le PC
}
//////////////////////////////////////////// 
void loop()
{
   int i,j; 
   if (mySerial.available()!=0) //si il y a au moins un caractère à recevoir
     {
     i=mySerial.read();       // lit le caractère reçu
     digitalWrite(rtsPin, 1); // interdit l'envoi depuis le pc le temps que l'on traite le caractère reçu
     delay(1000);             // attend une seconde, pour simuler un traitement long
     while (mySerial.available()!=0)  j=mySerial.read();   //vidage de la fifo de réception de l'uart soft, pour simuler l'absence de fifo
     mySerial.print("J'ai eu besoin d'une seconde pour traiter le caractère ");  
     mySerial.write(i);
     mySerial.println("\r\n");  
     digitalWrite(rtsPin, 0); //re autorise l'envoi depuis le pc
     }
}
 

Dans la console miniterm, saisir rapidement les touches “azertyuiop”, et observer le traitement correct de chacun des caractères émis par le PC.

Commenter la ligne suivante: digitalWrite(rtsPin, 1);

Dans la console miniterm, saisir rapidement les touches “azertyuiop”, et observer le changement.

La librairie de gestion de l'uart implémente en réalité une FIFO de 64 caractères en réception. Afin de la “désactiver”, on peut la vider de tout son contenu. Pour cela, mettre en commentaire la ligne suivante: while (mySerial.available()!=0) j=mySerial.read();

Dans la console miniterm, saisir rapidement les touches “azertyuiop”, et observer le changement.

Quelles conclusions en tirer? Appeler un enseignant pour valider.

Exercice 6 : Configuration manuelle de l'UART matériel

A l'aide de la datasheet de l'Atmega328P (UART à partir de la page 143, http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf#page=143

Etablir la configuration des registres suivants pour une communication 9600 bauds, 8N1:

  • UBRR0H
  • UBRR0L
  • UCSR0C
  • UCSR0A
  • UCSR0B

L'arduino comporte plusieurs USART matériels, le module 0 est utilisé comme UART. Comme la documentation est générique et s'applique aux différents modules, il faudra remplacer n par le chiffre 0 pour l'UART matériel utilisé.

Définir ensuite:

  • Une fonction bloquante d'envoi d'un caractère sur le port série: void USART_Transmit(unsigned char data )
  • Une fonction bloquante de réception caractère sur le port série: unsigned char USART_Receive(void )

Dans la fonction loop, faire en sorte de renvoyer chaque caractère reçu sur l'UART en ajoutant 1 à son code ASCII

Vous pouvez maintenant regarder comment la librairie Arduino utilisant l'UART matériel implémente ce fonctionnement et comparer avec votre implémentation. Vous noterez que cette librairie est utilisable pour plusieurs UART car certaines cartes Arduino (la Mega par exemple) en possèdent plusieurs. Pour cela, ouvrir les fichiers:

/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h
/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.cpp 
tdcom1.txt · Dernière modification : 2022/01/24 15:05 de bvandepo