Table des matières

TP Capteur 1: Présentation Arduino et E/S numériques et analogiques

Objectifs

Le TP se déroule sous Linux mais vous pouvez tout à fait utiliser la version Windows ou OS/X d'Arduino

Carte Arduino pour le TD/TP

Arduino est une plateforme de développement open-source qui se compose d'une carte microcontrôleur et d'un environnement de développement associé. La carte Arduino UNO se compose de :

Le schéma de cette carte est visible sur: http://arduino.cc/en/uploads/Main/Arduino_Uno_Rev3-schematic.pdf

Le schéma de la carte d'extension ainsi que la numérotation des broches des connecteurs Arduino sont visibles ci dessous:

Pour plus d'informations, vous reporter à http://arduino.cc/

Il existe des cartes compatibles arduino que vous pouvez acheter pour 4 euros par exemple sur: http://www.ebay.com/itm/NEW-UNO-R3-ATmega328P-CH340-Mini-USB-Board-Compatible-Arduino-/311155383820?pt=LH_DefaultDomain_0&hash=item48724e5e0c

Il existe aussi des kits tels que: https://www.dx.com/fr/p/funduino-uno-r3-lcd-1602-keypad-shield-v2-0-lcd1602-expansion-board-building-blocks-deep-blue-315276?tc=EUR&gclid=CJ_Hvd645b4CFaXHtAod-1MA4A#.VMRAaTVrpwH

Il est également possible d'utiliser un outils en ligne pour développer sur arduino sans rien installer sur votre machine: https://codebender.cc/

Exercice 1: Prise en main de l'Arduino

Branchement de la carte Arduino

La carte Arduino se branche au PC via un des ports USB disponibles en façade. Le connecteur côté Arduino est de type USB-A mâle et le connecteur côté PC est de type USB-B femelle. Avant de passer à la suite, connectez la carte au PC à l'aide du câble fourni.

Pour votre PC, le branchement d'une carte Arduino est vu comme l'ajout d'un port de communication série par lequel vous allez pouvoir envoyer et recevoir des caractères ASCII à l'aide d'une application Console Texte (intégrée à Arduino)

La carte Arduino n'étant pas protégée, il est préférable de vérifier que la table de TP est libre de tout objet métallique afin d'éviter les court-circuits !

Prise de main de l'outil Arduino IDE

Le système d'exploitation utilisé lors des TP de bus de communication est Debian (basé Linux). Sous Linux le lancement des utilitaires peut se faire de deux manières:

Pour lancer l'application Arduino au travers de la ligne de commande, suivez la suite d'instructions suivante :

  1. Taper ALT+F2 puis saisir xterm et touche entrée
  2. Dans le terminal, taper le nom de l'application (arduino) suffixé par &

  1. Attendre le chargement de l'application, une fois l'application chargée, vous devriez avoir la vue suivante

Configuration de l'IDE

Dans l'onglet “Outils”, accédez au menu “Port Série” et cliquez sur la valeur /dev/ttyACM0 ou /dev/ttyUSB0. Accédez aussi eu menu “Carte” et vérifiez que la valeur sélectionnée est “Arduino Uno”.

Votre premier sketch

Maintenant que l'editeur est lancé, nous pouvons entrer (en copiant/collant) dans la fenêtre le programme suivant:

blink.ino
int led = 3; //numéro de la broche Arduino pilotant la LED sur le shield PERIPH
// the setup routine runs once when you press reset:
void setup() {                
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);     
}
 
// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
Cette ligne n'a rien à faire ici, elle provoque une erreur de compilation, il faut donc l'effacer  
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

Consultation des documentations: https://www.arduino.cc/reference/en/

Compilation du sketch

Copier coller le contenu dans votre fichier et cliquez sur le bouton “Vérifier” pour le compiler.

Les erreurs de compilation apparaissent en rouge (et en anglais) dans la fenêtre de compilation en bas de l'IDE. Corriger le programme pour qu'il puisse être compilé.

Chargement sur la platine Arduino

Une fois que la compilation ne génère plus d'erreurs, chargez le fichier sur la carte Arduino (préalablement connectée sur le port USB) en cliquant sur le bouton “Téléverser”

A partir de ce point, si votre code est correct, la LED doit clignoter.

Précautions à prendre avec la plateforme et l'IDE

Exercice 2: Communication avec la carte Arduino

Nous allons utiliser la librairie Serial pour échanger des caractères ASCII entre le PC et la carte Arduino de manière bidirectionnelle. Vous pouvez accéder au descriptif de cette librairie en sélectionnant le menu “Aide” puis le menu “Référence”.

L'utilisation de ce lien de communication va notamment permettre de deboguer votre programme en affichant par exemple la valeur de certaines variable. Le debogage de votre application pourra se faire à l'aide d'affichage vers la console MAIS il faut tenir compte du fait que le code ainsi modifié ne sera pas exactement le même code que celui sans les appels d'affichage.

Egalement, vous pourrez utiliser des broches du microcontroleur pour indiquer l'entrée ou la sortie d'une portion de code, afin de tester précisément le temps nécessaire à son exécution.

Utilisation de la librairie Serial

Repérer sur le schéma électrique de la carte les broches réservées pour la communication série. Ces brôches ne devront pas être utilisées pour une autre fonction!

L'application à programmer implémente le comportement suivant :

  1. Configurer l'UART pour une communication 8N1 à 9600Bauds (Serial.begin)
  2. Attendre que un caractère soit disponible sur le périphérique UART (Serial.available)
  3. Lire le caractère (Serial.read)
  4. Si le caractère est une minuscule, le convertir en majuscule (?)
  5. Envoyer le caractère sur la liaison série (Serial.write)

Pour des formats de trames autres que 8N1, vous trouverez les valeurs de paramètres adaptés à la méthode Serial.begin à l'adresse: http://arduino.cc/en/Serial/Begin

TP11.ino
void setup()  
{
  Serial.begin(9600); 
  Serial.println("Hello, world?"); // Envoi de la chaîne terminée par un saut de ligne
}
 
void loop()
{
  char car ;
  if (Serial.available()>0){
     car = Serial.read();
     if ( (car>='a') && (car<='z') )
      car=car+'A'-'a';
     Serial.write(car);
  }
}

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Compiler et charger ce programme sur la carte.

Utilisation de la console série sur le PC

L'IDE arduino dispose d'une console série permettant de visualiser les caractères envoyés par l'Arduino sur son port périphérique matériel. Pour accéder à la console série, il suffit de cliquer sur la loupe en haut à droite de l'éditeur de code.

Une console série apparaîtra alors sous la forme suivante:

Il suffit alors de configurer le baudrate de la communication à l'aide la liste déroulante en bas à gauche (le régler à 9600 pour être cohérent avec le programme chargé dans l'Arduino).

Pour envoyer des caractères à l'application, il suffit de les rentrer dans la zone de texte en haut de de la fenêtre, puis de cliquer sur “Envoyer”.

Les caractères émis par l'UART HARD du Arduino doivent ensuite s'afficher dans la partie basse de la fenêtre.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Vérifier la communication avec la carte Arduino en utilisant le programme chargé précédemment.

Exercice 3: Prise en main des Entrées/Sorties numériques de la carte d'extension

Dans l'exercice 1, vous avez utilisé une sortie numérique de l'Arduino pour piloter une LED. Dans cet exercice, vous allez devoir utiliser des E/S numériques cablées sur des composants périphériques.

La carte visible sur la figure suivante (ignorez les commentaires) comporte notamment 8 interrupteurs ainsi qu'un barregraphe de 8 LEDs que nous allons utiliser ici.

Copier le squelette de programme ci dessous et s'en servir de base pour faire l'exercice.

es.ino
#include <Wire.h>
#define SLAVE_ADDR_8574_A (0x38+6)
#define SLAVE_ADDR_8574_B (0x38+7)
//////////////////////////////////////////
unsigned char LirePortB()
{
   Wire.requestFrom((byte)SLAVE_ADDR_8574_B, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique
    if (Wire.available()==1) //si l'octet est disponible
        return Wire.read(); // lire l'octet
    else
        return 0;
}
//////////////////////////////////////////
void EcrirePortA(unsigned char valeur)
//cette fonction pilote les 8 leds avec la valeur 8bits fournie dans le paramètre valeur 
{
    Wire.beginTransmission((byte)SLAVE_ADDR_8574_A);//démarre la transmission avec l'adresse du pérpiphérique
    Wire.write(~(byte)valeur);     //envoie la donnée complémentée car les LEDs s'allument à l'état 0
    Wire.endTransmission();
}
//////////////////////////////////////////
int sensorPin = A0;    // numéro de la broche analogique à utiliser
int sensorValue = 0;  // variable pour stocker la valeur lue depuis la capteur
//////////////////////////////////////////
void setup() {
  Serial.begin(9600);
  Serial.println("reset");
  Wire.begin();
  delay(100);
 
Wire.beginTransmission((byte)SLAVE_ADDR_8574_B);Wire.write((byte)0xff);Wire.endTransmission();//configure le composant B en entrée
  pinMode(3,OUTPUT);
}
//////////////////////////////////////////
void loop() {
  //à compléter ici 
 
}

Vous avez accès à l'état des 8 interrupteurs à l'aide de la fonction unsigned char LirePortB() qui retourne une valeur binaire sur 8 bits, l'interrupteur i pilotant le bit numéro i.

Vous pouvez piloter les 8 LED à l'aide de la fonction void EcrirePortA(unsigned char valeur) qui prend en paramètre d'entrée la valeur 8 bits avec laquelle piloter les LED, le bit numéro i pilotant la LED i.

La fonction setup() est déjà fournie complète. Vous devrez par contre compléter la fonction void loop() pour répondre aux questions suivantes:

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Effectuer la recopie du port d'entrée sur le port de sortie. Vous devriez alors être capable de piloter les LED à l'aide des interrupteurs.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Compléter votre programme pour afficher sur la console à l'aide de la fonction Serial.println(…) la valeur lue sur le port d'entrée. Régler les interrupteurs dans des positions variées et vérifier que vous arrivez à interpréter correctement la valeur affichée sur les LED et sur la console.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Modifier votre programme pour n'allumer qu'une seule LED, dont le numéro doit être piloté par les bits 0 à 2 (uniquement) du port d'entrée. Pour cela vous utiliserez les opérateurs de décalage binaire (« et ») ainsi que les opérateurs logiques (&, | etc…). Il est conseillé d'utiliser une variable de type unsigned char pour stocker la valeur lue sur le port d'entrée et effectuer les différentes opérations nécessaires. Vous pourrez également utiliser Serial.print(…,DEC) ou Serial.print(…,HEX) pour afficher la valeur de cette variable respectivement en décimal ou en hexadécimal et vous aider à comprendre. Expliquer la valeur numérique permettant le pilotage du port de sortie en fonction de la valeur lue sur le port d'entrée à l'aide d'opérations mathématiques usuelles.

Faire valider vos réponses à l'enseignant.

Exercice 4: Mise en place d'un anti-rebonds mécaniques

Dans cet exercice, nous allons illustrer la notion de rebonds mécaniques sur des capteurs tout-ou-rien (TOR) de type interrupteur, mais plus généralement tout capteur impliquant un contact électrique entre deux lames, par exemple un interrupteur reed piloté par un champ magnétique: https://fr.wikipedia.org/wiki/Interrupteur_reed .

Lors d'une commutation (changement de position), un tel capteur fournit une sortie faisant apparaître plusieurs commutations rapprochées dans le temps. Si l'on souhaite comptabiliser le nombre de fois qu'un interrupteur est commuté, ces commutations parasites (appelées rebonds) posent problème et il faut donc s'en prémunir à l'aide de la fonction d'anti-rebonds mécaniques. Cette fonction peut être réalisée de différentes manières:

Un exemple de composant analogique permettant cette fonction est le célèbre NE555: https://fr.wikipedia.org/wiki/NE555#Fonctionnement_monostable

La fonction d'anti-rebonds mécaniques peut être localisée:

Ainsi, alors que la commutation d'un interrupteur de l'état haut à l'état bas devrait générer un chronogramme tel:

On observe plutot en pratique:

Pour cet exercice, nous ne pouvons pas utiliser les interrupteurs du port d'entrée de la carte PERIPH, car ils sont connectés à un circuit d'interface trop lent. Nous allons donc plutôt utiliser une broche de l'Arduino configurée en entrée. L'état de la broche pin est habituellement obtenu dans le programme en appelant la fonction digitalRead(pin) qui renvoie HIGH ou LOW. Nous avons remplacée cette fonction ici par un accès direct au registre pour accélérer la lecture de l'état de la broche et rendre évident le phénomène.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Lire ce programme et le charger sur la carte arduino puis ouvrir la console série pour afficher le nombre de fronts descendants détectés. Connecter au broches Ground et 2 de l'Arduino différents capteurs/câbles/générateurs de fronts fournis par l'enseignant et observer l'évolution du compteur. Faire le lien avec les chronogrammes montrés précédemment.

compteur_front_descendant.ino
int ledPin = 3;  // LED connected to digital pin 3
int inPin = 2;    // pushbutton connected to digital pin 2
int val = 0;      // variable to store the read value
int val_ancien = 0;      // variable to store the read value
 
 
void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);  // sets the digital pin 13 as output
  pinMode(inPin, INPUT_PULLUP);    // sets the digital pin 7 as input with internal PULL UP
  val_ancien=digitalRead(inPin);   // read the input pin
}
 
int compteur_front_descendant=0;
 
void loop() {
//le code suivant sert à afficher la valeur de compteur_front_descendant tout les 10000 exécutions de loop
  static int cpt_loop=0;
  cpt_loop++;
  if ( (cpt_loop%10000)==0)   Serial.println(compteur_front_descendant);
 
//digitalRead pour lire l'état de la broche est lent, on le remplace par une lecture directe du registre  
//  val = digitalRead(inPin);   // read the input pin
val= (PIND>>2)&1;
 
//compteur_front_descendant est incrémenté si un front descendant est détecté  
  if ((val==LOW) && (val_ancien==HIGH))
    {
    compteur_front_descendant++;
    }
  val_ancien=val;
 
}

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Proposer une solution pour ne comptabiliser qu'un front à chaque commutation réelle du capteur et modifier le programme en conséquence.

Faire valider vos réponses à l'enseignant.

Exercice 5: Utilisation du convertisseur analogique numérique (ADC)

Nous abordons maintenant un composant très important permettant à un système numérique tel le microcontroleur Arduino d'acquérir des informations analogique, c'est à dire pouvant varier de manière continue entre plusieurs valeurs, au contraire des informations “tout ou rien”. Ce composant est le convertisseur analogique numérique (appelé Analog to Digital Converter en anglais).

L'environnement Arduino propose la fonction unsigned int analogRead(pin) qui permet d'obtenir la valeur numérique issue de la conversion analogique vers numérique de la tension présente sur la broche pin.

Dans le cas de la carte UNO, elle retourne un nombre sur 10 bits puisque les convertisseurs sont des convertisseurs 10 bits. Cela veut dire qu’ils sont capables de retourner une valeur entre 0 et 1023, valeur représentant une tension entre 0 et 5V. Seules les entrées nommées A0 à A5 peuvent être utilisée pour des signaux analogiques.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Connecter un potentiomètre en montage diviseur de tension entre les broches 5V (fil rouge) et Ground (fil noir) de l'Arduino et le point milieu doit être connecté à la broche A0 (fil vert). Demander conseil à l'enseignant en cas de doute. Compléter le programme suivant afin que la fonction loop() effectue la conversion analogique vers numérique de la tension fournie par le potentiomètre sur la broche A0. Cette valeur, appelée échantillon, doit être stockée dans une variable de type unsigned int dont la valeur doit être affichée sur la console en décimal à l'aide de la fonction Serial.println().

squelette.ino
#include <Wire.h>
#define SLAVE_ADDR_8574_A 0x3e
#define SLAVE_ADDR_8574_B 0x3f
//////////////////////////////////////////
unsigned char LirePortB()
{
  Wire.requestFrom((byte)SLAVE_ADDR_8574_B, (byte)1);// demande la lecture d'1 octet depuis l'adresse du pérpiphérique
  if (Wire.available()==1) //si l'octet est disponible
    return Wire.read(); // lire l'octet
  else
    return 0;
}
//////////////////////////////////////////
void EcrirePortA(unsigned char valeur)
//cette fonction pilote les 8 leds avec la valeur 8bits fournie dans le paramètre valeur 
{
  Wire.beginTransmission((byte)SLAVE_ADDR_8574_A);//démarre la transmission avec l'adresse du pérpiphérique
  Wire.write(~(byte)valeur);     //envoie la donnée complémentée car les LEDs s'allument à l'état 0
  Wire.endTransmission();
}
//////////////////////////////////////////
int sensorPin = A0;    // numéro de la broche analogique à utiliser
int sensorValue = 0;  // variable pour stocker la valeur lue depuis la capteur
//////////////////////////////////////////
void setup() {
  Serial.begin(9600);
  Serial.println("reset");
  Wire.begin();
  delay(100);
  Wire.beginTransmission((byte)SLAVE_ADDR_8574_B);
  Wire.write((byte)0xff);
  Wire.endTransmission();//configure le composant B en entrée
  pinMode(3,OUTPUT);
}
//////////////////////////////////////////
void loop() {
// à compléter
}

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Lancer l'outils de visualisation de courbes d'arduino (via Outils→Traceur série), et visualiser le signal issus du potentiomètre en fonction du temps. Afin d'éviter un zoom automatique de l'application Traceur série, modifier votre programme pour que sur la ligne envoyée via la liaison série soit au format:

0 1023 valeur_lue

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Compléter le programme pour que la valeur de l'échantillon permette de piloter de manière proportionnelle une unique LED du barregraphe, en utilisant la LED 0 pour une valeur d'échantillon de 0 et la LED 7 pour une valeur d'échantillon de 1023.

Faire valider vos réponses à l'enseignant.

Exercice 6: Seuillage d'une valeur analogique et mise en place d'un hystérésis

Nous allons maintenant aborder la notion de seuillage d'une grandeur analogique. Dans un capteur impliquant un dispositif analogique (par exemple une sonde de température), il est parfois souhaitable de générer une sortie “tout ou rien” dont la valeur dépend de la grandeur analogique. Ceci peut être fait en seuillant la grandeur analogique, c'est à dire en appliquant l'algorithme suivant:

si grandeur_analogique<seuil 
  alors sortie_tor=0
  sinon sortie_tor=1

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Compléter le programme de l'exercice précédent pour allumer la LED connectée à la sortie 3 de l'Arduino si la tension analogique issue du potentiomètre est supérieure à la moitié de la plage de tension admissible pour le convertisseur analogique vers numérique. Déplacer le potentiomètre et vérifier que la led est bien pilotée.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Trouver une position du potentiomètre permettant de faire clignoter la LED. Au besoin ajouter la ligne suivante dans votre programme pour bruiter la valeur de l'échantillon:

sensorValue+=-10+rand()%20; //ajout de bruit à la donnée lue pour rendre plus visible le phénomène

Nous allons maintenant mettre en place un mécanisme de commutation à double seuil (appelé hystérésis) permettant d'éviter ces changements d'états intempestifs. Comme pour l'anti rebonds mécaniques, cette fonctionnalité peut être réalisée de plusieurs manières:

Elle peut aussi être localisée:

Pour réaliser cet hystérésis, il est nécessaire de mettre en place une mémorisation (à l'aide d'une variable) de la plus récente commutation correspondant à l'état de la sortie. En fonction de la valeur de cette variable, l'une des deux valeurs de seuil devra être utilisée.

bvdp.inetdoc.net_files_iut_tp_tns_todo.jpg Modifier le programme précédent pour mettre en place un hystérésis dont les 2 seuils sont distants d’approximativement 0.1V autour de la valeur 2.5V.

Faire valider vos réponses à l'enseignant.