Les capteurs
Les capteurs et périphériques
Principes et théorie
Objectifs
Ce chapitre a pour but de faire un petit tour d’horizon des différents capteurs et de leur mise en place.
Une mise en exemple sera faite avec le code de base pour réaliser un serveur Web.
Les types de capteurs
Il existe une multitude de capteurs:
- Capteur de distance
- Capteur de température
- Capteur de présence
- Capteur de pression-humidité
- Capteur de position (potentiomètre, joystick, fin de course)
- Capteur de particules fines
- Capteur d’accélération
Les modes de transmission
Voici les différentes façon de communiquer.
Pour nos exemples, nous nous baserons sur deux périphériques qui communiquent entre eux.
- Simplex: la communication est unidirectionnel , c’est à dire que le périphérique A envoie des informations au périphérique B mais le B ne peut pas envoyer au A.
- Half-duplex: la communication se fait dans les deux sens mais avec un décalage dans le temps. Si le périphérique A communique, le B ne peut pas envoyer des informations en meme temps que le A.
- Full-duplex: les périphériques peuvent communiquer en même temps, comme dans une conversation téléphonique.
Les protocoles de communication
Pour communiquer, de nombreux protocoles existent mais voici les principaux.
Le bus I2C
Le bus I2C est un bus informatique qui a émergé dans les années 80 pendant la «guerre des standards» lancée par les acteurs du monde électronique.
Conçu par Philips pour les applications de domotique et d’électronique domestique, il permet de relier facilement un microcontrôleur et différents circuits récepteurs tels que des capteurs de pression, température….
C’est un bus série synchrone bidirectionnel half-duplex avec 2 broches utilisées pour communiquer :
- SDA : Serial Data (ligne de données)
- SCL : Serial Clock (ligne d’horloge)
Une masse est commune aux périphériques.
Les échanges ont toujours lieu entre un seul maître et un (ou tous les) esclave(s), toujours à l’initiative du maître [note] et pour éviter les conflits électriques les broches SDA et SCL sont de type Collecteur Ouvert. Il faut donc ajouter des résistances de tirage mais ces dernières sont généralement intégrées.
Il existe d’innombrables périphériques exploitant ce bus, il est même implémentable par logiciel dans n’importe quel microcontrôleur.
A chaque composant est attribué une adresse physique qui permettra les échanges.
Cette adresse est codée sur 7 bits, ce qui fait que le bus I2C peut supporter en théorie 127 périphériques [note].
Par exemple, on pourra trouver sur un même bus I2C :
- 1 écran OLED (adresse 0x3C)
- 1 écran LCD (0x27)
- 1 capteur de pression BME180 (0x35)
Les changements d’adresses
Lorsqu’on souhaite connecter plusieurs périphériques ayant la même adresse (par exemple 2 capteurs de température), il est possible pour certains périphériques de mettre certaines broches à un certain niveau logique pour définir l’adresse.
Le bus SPI
Le bus SPI[note] SPI est full-duplex et développé par Motorola dans le milieu des années 80.
La liaison est de type maitre-esclave ou le maitre sélectionne l’esclave avec qui il veut communiquer avec une broche \genericPin{SS}.
Le bus comporte 4 broches :
- SCLK : Serial Clock, Horloge (généré par le maître)
- MOSI : Master Output Slave Input (généré par le maître)
- MISO : Master Input Slave Output (généré par l’esclave)
- SS : Slave Select, Actif à l’état bas (généré par le maître)
Protocole
- Le maître génère l’horloge et sélectionne l’esclave avec qui il veut communiquer par l’utilisation du signal SS
- L’esclave répond aux requêtes du maître
La liaison UART
\index{UART}
La liaison UART est une liaison série avec deux broches :
- RX
- TX
Il permet uniquement de faire communiquer plus de deux appareils entre eux, contrairement aux bus I2C ou SPI, on ne peut pas relier plusieurs périphériques.
Protocole
- Un bit de start toujours à 0 pour synchroniser la communication
- Un champ de données de 7 à 8 bits
- Un bit de parité (paire ou impaire)
- Un bit de stop
Au repos, la ligne est au niveau logique HAUT.
Vitesse de communication
La liaison étant asynchrone, il faut que les périphériques communiquent à la même vitesse. Cette dernière est normalisée et représente le nombre de bit par seconde (baud[note])
- 1 200 bauds
- 2 400 bauds
- 4 800 bauds
- 9 600 bauds
- 19 200 bauds
- 38 400 bauds
- 57 600 bauds
- 115 200 bauds
Une trame en exemple
On constate bien que le niveau au repos est au niveau HAUT.
D’autres exemple
- Le bus CAN[note] est un bus série half-duplex couramment utilisé dans l’industrie automobile et avionique. La transmission suit le principe de transmission en paire différentielle et possèdent donc deux lignes CAN L (CAN LOW) et CAN H (CAN HIGH). Tous les équipements, appelés noeuds, souhaitant communiquer via le bus sont connectés et peuvent échanger des informations.
- Protocole One-Wire qui utilise un seul câble pour communiquer.
- Protocole MODBus [note]
Les capteurs de distance
Différentes technologies sont utilisées pour mesurer une distance, cependant elles possèdent leurs avantages et inconvénients.
- Infrarouge
- Bon marché
- Assez précis
- Non-linéaires
- Sensibilité à la lumière ambiante
- Dépend du coefficient de réflexion lumineuse de la surface en face du capteur
- Laser
- Très précis
- Longue distance
- Prix
- Ultra-sonore
- Prix
- Ne dépend pas de la couleur de la surface en face du capteur
- Précision parfois arbitraire
Les capteurs infrarouges
Ce capteur envoie une tension qui dépend de la distance de l’objet.
Cependant, cette tension n’est pas proportionnelle à la distance[note]
Les capteurs ultrasons
Principe
Le principe de ce capteur repose sur le temps de propagation d’une onde sonore dans l’air.
En connaissant le temps d’une aller-retour et la vitesse de propagation, on peut déterminer la distance de l’objet.
Séquence de la mesure
- On envoie une impulsion de 10µs sur la broche \lbl{green}{PIN}{TRIGGER} du capteur.
- Le capteur envoie une dizaine d’impulsions ultrasonores à 40 kHz
- Les ondes se propagent et rebondissent sur l’obstacle
- Le capteur renvoie le temps de propagation avec la broche \lbl{green}{PIN}{ECHO} en mettant la sortie à
l’état haut durant le temps de l’aller-retour.
Voici le relevé de la broche \lbl{green}{PIN}{TRIGGER} et \lbl{green}{PIN}{ECHO}
Les écrans OLED
Les écrans OLED[note] sont des afficheurs graphiques compacts avec une résolution de 128×64 pixels ou 64×32 pixels.
Leur résolution plus élevée que des écrans LCD permet de faire des petits dessins.
Ces écrans utilisent le protocole I2C pour communiquer.
Les capteurs de température
Les capteurs numériques
Les capteurs de température DHTXX[note] sont des capteurs de température et d’humidité fonctionnant entre 3.3 et 5V.
Protocole
Le protocole de communication se fait sur un seul câble.[note]
Branchements
Les capteurs analogiques
Enfin, certains capteurs transmettent leurs données via une tension analogique.
Pour certains capteurs, il suffire le lire une tension pour obtenir indirectement la grandeur physique. Par exemple, le capteur LM35 sort une tension de 10 mV/°C.
Si le capteur sort une tension de 210 mV, cela veut dire qu’il fait 21°C.
Les capteurs PIR
Principe
Les capteurs PIR (Passive-Infra-Red) détectent les rayonnements infrarouges émis par un objet.
Puisque tout objet émet un rayonnement infrarouge, le capteur PIR est muni de deux cellules sensibles aux infrarouges qui vont détecter ces rayons infrarouges réfléchit ou émit par l’objet.
Lorsqu’il n’y a pas de mouvement, le niveau d’infrarouge reçu est le même pour les deux cellules. Lors du passage d’un objet, l’émission de ces rayons va être modifiée sur une cellule puis sur l’autre ce qui va permettre de détecter le mouvement.
Le cache blanc, qui couvre et protège généralement le capteur, est une lentille de Fresnel avec plusieurs facettes qui permet de concentrer le rayonnement infrarouge sur les cellules.
Utilisation
Ces capteurs possèdent une broche de sortie qui est mise à l’état HAUT pendent une certaine durée
[note] lorsqu’il y a détection d’un mouvement.
\begin{numeric}{Diagramme temporel du capteur}
Présence & [green] LLLLLLHHHHHHHLLLLLLHHHLLLLLLLLLLLLHHHHHHLLLLL
OUT & [blue] LLLLLLLHHHHHHHHLLLLLHHHHHHHHLLLLLLLHHHHHHHHLL
\end{numeric}
Applications
- Allumage d’une lumière à la détection d’un mouvement
- Activation d’une alarme lors de l’intrusion d’une personne
Les relais électromagnétiques
Principe
Les relais sont des interrupteurs commandés électriquement.
Une bobine alimentée sous faible tension (5 à 24 V) génère un champ électromagnétique qui fait déplacer une membrane qui va ouvrir ou fermer le circuit.
Le relai offre une isolation galvanique entre le circuit de commande et de puissance, c’est à dire qu’il n’y a aucune liaison conductrice entre ces deux circuits.
Un relai est caractérisé par :
- La tension de commande : 5 à 24V
- Le courant de coupure : Ex 30A
- La tension maximale dans le circuit de puissance : Ex 230V
- Sa position au repos[note] : Normalement Ouvert (NO) ou
- Sa durée de vie : les relais sont garantis pour un nombre de commutation, par exemple 1 million.
Normalement Fermé (NF)
Symbole
Le relai se symbolise de la façon suivante :
On distingue clairement la partie de commande (rectangle) et le circuit qui s’ouvre ou se ferme pour laisser passer le courant.
La diode de roue libre
La bobine de commande du relai nécessite un certain courant [note] qu’une broche de microcontrôleur ne peut pas fournir.
Pour cela on utilise un composant qui fera l’interface entre le microcontrôleur et le relai : le transistor.
Cependant, lors de la fermeture du relai [note], le courant est brutalement coupé, or, les bobines s’opposent aux variations de courant.
Cela engendre une surtension qui va se répercuter sur le transistor.
Cette surtension vaut :
\( U = L\cdot \frac{dI}{dt}\)
Avec :
- U la tension en Volt aux bornes de la bobine
- L la valeur en Henry de l’inductance[note]
- I la variation de courant en Ampère dans la bobine
On met donc une diode en parallèle de la bobine pour que l’énergie accumulée dans la bobine passe dans la diode.
Cette diode est appelé diode de roue libre.
En exemple, une simulation sans diode est faite avec LTSpice :
On active le transistor pendant 100 ms puis on le désactive et on observe la tension aux bornes du transistor.
On constate un pic à 24V, c’est à dire le double de l’alimentation 12V.
Maintenant, faisons la même simulation avec une diode de roue libre. Pour ces diodes, on privilégie des diodes Schottky à commutation rapide.
La surtension ne vaut plus que quelques dizaines de mV.
En pratique
Pour utiliser des relais avec des microcontrôleurs, on utilise le plus souvent des relais qui intègrent une interface de contrôle.
Il suffit généralement d’alimenter le relai en 5V constant et une broche active le relai si elle passe au niveau logique HAUT.
Les codes suivants seront utilisés avec le serveur Web mis en place avec l’ESP12.
Cela permettra de réaliser une interface plus élaborée avec des capteurs et actionneurs.
Utilisation du DHT11
Objectif
L’intégration du code permettant de lire la température permettra d’obtenir l’interface suivante, à savoir un graphique pour
visualiser la température et l’humidité en temps réel.
Branchements
Programme de test
Avant de tester le code complet du DHT11/22 avec le serveur Web , on va essayer le module DHT sans le serveur.
Pour cela, on va téléverser le programme suivant[note]{FILE}{temperature\_humidite.ino}} :
#include "DHT.h"
#define DHTPIN D2 //Broche du capteur
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22
//#define DHTTYPE DHT21 // DHT 21
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(115200);
dht.begin(); //Initialisation du capteur
}
void loop() {
float h = dht.readHumidity(); //Récupère la température
float t = dht.readTemperature(); //récupère l'humidité
Serial.print("Humidite: ");
Serial.print(h);
Serial.print("\% Temperature: ");
Serial.print(t);
Serial.println("C ");
delay(2000);
}
Si vous obtenez le résultat suivant en lançant la console série, c’est que le capteur est fonctionnel.
Il ne vous reste plus qu’à lancer le programme \lbl{red}{FILE}{Serveur\_Web\_DHT11\_Graphe.ino}.
Explications
Pour gérer les températures et les valeurs d’humidité dans le temps, un tableau ‘circulaire’ est utilisé dans le programme.
Il consiste à remplir au fur et à mesure un tableau et quand celui-ci est plein, on décale les valeurs pour ajouter la dernière.
Prenons un exemple avec un tableau de 5 éléments auquel on cherche à ajouter le cycle suivant : 21,22,21,22,23,24,25,26
\begin{numeric}{Les tableaux ‘circulaires’}
Etape Initial & 2D{0} 2D{0} 2D{0} 2D{0} 2D{0}
Ajout de ’21’ & 2D{21} 2D{0} 2D{0} 2D{0} 2D{0}
Ajout de ’22’ & 2D{21} 2D{22} 2D{0} 2D{0} 2D{0}
Ajout de ’21’ & 2D{21} 2D{22} 2D{21} 2D{0} 2D{0}
Ajout de ’22’ & 2D{21} 2D{22} 2D{21} 2D{22} 2D{0}
Ajout de ’23’ & 2D{21} 2D{22} 2D{21} 2D{22} 2D{23}
Ajout de ’24’ & 2D{22} 2D{21} 2D{22} 2D{23} 2D{24}
Ajout de ’25’ & 2D{21} 2D{22} 2D{23} 2D{24} 2D{25}
Ajout de ’26’ & 2D{22} 2D{23} 2D{24} 2D{25} 2D{26}
\end{numeric}%
Ce mouvement cyclique est géré par la fonction \lbl{blue}{FUNC}{updateRings} dans le fichier \lbl{purple}{LIB}{circularRings.h}
La fonction principale pour gérer le graphique est la fonction \lbl{blue}{FUNC}{getString} :
temperature = dht.readTemperature();
humidity = dht.readHumidity();
Une fois ces deux données lues, on actualise les tableaux circulaires contenant les températures, les valeurs d’humidité et les références du graphique [note].
updateRings(¤t_index, NB_DATA_TEMP, temperature, humidity); //Mise à jour des tableaux
On créer ensuite les chaines de caractères pour générer le graphique :
String dataTemperatures = concatenateArray(temperatures, current_index);
String dataHumidities = concatenateArray(humidities, current_index);
String dataReferences = concatenateArray(references, current_index); //Tableau contenant toutes les valeurs à 0, pour afficher la référence sur le graphique
String dataTime ="[";
for (int i=current_index;i>0;i--) {
dataTime += "'"+String(i)+"',";
}
dataTime += "]";
Une fois toutes les données, on génère la page dans son intégralité :
const String fullPageContent = "\
\
Serveur Web CREPP \
\
\
\
\
\
\
Interface ESP12
\
Contrôle de la LED sur la broche D4
\
\
\
Mesure de la température et humidité avec le module DHT11 sur la broche D2
\
\
>>> Temperature : "+String(temperature)+" C
\
>>> Humidite : "+String(humidity)+"%\
\
\
\
";
Utilisation du HC-SR04
Branchements
Code complet
#define TRIGGER_PIN D5 //Broche Trigger
#define ECHO_PIN D6 //Broche Echo
#define SOUND_VELOCITY 0.034 //Vitesse en cm/us
float distance = 0.0;
void setup() {
Serial.begin(9600); //Communication à 9600 bauds
pinMode(TRIGGER_PIN, OUTPUT); //Broche Trigger en sortie
pinMode(ECHO_PIN, INPUT); //Broche Echo en entrée
digitalWrite(TRIGGER_PIN, LOW);
}//End setup
void loop() {
digitalWrite(TRIGGER_PIN, HIGH); //Envoie une impulsion de 10us
delayMicroseconds(10);
digitalWrite(TRIGGER_PIN, LOW);
int duration = pulseIn(ECHO_PIN, HIGH); //Récupère le temps à l'état Haut de la broche ECHO
distance = duration * SOUND_VELOCITY/2; //Distance en cm, v=d/t
Serial.print("Distance (cm) = ");
Serial.println(distance);
delay(1000);
}
Utilisation d’un capteur PIR
Branchements
Code complet
#define LED D2 //Broche de la LED
#define OUT D7 //Broche du capteur PIR
int status = LOW; //Statut du mouvement : LOW : pas de mouvement détecté
bool outValue = 0; //Valeur du capteur
long beginTime = 0; //instant du déclenchement lors de la ldétection d'un mouvement
void setup()
{
pinMode(LED, OUTPUT); //LED en sortie
pinMode(OUT, INPUT); //Broche du capteur en entrée
Serial.begin(9600); //Vitesse de communication à 9600 bauds
}//End setup
void loop(){
outValue = digitalRead(OUT); //Lire létat du capteur
if (outValue == HIGH) //Détection d'un mouvement
{
digitalWrite(LED, HIGH); //Allume la LED
if (status == LOW)
{
Serial.println(">>> Mouvement ");
status = HIGH; //Mise à jour du statut du capteur
beginTime = millis(); //Sauvegarde du temps
}//End if
}
else //Aucun mouvement
{
digitalWrite(LED, LOW); //Eteint la LED
if(status == HIGH) //Fin de détection
{
Serial.print(">>> Fin du mouvement");
status = LOW; //Mise à jour du statut du capteur
unsigned long duree = millis() - beginTime; //Calcul de la durée du mouvement
Serial.print(">>> Duree = ");
Serial.print(duree);
Serial.println(" ms");
}//End if
}//End else
}//End loop
Utilisation d’un écran OLED
Récupération de l’adresse I2C
Pour tous les périphériques I2C, il convient de connaître l’adresse du périphérique. Or parfois on ne s’en rappel plus.
Il existe un code qui permet de scanner toutes les adresses possibles et d’afficher l’adresse du composant qui est relié au bus I2C.
Voici le code, disponible dans les exemples de la classe Wire [note] :
void loop()
{
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ )
{
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0)
{
Serial.print("I2C device found at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.print(address,HEX);
Serial.println(" !");
nDevices++;
}
else if (error==4)
{
Serial.print("Unknow error at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
}
delay(5000);
}
Code complet
#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"
#define I2C_ADDRESS 0x3C
SSD1306AsciiAvrI2c oled;
void setup() {
//Init size
oled.begin(&Adafruit128x64, I2C_ADDRESS);
oled.setFont(Adafruit5x7);
oled.clear();
oled.set2X();
oled.println("CREPP");
oled.set1X();
oled.println("Club de");
oled.println("Robotique et");
oled.println("d'Electronique");
oled.println("Programmable");
}
void loop() {
}