Je dis toujours : « Avant de vous lancer dans un projet de tondeuse à gazon guidée par GPS avec évitement d’obstacles à laser et retour vidéo, apprenez déjà à allumer une LED
» …
Enfin, vous faites comme vous voulez, ce n’est que mon avis… Patrice nous propose dans son premier article pour framboise314 de faire clignoter une LED avec un Raspberry Pi … Un tracteur pour déplacer un œuf me direz vous !
Mais La Saga Blink aborde de nombreuse façons de le faire. Au menu: bash, Python, nodejs, wiringpi, pigpio, Rpi.GPIO …
Introduction
Rien de neuf sous les tropiques car il existe une multitude de tutoriels, de présentations et autres billets sur le sujet. La présentation s’adresse aux débutants expérimentés c’est à dire ceux qui disposent d’un Raspberry Pi opérationnel et qui n’ont pas peur d’utiliser la console pour l’élaboration des programmes. Les experts n’ont pas besoin de cette présentation et la trouveront certainement inutile.
Il faut, à un moment donné, un début.
Faire clignoter une LED sur le Raspberry Pi ou autres cartes consœurs (Arduino, ChipKit, LaunchPad, etc…) est le pendant du traditionnel « Hello World ! » de l’apprentissage d’un langage de programmation.
Base d’expérimentation.
Pour notre expérimentation, il nous faut :
- Un raspberry Pi opérationnel,
- Une LED,
- Une résistance de 330 Ω (ou entre 330 et 470 Ω).
Schéma électronique
L’anode de la diode LED (patte longue) est raccordée à la sortie GPIO23 (broche 16 du connecteur P5).
La cathode (patte courte) est reliée à la masse du Raspberry Pi (Ground), par exemple la pin 20 du connecteur P5.
La résistance R1 sert à limiter le courant traversant la LED. Plus cette résistance est élevée et moins le courant sera élevé. Attention, une résistance trop faible risque de détruire la sortie GPIO par dépassement du courant maximal.
Schéma de câblage
Le câblage est simple et demande que peu de composants. On peut le réaliser avec un cobbler comme sur la photo de la figure 1 ou par une connexion directe sur le port GPIO du raspberry (voir figure 3).
Le cobbler est un accessoire qui permet de déporter les pins du GPIO vers une plaque d’essai (breadboard).
Remarque : Le RPI3 de la photo figure 3 est équipé de l’écran officiel de la Fondation mais non utilisé dans les expérimentations qui suivent.
Cahier des charges.
Tout programmeur qui se respecte doit disposer ou établir un cahier des charges qui défini les différentes opérations à réaliser. Dans notre cas, il sera très simple.
Notre cahier des charges :
- allumer la led,
- attendre 1 seconde,
- éteindre la led,
- attendre 1 seconde,
- continuer en 1) (on répète indéfiniment la boucle)
Organigramme
L’organigramme est une représentation graphique du déroulement de notre programme. Il comporte les différentes étapes qui permettront une transcription dans un langage donné.
Le premier pavé, qui nous intéresse, est « Initialisation » qui consiste à préparer la pin GPIO23 pour qu’elle puisse piloter la led.
Après cette phase, il faut allumer la LED.
Puis attendre x secondes (dans notre cas 1 sec.).
Après cette attente, on éteint la LED.
Suivi d’une nouvelle attente de x secondes (1 sec. pour notre exemple).
Et finalement, on reprend le cycle en allumant la LED et cela indéfiniment (boucle infinie).
Programmation.
Les différents programmes abordés dans la suite peuvent être exécutés sur toutes les versions du Raspberry Pi (type A, B, jusqu’au RPI3 y compris le Zero).
La saisie des programmes se fait via un éditeur de texte graphique (par exemple geany) ou en mode console (par exemple nano).
L’accès au Raspberry Pi peut se faire via son interface écran HDMI / clavier ou bien par l’intermédiaire d’un connexion à distance (mode console ou graphique).
Pour ma part, j’utilise une connexion console via une liaison SSH.
Dans la suite, nous verrons quelques programmes qui effectuent tous les mêmes actions (allumer / éteindre la LED) mais dans des langages différents.
Bash
Dans l’os Linux tout est « fichier » donc nous ferons des opérations de création, lecture, écriture et suppression de fichiers.
Programme
Pour saisir ce programme, il faut faire dans la console :
nano blink90.sh
Cette commande ouvre un fichier texte vide appelé bilnk90.sh (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
La combinaison Ctrl+o signifie l’appuie sur la touche Ctrl ainsi que la touche o.
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/bin/bash #Programme classique LED clignotante #Led rouge sur GPIO23 via une résistance de 330 Ohms #logiciel : bash #cible : raspberry Pi #date de création : 17/06/2016 #date de mise à jour : 18/06/2016 #version : 1.0 #auteur : icarePetibles #référence : #Remarques : Pour fonctionner, il faut être sous super utilisateur # Il faut rendre le fichier exécutable avec # sudo chmod +x blink90.sh # Pour exécuter le fichier, il faut faire # sudo ./blink90.sh # #Attention : Ce script à des effets de bord lorsqu'on interrompt la boucle # infinie par Ctrl-C. On a des messages d'errreur lors de la relance # du script mais fonctionne néanmoins # echo "23" > /sys/class/gpio/export #assigne pin echo "out" > /sys/class/gpio/gpio23/direction #en sortie while true; #boucle infinie do echo "1" > /sys/class/gpio/gpio23/value #allume led # echo "Led allumée" #message IHM sleep 1; #attente 1 sec echo "0" > /sys/class/gpio/gpio23/value #éteint led # echo "Led éteinte" #message IHM sleep 1; #attente 1 sec done #fin script
Si l’on supprime les lignes de commentaires, il ne reste plus que 9 lignes.
Les commentaires sont importants si l’on souhaite reprendre un programme après quelques jours car notre mémoire n’est pas fiable. Ce qui était évident lors de l’écriture du programme devient incompréhensible. On peut également insérer des remarques concernant l’utilisation du programme (lignes 11 à 20).
Les lignes 21 et 22 correspondent à la phase « Initialisation« .
L’allumage de la LED se fait ligne 25 suivi d’une attente d’une seconde ligne 27.
L’extinction de la led se fait ligne 28 suivi de l’attente ligne 30.
Si l’on dé-commandante les lignes 26 et 29, le programme affiche également l’état de la LED dans la console.
Exécution du programme.
Pour exécuter ce programme bash, il faut le rendre exécutable avec la commande :
sudo chmod +x blink90.sh
Et pour l’exécuter :
sudo ./blink90.sh
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier (voir la remarque lignes 17 à 19 du programme).
Python
Le pilotage des ports GPIO, sous Python s’appuie sur des bibliothèques. Les bibliothèques RPi.GPIO et gpiozero sont incluses dans les versions de Python. Nous utiliserons également les bibliothèques pigpio et wiringpi qui devront être installées sous Python.
Rpi.GPIO
Programme
Pour saisir ce programme, il faut faire dans la console :
nano blink01.py
Cette commande ouvre un fichier texte vide appelé bilnk01.py (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/usr/bin/python3 # -*- coding:utf-8 -*- """ Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 Ohms logiciel : python 3.4.2 cible : raspberry Pi date de création : 08/06/2016 date de mise à jour : 08/06/2016 version : 1.0 auteur : icarePetibles référence : """ #------------------------------------------------------------------------------- # Bibliothèques #------------------------------------------------------------------------------- import RPi.GPIO as GPIO #bibliothèque RPi.GPIO import time #bibliothèque time #------------------------------------------------------------------------------- GPIO.setwarnings(False) #désactive le mode warning GPIO.setmode(GPIO.BCM) #utilisation des numéros de ports du #processeur GPIO.setup(23, GPIO.OUT) #mise en sortie du port GPIO 23 (broche #16 du connecteur) if __name__ == '__main__': """ Programme par défaut """ # print(sys.version) #affiche version python print("Début du programme LED clignotante") #message IHM while True : #boucle infinie GPIO.output(23, GPIO.HIGH) #sortie 23 high time.sleep(1) #attente 1 seconde GPIO.output(23, GPIO.LOW) #sortie 23 low time.sleep(1) #attente 1 seconde #-------------------------------------------------------------------------------
Les lignes 20 à 24 correspondent à la phase « Initialisation ».
L’allumage de la LED se fait ligne 34 suivi d’une attente d’une seconde ligne 35.
L’extinction de la LED se fait ligne 36 suivie de l’attente ligne 37.
La ligne 31 transmet un message console signalant le démarrage du programme.
Exécution du programme
Pour exécuter ce programme, il faut lancer la commande suivante dans la console Linux :
python3 blink01.py
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
Commentaire bibliothèque
La documentation concernant cette librairie est faible au niveau de la toile. On trouvera quelques informations sur le site :
https://sourceforge.net/p/raspberry-gpio-python/wiki/Home/
On peut également avoir des informations sous Python par les commandes suivantes :
python3 >>> import Rpi.GPIO as gp >>> help(gp)
Rappel : pour sortir de l’interpréteur python, il suffit de faire Ctrl+d
Remarque : le contenu de cette librairie est étique et ne gère pas les bus I²C ou SPI.
gpiozero
Programme
Pour saisir ce programme, il faut faire dans la console :
nano blink20.py
Cette commande ouvre un fichier texte vide appelé bilnk20.py (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/usr/bin/python3 # -*- coding:utf-8 -*- """ Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 Ohms logiciel : python 3.4.2 cible : raspberry Pi date de création : 09/06/2016 date de mise à jour : 09/06/2016 version : 1.0 auteur : icarePetibles référence : https://gpiozero.readthedoc.io/en/v1.2.0/ """ #------------------------------------------------------------------------------- # Bibliothèques #------------------------------------------------------------------------------- from gpiozero import LED #bibliothèque gpiozero from time import sleep #sleep de la bibliothèque time #------------------------------------------------------------------------------- if __name__ == '__main__': """ Programme par défaut """ led = LED(23) #instance LED sur GPIO23 while True: #boucle infinie led.on() #allume led sleep(0.5) #pause 0.5 sec led.off() #éteind led sleep(0.5) #pause 0.5 sec #-------------------------------------------------------------------------------
La ligne 24 correspond à la phase « Initialisation ».
L’allumage de la LED se fait ligne 26 suivi d’une attente d’une demi-seconde ligne 27. L’extinction de la LED se fait ligne 28 suivi de l’attente ligne 29.
Exécution du programme
Pour exécuter ce programme, il faut lancer la commande suivante dans la console Linux :
python3 blink20.py
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
Commentaire bibliothèque
La documentation pour cette librairie peut être consultée sur le site :
https://gpiozero.readthedocs.io/en/v1.2.0/
On peut également avoir quelques informations supplémentaires par les commandes suivantes :
python3 >>> import gpiozero >>> help(gpiozero)
Rappel : pour sortir de l’interpréteur Python, il suffit de faire Ctrl+d
Remarque : le contenu de cette librairie est nettement plus riche en méthodes que la précédente et gère le bus I²C ou SPI.
wiringpi
Programme
Pour utiliser la bibliothèque wiringpi, il faut l’installer au préalable. On trouvera la procédure l’installation sous le lien :
https://github.com/WiringPi/WiringPi-Python/
Pour saisir ce programme, il faut faire dans la console :
nano blink60.py
Cette commande ouvre un fichier texte vide appelé bilnk60.py (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/usr/bin/python3 # -*- coding:utf-8 -*- """ Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 Ohms logiciel : python 3.4.2 cible : raspberry Pi date de création : 21/06/2016 date de mise à jour : 21/06/2016 version : 1.0 auteur : icarePetibles référence : wiringpi.com Remarques : """ #------------------------------------------------------------------------------- # Bibliothèques #------------------------------------------------------------------------------- import wiringpi #bibliothèque wiringpi #------------------------------------------------------------------------------- if __name__ == '__main__': """ Programme par défaut """ print("\nDébut du programme LED clignotante") #messages IHM LED = 4 #sortie LED sur GPIO23 = 4 mode wiringpi DUREE = 1000 #durée demi période = 1 sec ON = 1 OFF = 0 wiringpi.wiringPiSetup() #mode wiringpi ou "pseudo Arduino" wiringpi.pinMode(LED, 1) #pi en sortie sortie wiringpi.digitalWrite(LED, OFF) #led éteinte while True: #boucle infinie wiringpi.digitalWrite(LED, ON) #allume led wiringpi.delay(DUREE) #attente DUREE wiringpi.digitalWrite(LED, OFF) #éteind led wiringpi.delay(DUREE) #attente DUREE #-------------------------------------------------------------------------------
Les lignes 30 à 32 correspondent à la phase « Initialisation ».
L’allumage de la LED se fait ligne 34 suivi d’une attente d’une seconde ligne 35.
L’extinction de la LED se fait ligne 36 suivi de l’attente ligne 37.
La ligne 24 transmet un message console signalant le démarrage du programme.
Exécution du programme
Pour exécuter ce programme, il faut lancer la commande suivante dans la console Linux avec les privilèges root :
sudo python3 blink60.py
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
Commentaire bibliothèque
La documentation pour cette librairie peut être consultée sur le site :
http://wiringpi.com/reference/
On peut également avoir quelques informations supplémentaires par les commandes suivantes :
python3 >>> import wiringpi >>> help(wiringpi)
Rappel : pour sortir de l’interpréteur python, il suffit de faire Ctrl+d
Remarque : le contenu de cette librairie est également très riche en méthodes et gère le bus I²C ou SPI.
Langage C
Le pilotage des ports GPIO, sous C s’appuie sur la bibliothèque wiringPi. L’installation de cette bibliothèque et décrite sur le site de wiringPi sous le lien : http://wiringpi.com/download-and-install/
wiringPi
Programme
Pour saisir ce programme, il faut faire dans la console :
nano blink80.c
Cette commande ouvre un fichier texte vide appelé blink80.c (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme classique LED clignotante Led rouge sur GPIO23 (4) via une résistance de 330 ohms os : RPi Linux 4.4.13+ logiciel : gcc (Raspbian 4.9.2-10) 4.9.2 cible : raspberry Pi date de création : 21/06/2016 date de mise à jour : 22/06/2016 version : 1.0 auteur : icarePetibles référence : www.wiringpi.com Remarques : ----------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------- Bibliothèques ----------------------------------------------------------------------------- */ #include <stdio.h> //utilisé pour printf() #include <wiringPi.h> //bibliothèque wiringPi //------------------------------------------------------------------------------ #define LED 4 //numéro led = GPIO23 int main(void){ //programme principale printf("Led clignotante\n"); //IHM wiringPiSetup(); //numérotation wiringPi ou "pseudo Arduino" pinMode(LED, OUTPUT); //pin en sortie for(;;){ //boucle infinie digitalWrite(LED, HIGH); //allume led delay (500); //attente 0.5 sec digitalWrite(LED, LOW); //éteint led delay (500); //attente 0.5 sec } return(0); //code sortie } //------------------------------------------------------------------------------
Les lignes 23 et 24 correspondent à la phase « Initialisation ».
L’allumage de la LED se fait ligne 26 suivi d’une attente de 0.5 seconde ligne 27.
L’extinction de la LED se fait ligne 28 suivie de l’attente ligne 29.
La ligne 22 transmet un message console signalant le démarrage du programme.
Exécution du programme
Pour exécuter se programme, il faut d’abord le compiler. La compilation se fait par la commande ci-dessous (en mode console) :
gcc -Wall -o blink80 blink80.c -lwiringPi
Le résultat de la compilation est un fichier : blink80
Lancement du programme :
sudo ./blink80
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
Commentaire bibliothèque
La documentation pour cette librairie peut être consultée sur le site :
http://wiringpi.com/reference/
Cette bibliothèque est la même que celle utilisée au paragraphe 4.3 mais qui elle était adaptée à Python.
Perso
Une petite récréation avec une bibliothèque GPIO personnelle qui n’apporte rien de particulier et elle est même un tantinet « capillotracté ».
La bibliothèque se compose de 2 fichiers ipsGPIO.h (fichier entête) et ipsGPIO.c (fichier fonctions) qui sont utilisés dans le programme blink50.c pour piloter le port GPIO du Raspberry Pi.
Programme
Bibliothèque perso
Pour saisir ce programme ipsGPIO.h, il faut faire dans la console :
nano ipsGPIO.h
Cette commande ouvre un fichier texte vide appelé ipsGPIO.h (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme classique LED clignotante Fichier entête de ipsGPIO.c os : RPi Linux 4.4.13+ (Jessie) logiciel : gcc (Raspbian 4.9.2-10) 4.9.2 cible : raspberry Pi date de création : 26/06/2016 date de mise à jour : 28/06/2016 version : 1.0 auteur : icarePetibles référence : Remarques : ----------------------------------------------------------------------------- */ #ifndef IPS_H #define IPS_H //directives constantes #define ENTREE 0 #define SORTIE 1 #define DESACTIVE 2 #define HAUT 1 #define BAS 0 #define VRAI 1 #define FAUX 0 //prototypes fonctions void afficheLn(const char * nom); //eq. println() void affiche(const char * nom); //eq. print() void modeBroche(int, int); //eq. pinMode() void ecritureDigitale(int, int); //eq. digitalWrite() void dormir(unsigned int); //eq. delay() unsigned long int mTemps(void); //eq. millis() #endif
Ce fichier contient les définitions des constantes et les prototypes des fonctions.
Pour saisir ce programme ipsGPIO.c, il faut faire dans la console :
nano ipsGPIO.c
Cette commande ouvre un fichier texte vide appelé ipsGPIO.c (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme classique LED clignotante Fichier bibliothèque ipsGPIO.c os : RPi Linux 4.4.13+ (Jessie) logiciel : gcc (Raspbian 4.9.2-10) 4.9.2 cible : raspberry Pi date de création : 26/06/2016 date de mise à jour : 28/06/2016 version : 1.0 auteur : icarePetibles référence : Remarques : ----------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------- Bibliothèques ----------------------------------------------------------------------------- */ #include <stdio.h> //bibliothèque entrées/sorties #include <string.h> //manipulation chaîne #include <stdlib.h> //conversion nombre et autres #include <unistd.h> //types et constantes #include "ipsGPIO.h" //bibliothèque ipsGPIO /* ---------------------------------------------------------------------------- Fonction affichage avec retour ligne suivant SYNTAXE : afficheLn("texte") eq. println() ---------------------------------------------------------------------------- */ void afficheLn(const char * nom){ printf("%s\n", nom); //IHM } /* ---------------------------------------------------------------------------- Fonction affichage sans retour ligne suivant SYNTAXE : affiche("texte") eq. print() ---------------------------------------------------------------------------- */ void affiche(const char * nom){ printf("%s", nom); //IHM } /* ---------------------------------------------------------------------------- Fonction définition du mode de fonctionnement de la broche SYNTAXE : modeBroche(BROCHE, MODE) BROCHE : Port GPIOXX MODE : ENTREE = 0, SORTIE = 1 ou DESACTIVEE = 2 eq. pinMode() ---------------------------------------------------------------------------- */ void modeBroche(int broche, int mode){ char bufferBroche[10]; //buffer de conversion sprintf(bufferBroche, "%d", broche); //conversion int en string char commande[50] = ""; //buffer commande if(mode == 1){ //broche en sortie //commande bash pour assigner le port //echo PIN > /sys/class/gpio/export strcpy(commande, "echo "); //composition commande par concaténation strcat(commande, bufferBroche);//composition commande strcat(commande, " > /sys/class/gpio/export"); //composition commande system(commande); //envoi commande système //commande bash pour assigner le port en sortie //echo out > /sys/class/gpio/gpioPIN/direction strcpy(commande, "echo out > /sys/class/gpio/gpio"); //composition commande par concaténation strcat(commande, bufferBroche);//composition commande strcat(commande, "/direction");//composition commande system(commande); //envoi commande système } else if(mode == 2){ //broche déactivée //commande bash pour désactiver le port //echo PIN > /sys/class/gpio/unexport strcpy(commande, "echo "); strcat(commande, bufferBroche); strcat(commande, " > /sys/class/gpio/unexport"); system(commande); } else { //broche en entrée *** en attente *** // //commande bash pour assigner le port // //echo PIN > /sys/class/gpio/export // strcpy(commande, "echo "); //composition commande par concaténation // strcat(commande, bufferBroche);//composition commande // strcat(commande, " > /sys/class/gpio/export"); // //composition commande // system(commande); //envoi commande système // //commande bash pour assigner le port en entrée // //echo in > /sys/class/gpio/gpioPIN/direction // strcpy(commande, "echo in > /sys/class/gpio/gpio"); // //composition commande par concaténation // strcat(commande, bufferBroche);//composition commande // strcat(commande, "/direction");//composition commande // system(commande); //envoi commande système } } /* ---------------------------------------------------------------------------- Fonction écriture état de sortie de la broche SYNTAXE : ecritureDigitale(BROCHE, ETAT) BROCHE : XX (Port GPIOXX) ETAT : HAUT = 1 = 3.3V ou BAS = 0 = 0V eq. digitalWrite() ---------------------------------------------------------------------------- */ void ecritureDigitale(int broche, int etat){ char bufferBroche[10]; //buffer de conversion sprintf(bufferBroche, "%d", broche); //conversion int en string char commande[50] = ""; //buffer commande if(etat == 1){ //état HAUT //commande bash pour état haut //echo 1 > /sys/class/gpio/gpioPIN/value strcpy(commande, "echo 1 > /sys/class/gpio/gpio"); //composition commande par concaténation strcat(commande, bufferBroche);//composition commande strcat(commande, "/value"); //composition commande system(commande); //envoi commande système } else { //état BAS //commande bash pour état bas //echo 0 > /sys/class/gpio/gpioPIN/value strcpy(commande, "echo 0 > /sys/class/gpio/gpio"); //composition commande par concaténation strcat(commande, bufferBroche);//composition commande strcat(commande, "/value"); //composition commande system(commande); //envoi commande système } } /* ---------------------------------------------------------------------------- Fonction attente blocante SYNTAXE : dormir(TEMPS) TEMPS : XX (en milli-seconde) eq. delay() ---------------------------------------------------------------------------- */ void dormir(unsigned int temps){ temps = temps * 1000; //temps en micro-seconde usleep(temps); //attente } /* ---------------------------------------------------------------------------- Fonction retourne le temps système SYNTAXE : TEMPS = mTemps() TEMPS : XX (en milli-seconde) eq. millis() ---------------------------------------------------------------------------- */ unsigned long int mTemps(void){ unsigned long int temps = 0; //variable enttière double uptime, idleTime; //variables décimales FILE* fp; //variable fichier fp = fopen("/proc/uptime", "r"); //ouverture fichier en lecture fscanf(fp, "%lf %lf\n", uptime, idleTime); //lecture données fclose(fp); //fermeture fichier temps = (unsigned long int)(uptime * 1000); //mise en forme sec en msec return temps; //retour temps } /* ------------------------------------------------------------------------- */
Le principe de ce programme est relativement simple puisqu’on appelle des commandes « bash » à partir d’un programme en C (system(commande)).
Les commentaires du programme sont auto-suffisants pour la compréhension.
Programme blink
Pour saisir ce programme blink50.c, il faut faire dans la console :
nano blink50.c
Cette commande ouvre un fichier texte vide appelé blink50.c (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 ohms os : RPi Linux 4.4.13+ (Jessie) logiciel : gcc (Raspbian 4.9.2-10) 4.9.2 cible : raspberry Pi date de création : 22/06/2016 date de mise à jour : 22/06/2016 version : 1.0 auteur : icarePetibles référence : Remarques : ----------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------- Bibliothèques ----------------------------------------------------------------------------- */ #include <stdio.h> //bibliothèque entrées/sorties #include "ipsGPIO.h" //bibliothèque ipsGPIO #define LED 23 //led sur GPIO23 int main(void){ //programme principal affiche("Led clignotante"); //IHM afficheLn(" by icarePetibles"); //IHM modeBroche(LED, SORTIE); //GPIO23 en sortie for(;;){ //boucle infinie ecritureDigitale(LED, HAUT); //allume led dormir(1000); //attente ecritureDigitale(LED, BAS); //éteint led dormir(1000); //attente } return 0; //code sortie }
La syntaxe utilisée est proche de celle de wiringPi ou Arduino mais en français.
La ligne 25 correspondent à la phase « Initialisation ».
L’allumage de la LED se fait ligne 27 suivi d’une attente d’une seconde ligne 28.
L’extinction de la LED se fait ligne 29 suivie de l’attente ligne 30.
Les lignes 23 et 24 transmettent des messages console signalant le démarrage du programme.
Exécution du programme
Pour exécuter ce programme, il faut d’abord le compiler. La compilation se fait par la commande ci-dessous (en mode console) pour les différents fichiers C en créant des fichier objet :
gcc -c ipsGPIO.c gcc -c blink50.c
Et pour terminer, il faut créer le fichier final via l’éditeur de lien :
gcc -o blink50 blink50.o ipsGPIO.o
Le résultat de la compilation est un fichier : blink50
Lancement du programme :
sudo ./blink50
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
Remarque : On peut supprimer les fichiers objets (.o) du répertoire courant par :
rm *.o
Commentaire bibliothèque
Cette bibliothèque n’a rien d’extraordinaire mais montre uniquement que l’on peut arriver à ses fins avec un peu d’imagination et peu de moyens.
Comme souvent les solutions ou les erreurs se trouvent localisées entre la chaise et le clavier.
Cette bibliothèque fera certainement l’objet de mise à jour lors d’une autre « Saga ».
Conclusion intermédiaire
La première partie de notre expérimentation se termine. On aurait pu faire la même chose avec d’autres langages de programmation.
Les programmes réalisés ne me conviennent pas, principalement pour les raisons suivantes :
- Lorsqu’on sort de la boucle infinie par une sortie sauvage du genre Ctrl+c, on abandonne la boucle en laissant la sortie GPIO dans un état incertain (ce n’est pas très propre)
- Le temps d’attente dans les boucles est du type bloquant, c’est-à-dire que la tâche attend la fin avant de faire autre chose. On peut admettre ce type de programmation pour une démonstration mais pas dans un programme réel.
- Si on avait réalisé d’autres traitements informatiques dans la boucle sans fin, ils auraient subit des retards d’exécution à cause des attentes bloquantes de la boucle.
On peut corriger cette situation par les programmes qui suivent.
Organigramme
Il comporte les différentes étapes qui permettront une transcription dans un langage donné.
Le premier pavé, qui nous intéresse, est « Initialisation » qui consiste à préparer la pin GPIO23 pour qu’elle puisse piloter la LED.
Après cette phase, on teste si un caractère a été saisi au clavier, si c’est le cas, on sort de la boucle sans fin en éteignant la LED et on désalloue la ressource GPIO.
Dans le cas contraire, on teste si la LED a été allumée ou éteinte pendant un temps égal ou supérieur à DUREE.
Si c’est le cas, on permute l’état de la LED.
Dans le cas contraire, on peut traiter une autre tâche, puis on boucle pour refaire les mêmes opérations.
Bash
Programme
Pour cette partie du programme qui traite des valeurs décimales, il y a lieu d’installer le paquet bc pour que bash puisse faire les traitements correspondants.
sudo apt-get update sudo apt-get install bc
Pour saisir ce programme, il faut faire dans la console :
nano blink93.sh
Cette commande ouvre un fichier texte vide appelé blink93.sh (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/bin/bash #Programme classique LED clignotante #Led rouge sur GPIO23 via une résistance de 330 Ohms #Ajout Gestion Ctrl-C #Ajout attente non bloquante #Ajout vérification mode super utilisateur #logiciel : bash #cible : raspberry Pi #date de création : 18/06/2016 #date de mise à jour : 18/07/2016 #version : 1.0 #auteur : icarePetibles #référence : #Remarques : Pour fonctionner, il faut être sous super utilisateur # Il faut rendre le fichier exécutable avec # sudo chmod +x blink93.sh # Pour exécuter le fichier, il faut faire # sudo ./blink93.sh # LEDPIN=23 #GPIO23 OFF=0 #variable éteindre ON=1 #variable allumée DUREE=1000 #demi-période ETATLED=0 #led éteinte #vérification si accès root #if [ $EUID -ne 0 ] #si $EUID différent de 0 if [ $EUID != "0" ] #si $EUID différent de 0 then #alors echo "Il faut être root pour exécuter le script. Essaye sudo $0" exit #sortie fi #fin if #Procédure de netoyage, éteind led, désactive la sortie cleanup() { PIN=$1 #paramètre transmis # echo $PIN #affiche paramètre transmis #dans notre cas 23 echo $OFF > /sys/class/gpio/gpio$PIN/value #led éteinte echo $PIN > /sys/class/gpio/unexport #désactive port echo #esthétique echo Interruption #message IHM echo Led éteinte et pin désactivée #message IHM echo Fin script #message de fin exit #sortie } #lecture temps function mTemps() { ligne=`cat /proc/uptime` #lit uptime et idletime #valeurs décimales mTemps=$(echo "$ligne" | cut -f 1 -d ' ') #extrait uptime mTemps=$(echo "$mTemps*1000" |bc) #multiplie par 1000 pour #avoir des msec mTemps=${mTemps%%.*} #float to int return $mTemps #valeur mTemps } #programme principal echo Led clignotante #message de début echo ctrl-c pour sortir de la boucle #IHM #Setup pin et direction - Cature Control-C SIGHUP SIGKILL echo $LEDPIN > /sys/class/gpio/export #assigne pin 23 echo out > /sys/class/gpio/gpio$LEDPIN/direction #pin 23 en sortie #trap "cleanup $LEDPIN" 1 2 15 #capture SIGNAL trap "cleanup $LEDPIN" SIGHUP SIGINT SIGTERM #capture SIGNAL et lance la #la procédure cleanup avec #le paramètre 23 mTemps #lecture référence temps valeurPrecedente=$mTemps #sauve temps msec while true #boucle infinie do #faire mTemps #lecture référence temps valeurActuelle=$mTemps #sauve temps msec let "diff=$valeurActuelle - $valeurPrecedente" #calcule durée état if [ $diff -ge $DUREE ] #si temps écoulé >= DUREE then #alors valeurPrecedente=$valeurActuelle #init valeur précédente if [ $ETATLED -eq $ON ] #si led allumée then #alors echo $OFF > /sys/class/gpio/gpio$LEDPIN/value #éteint led # echo Led éteinte #affichage console ETATLED=$OFF #led éteinte else #sinon echo $ON > /sys/class/gpio/gpio$LEDPIN/value #allume led # echo Led allumée #affichage console ETATLED=$ON #led allumée fi fi # #Autres traitements # done #fin do #Fin du script
Les différentes variables sont définies aux lignes 20 à 24, si l’on souhaite modifier la fréquence du clignotement, il suffit de changer la valeur de DUREE (en milli-seconde).
En ligne 27, on teste si on est en mode « sudo » avec le message ad hoc (pas nécessaire dans notre cas).
La fonction cleanup(), ligne 34, permet une sortie « propre » de la boucle sans fin en éteignant la LED et en désactivant le port.
La fonction mTemps(), ligne 48, permet de mesurer le temps écoulé depuis le démarrage du Raspberry PI. Elle permet de mesurer la durée d’allumage/d’extinction de la LED.
Les lignes 62 et 63 correspondent à la phase « Initialisation ».
La ligne 65 capture le signal Ctrl+c et lance la fonction cleanup avec le paramètre correspondant à la LED.
L’allumage (ligne 85) ou l’extinction (ligne 80) de la LED est réalisé lorsque la différence entre valeurPrecedente et valeurActuelle est supérieure ou égale à DUREE.
Exécution du programme
Pour exécuter ce programme bash, il faut le rendre exécutable avec la commande :
sudo chmod +x blink93.sh
Et pour l’exécuter :
sudo ./blink93.sh
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
Python
Rpi.GPIO
Programme
Pour saisir ce programme, il faut faire dans la console :
nano blink04.py
Cette commande ouvre un fichier texte vide appelé blink04.py (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/usr/bin/python3 # -*- coding:utf-8 -*- """ Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 Ohms Ajout d'une possibilité de sortie de la boucle sans fin Ajout temporisation non bloquante logiciel : python 3.4.2 cible : raspberry Pi date de création : 08/06/2016 date de mise à jour : 19/07/2016 version : 1.0 auteur : icarePetibles référence : """ #------------------------------------------------------------------------------- # Bibliothèques #------------------------------------------------------------------------------- import RPi.GPIO as GPIO #bibliothèque RPi.GPIO import time #bibliothèque time #------------------------------------------------------------------------------- if __name__ == '__main__': """ Programme par défaut """ #------------------------------------------------------------------------------- # Constantes #------------------------------------------------------------------------------- DUREE = 0.5 #durée demi période = 0.5 sec LED = 23 #sortie LED sur GPIO23 #------------------------------------------------------------------------------- GPIO.setwarnings(False) #désactive le mode warning GPIO.setmode(GPIO.BCM) #utilisation des numéros de ports du #processeur GPIO.setup(LED, GPIO.OUT) #mise en sortie du port GPIO 23 (broche #16 du connecteur) print("\nDébut du programme LED clignotante") print("Arrêt du clignotement par ctrl+c") #messages IHM GPIO.output(LED, GPIO.HIGH) #initialisation sortie 23 allume led etatLed = True #led allumée previousTime = time.time() #valeur time précédente try: while True : #boucle infinie currentTime = time.time() #sauve time actuel if abs(currentTime - previousTime) >= DUREE: #si temps écoulé >= à DUREE previousTime = currentTime #nouveau time précédent if etatLed: #si led allumée GPIO.output(LED, GPIO.LOW) #éteind led etatLed = False #led éteinte else: #si led éteinte GPIO.output(LED, GPIO.HIGH) #allume led etatLed = True #led allumée #capture du ctrl+c et sortie boucle except KeyboardInterrupt: GPIO.output(LED, GPIO.LOW) #Eteint la LED GPIO.cleanup() #remet toutes pins en entrée print("\nFin du programme\n") #IHM #-------------------------------------------------------------------------------
La phase « Initialisation » est faite aux lignes 32 à 36.
L’allumage (ligne 55) ou l’extinction (ligne 51) de la LED est réalisé lorsque la différence entre previousTime et currentTime est supérieure ou égale à DUREE.
La ligne 59 capture le signal Ctrl+c qui éteint la LED et libère les ressources GPIO.
Exécution du programme
Pour exécuter ce programme, il faut lancer la commande suivante dans la console Linux :
python3 blink04.py
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
gpiozero
Programme
Je déroge un peu de l’organigramme du chapitre 7, sinon on a toujours la même structure du programme. Il existe dans la bibliothèque gpiozero une fonction blink().
Pour saisir ce programme, il faut faire dans la console :
nano blink25.py
Cette commande ouvre un fichier texte vide appelé blink25.py (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/usr/bin/python3 # -*- coding:utf-8 -*- """ Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 Ohms logiciel : python 3.4.2 cible : raspberry Pi date de création : 09/06/2016 date de mise à jour : 19/07/2016 version : 1.0 auteur : icarePetibles référence : https://gpiozero.readthedoc.io/en/v1.2.0/ """ #------------------------------------------------------------------------------- # Bibliothèques #------------------------------------------------------------------------------- from gpiozero import LED #bibliothèque gpiozero #------------------------------------------------------------------------------- if __name__ == '__main__': """ Programme par défaut """ DUREE = 0.5 #durée demi-période print("\nDébut du programme LED clignotante") print("Arrêter le clignotement - ctrl+c") #messages IHM led = LED(23) #instance LED sur GPIO23 led.blink(DUREE, DUREE) #clignote avec valeur par défaut try: while True : #boucle infinie pass #circuler, il n'y a rien à voir except KeyboardInterrupt: #capture ctrl+c print("\nFin du programme\n") #IHM #------------------------------------------------------------------------------- # Documentation #------------------------------------------------------------------------------- # led.blink(0.01, 1, 10, True) #voir Documentation (1) #pause() (attente signal) est remplacé par la boucle infinie while True #(1) #led.blink(on_time=1, off_time=1, n=None, background=True) #on_time = nombre de secondes (float) led allumée #off_time = nombre de secondes (float) led éteinte #n = nombre de clignotement - None = en continu #background = True (défaut) - démarre une tâche (thread) de clignotement # d'arrière plan et retour #background = Flase -retour que si le clignotement et fini (att. avec la valeur # par défaut de n, on n'aura jamais de retour #-------------------------------------------------------------------------------
La structure de ce programme est très simple. La phase « Initialisation » se résume à la ligne 27.
Pour le clignotement de la LED, tout est ligne 28. Le reste n’est que de l’habillage et l’attente de capture du Ctrl+c.
L’utilisation de led.blink() fait clignoter la LED avec les paramètres par défaut, c’est à dire en continu avec une demi-période de 1 seconde.
Syntaxe : Led.blink(on_time=1, off_time=1, n=None, background=True) on_time = durée d'allumage led (en sec) off_time = durée d'extinction led (en sec) n = nombre de clignotement (n=None clignotement continu) background = principe d'exécution de la tâche True (par défaut) = démarre la tâche et retourne False = retour après la fin du clignotement (Attention : avec n=None et background=False, on n'aura plus la main).
Exécution du programme
Pour exécuter ce programme, il faut lancer la commande suivante dans la console Linux :
python3 blink25.py
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
wiringpi
Programme
Pour l’installation de la bibliothèque voir le paragraphe 4.3.1.
Pour saisir ce programme, il faut faire dans la console :
nano blink62.py
Cette commande ouvre un fichier texte vide appelé blink62.py (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/usr/bin/python3 # -*- coding:utf-8 -*- """ Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 Ohms Ajout sortie boucle infinie et attente non blocante logiciel : python 3.4.2 cible : raspberry Pi date de création : 21/06/2016 date de mise à jour : 19/07/2016 version : 1.0 auteur : icarePetibles référence : www.wiringpi.com Remarques : à exécuter avec les privilèges root """ #------------------------------------------------------------------------------- # Bibliothèques #------------------------------------------------------------------------------- import wiringpi #bibliothèque wiringpi #------------------------------------------------------------------------------- if __name__ == '__main__': """ Programme par défaut """ print("\nDébut du programme LED clignotante") print("Arrêter le clignotement - ctrl+c") #messages IHM LED = 4 #sortie LED sur GPIO23 = 4 mode wiringpi DUREE = 500 #durée demi période = 0.5 sec ON = 1 OFF = 0 wiringpi.wiringPiSetup() #mode wiringpi ou "pseudo Arduino" wiringpi.pinMode(LED, 1) #pi en sortie sortie wiringpi.digitalWrite(LED, OFF) #led éteinte etatLed = False #sauve temps précédent (en msec) previousTime = wiringpi.millis() try: while True: #boucle infinie currentTime = wiringpi.millis() #sauve temps actuel if (currentTime - previousTime) >= DUREE: #si temps écoulé >= à DUREE (en msec) previousTime = currentTime #sauve temps précédent (en msec) if etatLed: #si led allumée wiringpi.digitalWrite(LED, OFF) #éteind led etatLed = False #led éteinte else: #si led éteinte wiringpi.digitalWrite(LED, ON) #allume led etatLed = True #led allumée except KeyboardInterrupt: #capture ctrl+c wiringpi.digitalWrite(LED, OFF) #éteind led wiringpi.pinMode(LED, 0) #pin en entrée print("\nFin du programme\n") #IHM #-------------------------------------------------------------------------------
La structure de ce programme est identique à ceux que l’on a déjà vu jusqu’à présent.
Exécution du programme
Pour exécuter ce programme, il faut lancer la commande suivante dans la console Linux :
sudo python3 blink62.py
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
pigpio
Pour utiliser la bibliothèque pigpio, il faut l’installer au préalable. On trouvera la procédure l’installation sous le lien :
http://abyz.co.uk/rpi/pigpio/download.html
Programme
Ce programme, pour changer, utilise une autre méthode pour sortir de la boucle infinie. La saisie non bloquante d’un caractère clavier est incluse dans un module Python indépendant.
Pour saisir ce programme, il faut faire dans la console :
nano saisieCarac.py
Cette commande ouvre un fichier texte vide appelé saisieCarac.py (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/usr/bin/python3 # -*- coding:utf-8 -*- """ Saisie caractère clavier non blocante logiciel : python 3.4.2 cible : raspberry Pi date de création : 08/06/2016 date de mise à jour : 16/06/2016 version : 1.0 auteur : icarePetibles référence : http://home.wlu.edu/~levys/software/kbhit.py """ #------------------------------------------------------------------------------- # Bibliothèques #------------------------------------------------------------------------------- import os #système d'exploitation import sys #informations système import termios #interface posix et contrôle I/O tty import atexit #nettoyage et enrégistrement fonctions from select import select #accès contrôles I/O plateforme #------------------------------------------------------------------------------- # Classe KBHit #------------------------------------------------------------------------------- class KBHit: #------------------------------------------------------------------------------- def __init__(self): """ Création d'un objet KBHit que l'on peut appeler pour faire différentes choses """ #Remarque : On ne traite pas le cas de windows #Sauvegade les paramètres du terminal self.fd = sys.stdin.fileno() #la méthode fileno() renvoie le #descripteur de fichier d'un objet de #type fichier self.new_term = termios.tcgetattr(self.fd) self.old_term = termios.tcgetattr(self.fd) #retourne une liste contenant les #attributs tty pour le descripteur de #fichier fd self.new_term[3] = (self.new_term[3] ~termios.ICANON ~termios.ECHO) #ICANON désactivé et ECHO désactivé termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.new_term) #fixe les attributs tty pour le #descripteur de fichier fd à partir des #attributs, qui est une liste comme #celle retournée par tcgetattr() #Réinitialisation terminal normal et sortie atexit.register(self.set_normal_term) #enrégistre la fonction à exécuter à la #fin #------------------------------------------------------------------------------- def set_normal_term(self): """ Reset vers le mode normal du terminal """ #Remarque : On ne traite pas le cas de windows termios.tcsetattr(self.fd, termios.TCSAFLUSH, self.old_term) #fixe les attributs tty pour le #descripteur de fichier fd à partir des #attributs, qui est une liste comme #celle retournée par tcgetattr() #------------------------------------------------------------------------------- def getch(self): """ Renvoi le caractère du clavier après un appel KBHit(). """ s = '' #Remarque : On ne traite pas le cas de windows return sys.stdin.read(1) #lecture du caractère de stdin #------------------------------------------------------------------------------- def kbhit(self): """ Retourne True si un caractère a été frappé au clavier, sinon False """ #Remarque : On ne traite pas le cas de windows dr, dw, de = select([sys.stdin], [], [], 0) return dr != [] #True ou False #------------------------------------------------------------------------------- #Test #------------------------------------------------------------------------------- if __name__ == "__main__": kb = KBHit() #instance KBHit() print("Début du programme") print("Appuyer sur une touche, ou ESC pour sortir") while True: #boucle sans fin if kb.kbhit(): #si touche clavier c = kb.getch() #lecture touche if ord(c) == 27: #si ESC break #sortie de la boucle sans fin print(c) #affiche le caractère kb.set_normal_term() #terminal en mode normal print("Fin du programme") #message HIM #-------------------------------------------------------------------------------
Les lignes 82 à 95 permettent de tester le programme de saisie.
Pour saisir ce programme blink, il faut faire dans la console :
nano blink41.py
Cette commande ouvre un fichier texte vide appelé blink41.py (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ees commentaires sont représentés ci-dessous.
#!/usr/bin/python3 # -*- coding:utf-8 -*- """ Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 Ohms Ajout sortie boucle infinie Ajout test pigpiod existe Ajout temporisation non bloquante logiciel : python 3.4.2 cible : raspberry Pi date de création : 09/06/2016 date de mise à jour : 19/06/2016 version : 1.0 auteur : icarePetibles référence : abyz.co.uk/rpi/pigpio/index.html Remarques : """ #------------------------------------------------------------------------------- # Bibliothèques #------------------------------------------------------------------------------- from saisieCarac import * #saisie caractère non blocante import time #bibliothèque time import pigpio #bibliothèque pigpio import os #bibliothèque os #------------------------------------------------------------------------------- if __name__ == '__main__': """ Programme par défaut """ #Test si pigpiod existe sinon lance sudo pigpiod if os.system('pidof pigpiod >/dev/null') == 256: os.system('sudo pigpiod >/dev/null') print("'sudo pigpiod' lancé par le programme") #------------------------------------------------------------------------------- kb = KBHit() #instance KBHit() print("\nDébut du programme LED clignotante") print("Arrêter le clignotement - appuyer sur 'q'") #messages IHM LED = 23 #sortie LED sur GPIO23 DUREE = 0.5 #durée demi période = 0.5 sec ON = 1 #esthétique OFF = 0 #esthétique pi = pigpio.pi() #connection à la tâche pigpiod pi.set_mode(LED, pigpio.OUTPUT) #configure pin en sortie pi.write(LED, ON) #sortie 23 allume led etatLed = True #led allumée previousTime = pi.get_current_tick() #valeur time précédente (en micro-sec) while True: #boucle infinie if kb.kbhit(): #test si touche appuiée c = kb.getch() #lecture de la touche if c.lower() == "q": #touche q ou Q break #sortie de boucle infinie currentTime = pi.get_current_tick() #sauve time actuel (en micro-sec) if pigpio.tickDiff(previousTime, currentTime)/1000000.0 >= DUREE: #si temps écoulé >= à DUREE (en sec) previousTime = currentTime #nouveau time précédent if etatLed: #si led allumée pi.write(LED, OFF) #éteind led etatLed = False #led éteinte else: #si led éteinte pi.write(LED, ON) #allume led etatLed = True #led allumée pi.set_mode(LED, pigpio.INPUT) #nettoyage kb.set_normal_term() #rétablie le terminal normal print("\nFin du programme\n") #message IHM pi.stop() #déconnexion #-------------------------------------------------------------------------------
Pour exécuter ce programme, il faut lancer au préalable une tâche de fond qui assure le contrôle des autres tâches. Si vous l’oubliez, les lignes 31 à 33 le feront pour vous.
Ligne 21, on importe les fonctions pour la saisie non bloquante d’un caractère au clavier.
Les lignes 50 à 53 permettent de sortir de la boucle infinie si l’on saisie ‘q’ ou ‘Q’ au clavier.
Le reste du programme nous est familier.
Exécution du programme
Pour exécuter ce programme, il faut lancer la commande suivante dans la console Linux :
python3 blink41.py
Pour sortir de la boucle infinie, il suffit de faire un q ou Q au clavier.
Commentaire bibliothèque
La documentation pour cette librairie peut être consultée sur le site :
http://abyz.co.uk/rpi/pigpio/python.html
On peut également avoir quelques informations supplémentaires par les commandes suivantes :
python3 >>> import pigpio >>> help(pigpio)
Rappel : pour sortir de l’interpréteur Python, il suffit de faire Ctrl+d
Graphique tkinter
Un peu de graphisme pour piloter notre LED.
Programme
Pour saisir ce programme, il faut faire dans la console :
nano blink70.py
Cette commande ouvre un fichier texte vide appelé blink70.py (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
#!/usr/bin/python3 # -*- coding:utf-8 -*- """ Programme led clignotante avec interface graphique os : RPi Linux 4.4.13+ logiciel : python3.4.2 cible : raspberry Pi date de création : 25/06/2016 date de mise à jour : 25/06/2016 version : 1.0 auteur : icarePetibles référence : Remarques : """ #------------------------------------------------------------------------------- # Bibliothèques #------------------------------------------------------------------------------- from tkinter import * #bibliothèque graphique tkinter import RPi.GPIO as GPIO #bibliothèque RPi.GPIO #------------------------------------------------------------------------------- #variables et constantes DUREE = 500 #1/2 période du clignotement led largeur = 26 #largeur canvas hauteur = 26 #hauteur canvas ledOn = '#ff0000' #led allumée couleur rouge ledOff = '#B1B1B1' #led éteinte couleur grise etatLed = False #led éteinte #------------------------------------------------------------------------------- #fonctions #------------------------------------------------------------------------------- def maj(): """Bascule état led en fonction de DUREE""" global etatLed #variable global - pas très orthodose #mais pour faire simple if(etatLed): #si led allumée etatLed=False #led éteinte GPIO.output(23, GPIO.LOW) #sortie 23 low - led éteinte des1.itemconfig(lumiere, fill=ledOff) #affiche la led éteinte else: #si led éteinte etatLed=True #led éteinte GPIO.output(23, GPIO.HIGH) #sortie 23 high - led allumée des1.itemconfig(lumiere, fill=ledOn) #affiche la led allumée des1.update_idletasks() #force le rafraîchissement graphique des1.after(DUREE, maj) #appel maj après écoulement DUREE #------------------------------------------------------------------------------- def quitter(): """Quitte l'application""" GPIO.output(23, GPIO.LOW) #sortie 23 low GPIO.setup(23, GPIO.IN) #GPIO23 en entrée quit() #sortie de mainloop destroy() #détruit l'objet ainsi que les enfants #------------------------------------------------------------------------------- def initialisation(): """Initialisation""" GPIO.setwarnings(False) #désactive le mode warning GPIO.setmode(GPIO.BCM) #numérotation ports processeur GPIO.setup(23, GPIO.OUT) #sortie sur GPIO23 GPIO.output(23, GPIO.LOW) #sortie 23 low #------------------------------------------------------------------------------- #programme pricipal #------------------------------------------------------------------------------- fen = Tk() #instance Tk fen.title('La saga Blink') #titre de la fenêtre fen.iconbitmap('@framboise.xbm') #icon de l'application largApplication = 300 #largeur de l'application hautApplication = 110 #hauteur de l'application largDisplay = fen.winfo_screenwidth() #largeur de l'écran en pixels hautDisplay = fen.winfo_screenheight() #hauteur de l'écran en pixels posX = int((largDisplay - largApplication)/2) #position X de l'appli pour être centrer posY = int((hautDisplay - hautApplication)/2) #position Y de l'appli pour être centrer fen.geometry('{}x{}+{}+{}'.format(largApplication, hautApplication, posX, posY)) #taille et position de la fenêtre fen.resizable(False, False) #ne permet pas le re-dimensionnement fen.protocol('WM_DELETE_WINDOW', quitter) #sortie par la petite croix (X) #------------------------------------------------------------------------------- #création objets graphiques #------------------------------------------------------------------------------- tex1=Label(fen, text='La saga Blink - Led clignotante', font="Tahoma 12 bold", fg="blue") #label message tex1.pack(padx=5, pady=5) #activation graphique des1=Canvas(fen, width=largeur, height=hauteur, bd=0) #canvas pour le dessin de la led center=int(largeur/2) r=int((largeur-2)/2) lumiere=des1.create_oval(center-r+1, center-r+1,center+r, center+r, fill=ledOff, outline="") #dessine led avec couleur éteinte des1.pack() #activation graphique bou1=Button(fen, text='Quitter', font="Tahoma 10", command=quitter) #button pour quitter l'application bou1.pack(padx=5, pady=5) #activation graphique tex2=Label(fen, text='icarePetibles ', font="Tahoma 7") #label auteurtex2.pack(side=RIGHT) #activation graphique #------------------------------------------------------------------------------- initialisation() #paramètres de départ maj() #lance le 'Blink' fen.mainloop() #boucle infinie graphique fen.destroy() #destruction de la fenêtre #-------------------------------------------------------------------------------
Normalement pour ce type de programme, la logique voudrait que l’on crée une classe pour l’application. Mais pour que le programme soit plus lisible, ce n’est pas le cas.
Notre programme comporte trois fonctions (initialisation, quitter et maj).
initialisation() : déclare et initialise le port GPIO via la bibliothèque RPi.GPIO (on aurait pu faire la même chose avec les autres bibliothèques).
quitter() : éteint la LED, libère la ressource port GPIO, sort de la boucle infinie et détruit le graphique. Cette fonction est appelée par le bouton quitter ou la petite croix (à droite et en haut de la fenêtre graphique).
maj() : cette fonction est appelée toutes les DUREE pour permuter l’état de la LED et l’affichage graphique.
Dans les lignes 65 à 78, on construit le support de notre fenêtre application. A la ligne 79, on capture le clic sur la petite croix.
Dans les lignes 84 à 102, on implémente les labels, bouton, canvas et dessin (LED).
Ligne 104 : on lance l’initialisation.
Ligne 105 : on déclenche le clignotement de la LED.
Ligne 106 : on active la boucle infinie graphique.
Ligne 107 : on détruit l’application graphique.
Exécution du programme
Pour exécuter ce programme, il faut lancer la commande suivante dans la console Linux dans l’environnement graphique :
python3 blink70.py
Pour sortir de la boucle infinie, il suffit de cliquer sur le bouton Quitter ou sur la petite croix.
Langage C
wiringPi
Pour ce programme, on utilise la même méthode pour sortir de la boucle infinie que pour pigpio. La saisie non bloquante d’un caractère clavier est incluse dans un fichier .h. Les experts du C vont voir tout rouge car on ne met pas de code dans un fichier .h, mais cela fonctionne et l’on fera mieux dans le prochain source.
Programme
Pour saisir ce programme, il faut faire dans la console :
nano saisieCarac.h
Cette commande ouvre un fichier texte vide appelé saisieCarac.h (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme saisie non bloquante caractère au clavier os : RPi Linux 4.4.13+ logiciel : gcc (Raspbian 4.9.2-10) 4.9.2 cible : raspberry Pi date de création : 22/06/2016 date de mise à jour : 22/06/2016 version : 1.0 auteur : icarePetibles référence : Remarques : ----------------------------------------------------------------------------- */ #ifndef saisieCarac_h #define saisieCarac_h /* ----------------------------------------------------------------------------- Bibliothèques ----------------------------------------------------------------------------- */ #include <stdio.h> //bibliothèque standard #include <termios.h> //bibliothèque entrées/sorties terminal #include <unistd.h> //bibliothèque constantes symboliques #include <fcntl.h> //bibliothèque descripteur de fichier /* -------------------------------------------------------------------------- */ int kbhit(void){ //fonction indiquant si frappe clavier struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, oldt); //sauve paramètres terminal newt = oldt; newt.c_lflag = ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, newt); //nouveaux paramètres terminal oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); //lecture caractère tcsetattr(STDIN_FILENO, TCSANOW, oldt); //restaure paramètres terminal fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF){ ungetc(ch, stdin); //replace le caractère dans le flux stdin //affiche le caractère dans la console return 1; //valeur de retour caractère saisie } return 0; //valeur de retour pas de caractère } /* -------------------------------------------------------------------------- */ #endif
Pour saisir le programme blink, il faut faire dans la console :
nano blink81.c
Cette commande ouvre un fichier texte vide appelé blink81.c (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme classique LED clignotante Led rouge sur GPIO23 (4) via une résistance de 330 ohms Ajout sortie boucle infinie et attente non blocante os : RPi Linux 4.4.13+ logiciel : gcc (Raspbian 4.9.2-10) 4.9.2 cible : raspberry Pi date de création : 22/06/2016 date de mise à jour : 22/06/2016 version : 1.0 auteur : icarePetibles référence : www.wiringpi.com Remarques : ----------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------- Bibliothèques ----------------------------------------------------------------------------- */ #include <stdio.h> //bibliothèque entrées/sorties #include <wiringPi.h> //bibliothèque wiringPi #include "saisieCarac.h" //fonction saisie caractère non bloquant #include <ctype.h> //bibliothèque pour tolower() //------------------------------------------------------------------------------ #define LED 4 //numéro led = GPIO23 #define DUREE 1000 int main(void){ //programme principal int c; //stocke touche clavier unsigned int valeurActuelle = 0; unsigned int valeurPrecedente = 0; int etatLed = FALSE; printf("Led clignotante\n"); //IHM printf("'q' pour arrêter le clignotement\n"); wiringPiSetup(); //numérotation wiringPi ou "pseudo Arduino" pinMode(LED, OUTPUT); //pin en sortie digitalWrite(LED, LOW); //led éteinte valeurPrecedente = millis(); for(;;){ //boucle infinie if(kbhit()) //si touche saisie c = getchar(); //lecture touche if(tolower(c) == 'q') //test si 'q' ou 'Q' break; //sortie de la boucle valeurActuelle = millis(); if(valeurActuelle - valeurPrecedente >= DUREE){ valeurPrecedente = valeurActuelle; if(etatLed){ digitalWrite(LED, LOW); etatLed = FALSE; } else { digitalWrite(LED, HIGH); etatLed = TRUE; } } } digitalWrite(LED, LOW); //éteint led pinMode(LED, INPUT); //pi en entrée printf("\nFin du programme\n"); //IHM return(0); //code sortie } //------------------------------------------------------------------------------
Rien de neuf par rapport à ce que l’on a vu dans les programmes précédents.
Exécution du programme
Pour exécuter se programme, il faut d’abord le compiler. La compilation se fait par la commande ci-dessous (en mode console) :
gcc -Wall -o blink81 blink81.c -lwiringPi
Le résultat de la compilation est un fichier : blink81
Lancement du programme :
sudo ./blink81
Pour sortir de la boucle infinie, il suffit de faire un ‘q’ ou ‘Q’ au clavier.
Perso
Programme
Ce programme se compose d’un fichier blink52.c et de deux bibliothèques externes (saisieCarac.h et ipsGPIO.h). La bibliothèque ipsGPIO.h est la même que celle du paragraphe 5.2.
saisieCarac.h et saisieCarac.c
Pour saisir le programme saisieCarac.h, il faut faire dans la console :
nano saisieCarac.h
Cette commande ouvre un fichier texte vide appelé saisieCarac.h (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme saisie non bloquante caractère au clavier Fichier entête de saisieCarac.c os : RPi Linux 4.4.13+ (Jessie) logiciel : gcc (Raspbian 4.9.2-10) 4.9.2 cible : raspberry Pi date de création : 26/06/2016 date de mise à jour : 28/06/2016 version : 1.0 auteur : icarePetibles référence : Remarques : ----------------------------------------------------------------------------- */ #ifndef SAISIE_CARAC_h #define SAISIE_CARAC_h /* -------------------------------------------------------------------------- */ //prototypes fonctions int kbhit(void); /* -------------------------------------------------------------------------- */ #endif
Pour saisir le programme saisieCarac.c, il faut faire dans la console :
nano saisieCarac.c
Cette commande ouvre un fichier texte vide appelé saisieCarac.c (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme saisie non bloquante caractère au clavier os : RPi Linux 4.4.13+ logiciel : gcc (Raspbian 4.9.2-10) 4.9.2 cible : raspberry Pi date de création : 22/06/2016 date de mise à jour : 22/06/2016 version : 1.0 auteur : icarePetibles référence : Remarques : ------ /* ----------------------------------------------------------------------------- Bibliothèques ----------------------------------------------------------------------------- */ #include <stdio.h> //bibliothèque standard #include <termios.h> //bibliothèque entrées/sorties terminal #include <unistd.h> //bibliothèque constantes symboliques #include <fcntl.h> //bibliothèque descripteur de fichier #include "saisieCarac.h" // /* -------------------------------------------------------------------------- */ int kbhit(void){ //fonction indiquant si frappe clavier struct termios oldt, newt; int ch; int oldf; tcgetattr(STDIN_FILENO, oldt); //sauve paramètres terminal newt = oldt; newt.c_lflag = ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, newt); //nouveaux paramètres terminal oldf = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, oldf | O_NONBLOCK); ch = getchar(); //lecture caractère tcsetattr(STDIN_FILENO, TCSANOW, oldt); //restaure paramètres terminal fcntl(STDIN_FILENO, F_SETFL, oldf); if(ch != EOF){ ungetc(ch, stdin); //replace le caractère dans le flux stdin //affiche le caractère dans la console return 1; //valeur de retour caractère saisie } return 0; //valeur de retour pas de caractère } /* -------------------------------------------------------------------------- */
ipsGPIO.h et ipsGPIO.c
voir paragraphe 5.2.1.1
blink52.c
Pour saisir le programme blink52.c, il faut faire dans la console :
nano blink52.c
Cette commande ouvre un fichier texte vide appelé blink52.c (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 ohms Ajout sortie boucle infinie Ajout attente non blocante os : RPi Linux 4.4.13+ (Jessie) logiciel : gcc (Raspbian 4.9.2-10) 4.9.2 cible : raspberry Pi date de création : 26/06/2016 date de mise à jour : 28/06/2016 version : 1.0 auteur : icarePetibles référence : Remarques : ----------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------- Bibliothèques ----------------------------------------------------------------------------- */ #include <stdio.h> //bibliothèque entrées/sorties #include <ctype.h> //manipulation caractères #include "ipsGPIO.h" //bibliothèque ipsGPIO #include "saisieCarac.h" //saisie caractère non blocant #define DUREE 500 //1/2 période clignotant #define LED 23 //led sur GPIO23 int main(void){ //programme principal int c; //caractère clavier unsigned long int valeurActuelle = 0; //sauve temps actuel unsigned long int valeurPrecedente = 0; //sauve temsp précédent int etatLed = FAUX; //led éteinte affiche("Led clignotante"); //IHM afficheLn(" by icarePetibles"); //IHM afficheLn("'q' ou 'Q' pour sortir");//IHM modeBroche(LED, SORTIE); //GPIO23 en sortie ecritureDigitale(LED, BAS); //éteind led valeurPrecedente = mTemps(); //temps for(;;){ //boucle infinie if(kbhit()) //si touche saisie c = getchar(); //lecture touche if(tolower(c) == 'q') //test si 'q' ou 'Q' break; //sortie boucle valeurActuelle = mTemps(); //temps if(valeurActuelle - valeurPrecedente >= DUREE){ //si temps écoulé supérieure DUREE valeurPrecedente = valeurActuelle; //temps if(etatLed){ //si led allumée ecritureDigitale(LED, BAS); //éteind la led etatLed = FAUX; //led éteinte }else{ //si led éteinte ecritureDigitale(LED, HAUT); //éteind la led etatLed = VRAI; //led éteinte } //fin (etat led) } //fin test DUREE } //fin boucle infinie ecritureDigitale(LED, BAS); //éteind led modeBroche(LED, DESACTIVE); //désactive pin LED afficheLn("\nFin du programme"); //IHM return 0; //code sortie } //fin programme
Exécution du programme
Pour exécuter se programme, il faut d’abord le compiler. La compilation se fait par la commande ci-dessous (en mode console) pour les différents fichiers C en créant des fichier objet :
gcc -c ipsGPIO.c gcc -c saisieCarac.c gcc -c blink52.c
Et pour terminer, il faut créer le fichier final via l’éditeur de lien :
gcc -o blink52 blink52.o ipsGPIO.o saisieCarac.o
Le résultat de la compilation est un fichier : blink52
Lancement du programme :
sudo ./blink52
Pour sortir de la boucle infinie, il suffit de faire q ou Q au clavier.
Remarque : On peut supprimer les fichiers objets (.o) du répertoire courant par :
rm *.o
Node.js
Un langage qui fait beaucoup parler et qui devient de plus en plus populaire (à surveiller). C’est quoi node.js ? C’est simplement du Javascript mais côté serveur contrairement à la version classique qui s’exécute côté client. Pour en savoir plus, il suffit de consulter les tutoriels sur le net ou des ouvrages spécialisés.
Ce langage est séduisant et l’on peut créer un serveur web en 3 à 4 lignes.
Pour ma part, je suis relativement « étanche » à ce langage et, mes vieux neurones ont du mal à s’adapter, aux fonctions avec des fonctions en paramètres qui s’exécutent de manière non bloquantes.
Pour notre application, nous n’utiliserons pas le concept serveur web mais comme un langage traditionnel.
Programme
Le programme utilise un module complémentaire « onoff« . La procédure d’installation ainsi que la documentation sont disponibles sous le lien :
https://www.npmjs.com/package/onoff
Pour les plus curieux, on trouvera sous https://www.npmjs.com/, la liste impressionnante des modules disponibles.
Pour saisir le programme, il faut faire dans la console :
nano blink02.js
Cette commande ouvre un fichier texte vide appelé blink02.js (pour la sauvegarde faire Ctrl+o et pour sortir Ctrl+x).
Le contenu du programme et de ses commentaires sont représentés ci-dessous.
/* ----------------------------------------------------------------------------- Programme classique LED clignotante Led rouge sur GPIO23 via une résistance de 330 ohms os : RPi Linux 4.4.13+ (Jessie) logiciel : node v0.12.6 cible : raspberry Pi date de création : 26/06/2016 date de mise à jour : 20/07/2016 version : 1.0 auteur : icarePetibles référence : https://www.npmjs.com/package/onoff Remarques : ----------------------------------------------------------------------------- */ var Gpio = require('onoff').Gpio, //module onoff led = new Gpio(23, 'out'); //led sur GPIO23 et en sortie DUREE = 500 //demi-période clignotement (msec) console.log('Début programme led clignotante'); console.log("'Sortie de la boucle infinie par ctrl+c'"); //IHM var iv = setInterval(function(){ //appel toutes les x milli-sec led.writeSync(led.readSync() === 0 ? 1 : 0) }, DUREE); //durée de répétition function exit(){ //sortie de la boucle infinie clearInterval(iv); //arrêt clignotement led.writeSync(0); //éteint led led.unexport(); //unexport GPIO et libère la resssource console.log('\nFin programme'); //IHM process.exit(); //arrêt node } process.on('SIGINT', exit); //capture du ^C et exécute exit()
Exécution programme
Pour exécuter ce programme, il faut lancer la commande suivante dans la console Linux :
node blink02.js
Pour sortir de la boucle infinie, il suffit de faire un Ctrl+c au clavier.
Conclusion
La saga pourrait continuer pendant des semaines et des semaines ou des pages et des pages. Finalement on va se trouver dans une situation de bis repetita.
On aurait pu utiliser d’autres langages (console ou graphique) pour commander notre port GPIO, comme Java, Scratch, Node-RED, C++, Pascal, Fortran, PHP, Javascript, etc…
Peut être à bientôt pour une prochaine saga (pushButton, I2C, SPI, 1-Wire, interruption, etc…)
Sources
Vous pouvez télécharger l’ensemble des sources ici :
http://psl.ibidouille.net/Images_forum/raspberryPi/sagaBlink.zip