Les GPIO du Raspberry pi peuvent être utilisés en sortie (écriture), mais également en entrée (lecture). Nous nous intéresserons ici à cette seconde possibilité, qui permettra au Raspberry pi de recevoir des informations du monde extérieur. L’objectif de ce tutoriel est de s’appuyer sur le tutoriel sur l’utilisation d’un GPIO en sortie pour contrôler une LED, et d’y ajouter le fait de lire un bouton poussoir connecté sur un autre GPIO pour changer l’état de cette LED. Il est également possible d’accéder à la liste des tutoriels sur le Raspberry pi pour voir d’autres utilisations.
Ce tutoriel est la version “blog” du tutoriel que j’ai posté sur le wiki sur ce sujet, et remplace le précédent billet sur le sujet, que j’ai donc entièrement réécrit.
Lecture bouton Raspberry pi : Prérequis
Pour ce tutoriel, nous aurons besoin d’un Raspberry Pi (A, A+, B, B+) configuré, ainsi que d’une breadboard, une LED, une résistance de 68 a 300 Ohms pour la LED, d’un bouton poussoir, d’une résistance de 2KOhms à 10KOhms, et enfin de quelques câbles pour breadboard “jumper wire”. Il est également conseillé d’avoir lu le tutoriel sur l’utilisation d’un GPIO en sortie pour contrôler une LED, puisque nous nous baserons dessus.
Montage de type “pull-up” : résistance de tirage
Nous reprendrons donc l’installation du tutoriel mentionné dans les prérequis. Nous ajouterons un câble connectant la broche en haut à gauche des GPIO au rail positif de la breadboard. Cette broche fournit du 3.3V, le niveau logique accepté par les GPIO en entrée. Il convient de faire attention à ne pas utiliser le 5V à la place, car dans ce cas, on pourrait rendre les GPIO connectés définitivement inutilisables, voir le Raspberry pi tout entier.
Le bouton poussoir sera ajouté au milieu de la breadboard, à cheval sur les deux rangées de trous. la broche du haut sera connectée à la masse, tandis qu’une résistance d’une valeur de 1 à 10 kilo-Ohms connectera la seconde broche au rail d’alimentation 3.3V. Enfin, un câble viendra s’intercaler sur entre la résistance et la broche du bouton connectée à celle ci, et sera connecté sur le GPIO 17, à savoir le sixième en partant du haut sur la colonne de gauche. Nous obtenons le résultat suivant :
Vous pouvez également télécharger le schéma de câblage d’un bouton poussoir avec une résistance de tirage pull-up en version PDF.
Puisque nous souhaitons lire la valeur d’un bouton poussoir, nous utilisons logiquement un GPIO supplémentaire. La nouvelle résistance ajoutée ici est une résistance de tirage. Elle devra avoir une valeur comprise entre 1 et 10KOhms, ici il s’agit d’une 4.7KOhms.
Son rôle est de fixer la valeur lue lorsque l’on appuie pas sur le bouton. Sans cela, nous aurions une valeur dite “flottante”, c’est à dire variable de façon imprévisible. Dans ce cas, il s’agit d’une résistance de tirage, ou pull-up resistor en anglais, et elle tire la valeur vers le 3.3V, ce qui correspondra à un 1 logique (signal haut).
Montage de type “pull-down” : résistance de rappel
Une autre solution serait de faire le contraire, c’est à dire de faire en sorte que la valeur lue par défaut, lorsque l’on n’appuie pas sur le bouton, soit nulle. Cette configuration est très proche, et utilise une résistance de rappel dite pull down. Notre montage change peu, puisque cette fois ci, la première broche du bouton poussoir est connectée au rail 3.3V, tandis que la résistance sera connectée à la masse, comme on peut le voir sur ce schéma :
Vous pouvez également télécharger le schéma de câblage d’un bouton poussoir avec une résistance de tirage pull-down en version PDF.
Code minimal en C
Le code en C sera relativement simple. Ici nous donnons un exemple basé sur une résistance de tirage (pull-up), mais il suffira d’inverser les valeurs logiques pour avoir le code pour une version rappel (pull-down).
#include <stdio.h> #include <wiringPi.h> int main(void) { int switchPin=0; if(wiringPiSetup()==-1) {return 0;} //le port GPIO du bouton est configuré en lecture pinMode(switchPin,INPUT); int button=0; while(1) { //on lit la valeur de la broche GPIO button=digitalRead(switchPin); if(button==0)//Si un appui sur le bouton est détecté { //on affiche un message printf("button pressed!\n"); //cette boucle permet de gerer un appui continu while(button==0) { //on relit la valeur à chaque fois button=digitalRead(switchPin); delay(20);//et on attend 20ms } } delay(20);//on attend 20ms entre chaque lecture. } return 0; }
Vous pouvez également télécharger le fichier source C du programme permettant de lire l’état du bouton en suivant ce lien.
On compile ensuite le code :
gcc readButton.c -o readButton -lwiringPi
On peut alors exécuter le programme :
sudo ./readButton
L’attente de 20 millisecondes (delay(20);) sert non seulement à ne pas surcharger le CPU, mais également à filtrer le rebond du bouton. Comme il s’agit d’un dispositif imparfait, sans cette attente, nous aurions une successions de changements d’états (0-1-0-1-0-1 …) lors des phases d’appui et de relâchement du bouton. Ce phénomène ne survient pas lorsque le bouton est maintenu enfoncé ou lorsque l’on ne le touche pas, mais uniquement sur les transitions. La seconde boucle permet de ne considérer qu’un seul appui tant que le bouton est maintenu enfoncé, sinon, nous aurions une succession d’appuis, et un affichage toutes les 20ms tant que le bouton est maintenu enfoncé. Cela peut paraître superflu, mais sans cela, si vous appuyez fugitivement sur le bouton, mais tout de même plus de 20ms, il y aurait au moins deux pressions de comptabilisées.
Cela s’appelle en anglais le debouncing. On peut également utiliser un condensateur pour atténuer le rebond, et potentiellement ne pas avoir à faire de debouncing logiciel.
Code utilisant le bouton et la LED en C
On peut maintenant réutiliser la LED installée pour cette fois ci changer l’état de celle ci selon les appuis. On obtient un code de ce genre :
#include <stdio.h> #include <wiringPi.h> int main(void) { int switchPin=0; int ledPin =7; if(wiringPiSetup()==-1) {return 0;} //le port GPIO du bouton est configuré en lecture pinMode(switchPin,INPUT); //le port GPIO de la LED est configuré en ecriture pinMode(ledPin,OUTPUT); int button=0; int ledState=0;//état initial de la LED digitalWrite(ledPin,ledState);//on eteint la LED au départ while(1) { //on lit la valeur de la broche GPIO button=digitalRead(switchPin); if(button==0)//Si un appui sur le bouton est détecté { //on affiche un message printf("button pressed!\n"); if(ledState==0) {ledState=1;} else {ledState=0;} digitalWrite(ledPin,ledState);//on applique le nouvel état de la LED //cette boucle permet de gerer un appui continu while(button==0) { //on relit la valeur à chaque fois button=digitalRead(switchPin); delay(20);//et on attend 20ms } } delay(20);//on attend 20ms entre chaque lecture. } return 0; }
Vous pouvez également télécharger le code C du programme permettant de lire le bouton pour changer l’état d’une LED en suivant ce lien.
Code minimal en python
Voyons maintenant le code minimal en python :
import time from RPi import GPIO GPIO.setmode(GPIO.BOARD) GPIO.setup(0, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) while True: inputval = GPIO.input(0) print inputval time.sleep(1)
Vous pouvez également télécharger le code python minimal du programme permettant de lire le bouton en suivant ce lien.
On exécute le code par :
sudo python readButton.py
Conclusions
Il est donc possible d’utiliser un GPIO comme entrée, pour lire des informations du monde extérieur. Ici, nous lisons des données numériques. Il est toutefois possible d’utiliser un convertisseur MCP3008 pour ajouter des entrées analogiques au Raspberry pi (tutoriel sur ce site) et ainsi lire des données analogiques.
Il est primordial de ne pas envoyer de courant à une tension supérieure à 3.3V aux GPIO sous peine de risquer d’endommager le/les GPIO voir le Raspberry pi tout entier.
On pourra se demander comment avons nous choisi la valeur de la résistance de tirage/rappel. Il s’agit en fait de valeurs assez universelles dans ce types de montages. Si l’on ne sait pas quoi prendre, les 4.7 et 10K feront généralement l’affaire. Il est cependant possible d’aller plus loin en cherchant les valeurs optimales de la résistance de tirage selon le circuit.
Bonjour, pouvez vous m’indiquer quel programme vous utilisez pour générer vos schémas svp ?? Merci d’avance.
Bonjour,
dans ce cas, il s’agit d’un editeur d’images classiques (genre gimp), mais depuis, j’utilise fritzing, qui est particulièrement adapté.
Les images utilisées pour les schemas de cette page étaient libre de droits, j’ai rajouté un calque pour mettre les fils et les composants.
Mais encore une fois, avec fritzing, ça va bien plus vite.
D’ailleurs pour les prochains tutos, je mettrai également le fichier source de fritzing, que chacun puisse modifier le schema à sa guise facilement.
Ne pourrait on pas brancher un condensateur aux bornes du bouton poussoir pour lisser les rebonds ? Cela permettrait de remplacer la seconde boucle par un simple test de changement d’état, ce changement ne pourrait plus intervenir avant une durée minimale R*C. Le delay serait ainsi totalement décorrelé de la durée minimale de transition.
Bonjour Julien,
Effectivement, nous pourrions utiliser un condensateur pour faire le “debounce”. C’est une autre approche, tout à fait valable; toutefois ici j’ai présenté l’approche logicielle, afin de ne pas ajouter de composants supplémentaires.
Pour ce qui est du delay, ici c’est une solution un peu facile en effet, dans l’absolu, je ne ferais plus de cette façon maintenant. En effet, si l’on se passe de condensateur, une solution un peu plus élégante serait de vérifier si un certain temps est écoulé depuis la dernière lecture, plutôt que de faire un delay() bloquant. Ainsi, il devient possible d’analyser l’état de nombreux capteurs, boutons, potentiomètres, etc, en parallèle.
Au passage, j’ai commencé à mettre ces tutoriels en forme sur un wiki, avec une meilleure mise en page, et j’en profiterai pour compléter ce genre de détails, et améliorer/corriger les exemples de code 🙂