Un titre un peu fourre tout car en effet le sujet est vaste…Cet article présente les bases de l’installation d’un RaspberryPi et sa configuration de base. Puis nous allons tester les différentes possibilités d’E/S SANS programmation : E/S TOR (GPIO), bus 1Wire, bus I2C, voie série,bus SPI. Puis nous passerons à la programmation en langage C à l’aide de la bibliothèque WiringPi de Gordon Henderson. Enfin nous terminerons par la création d’une page web qui dialoguera avec ces différents bus grâce à un script CGI. Bref que du bon…
Installation et configuration du RaspberryPI
Dans ce qui suit vous allez configurer votre raspberry pour une utilisation « de base » sur un réseau avec des adresses IP fixes. Mais avant tout quelques ressources (anglaises ou françaises) sur Internet.
Collection de liens
- le site de la fondation Raspberry et en particulier sa section téléchargement
- le site eLinux et en particulier sa section concernant le RaspberryPi
- la section « Apprendre » (learn) du site adafruit industries avec le filtrage sur les projets RaspberryPi
- le site de Gordon Henderson et en particulier la section sur WiringPI
- le site de Christophe Blaess : linux embarqué et de très bon article sur le RaspberryPI
- présentations du raspberryPi en français sur Wikipédia, Léa-Linux, un blog personnel, le site du vendeur Kubii, etc…
Création de la carte SD
Téléchargez sur le site de la fondation Raspberry l’image de la distribution Raspian ainsi que l’utilitaire de création de carte SD Win32Imager. Sous Microsoft Windows, lancez Win32Imager pour créer votre carte SD (mini 4Go). Patientez…votre carte est prête. Lorsque vous démarrerez avec cette carte votre raspberry, vous obtiendrez une distribution « debian » adapté à votre carte ARM. La fondation vous propose aussi une image « New Out Of the Box Software » qui permet de tester les différentes distributions disponibles pour le raspberry. Pour installer cette image, téléchargez-là, formatez votre carte SD de 4Go avec l’utilitaire SDFormat puis désarchivez les fichiers de l’image directement sur cette carte. Connectez les cables nécessaires sur le raspberry (clavier et souris USB, cable hdmi vers écran), insérez la carte SD raspian et enfin connectez l’alimentation. Vous devriez voir les messages de démarrage du noyau Linux à l’écran. Comme nous allons en parler tout le temps, j’insère ici un exemple de brochage des connecteurs du RaspberryPi (il en existe des tas sur internet, faites donc une recherche avec google image et les mots clés GPIO RaspberryPi): Si vous ne disposez pas de tout cela, vous pouvez travailler sur votre raspberry ! Il vous faudra un simple convertisseur USB-Série TTL comme on en trouve des dizaines sur e-bay (ici par exemple : 1,5€ frais de port compris!!). Il suffit de connecter la masse, RX et TX du convertisseur vers la masse (P1.6), la broche TX (P1.8) et la broche RX (P1.10) du raspberry. La connexion s’effectue en 115200 8N1. Vous pouvez utiliser le logiciel Putty sous Windows ou minicom sous Linux.
Première configuration du RaspberryPi
Quelque soit la méthode choisie, vous devez maintenant vous identifier: utilisateur (login) : pi, mot de passe: raspberry. La première chose à faire est de finir la configuration du raspberry. Pour cela tapez la commande suivante après l’invite de commande :
1 |
root@raspberrypi:~$ sudo raspi-config |
La commande ‘sudo’ permet d’exécuter la commande qui la suit avec les droits administrateur (root sous Linux). Vous obtenez le menu suivant :
- 1- Expand Filesystem : utiliser la totalité de la carte SD
- 2 – Change User Password : changer le mot de passe de l’utilisateur PI
- 3 – Enable boot to Desktop : démarrer en mode texte ou en mode graphique
- 4 – Internationalisation Options : choix des options d’internationalisation
- 4.1 – Change Locale : choix de la langue du SE : ici francais (Fr_fr UTF8)
- 4.2 – Change Timezone : pour appliquer le bon fuseau horaire (Europe/Paris)
- 4.3 – Change Keyboard Layout : le clavier francais sera automatiquement choisi si les deux dernières options ont été configurées
- 5 – Enable Camera : activation des pilotes de la camera du raspberry
- 6 – Add to Rastrack : enregistrement de votre raspberry en ligne
- 7 – Overclock : au choix différentes options pour « booster » votre raspberry de « pas du tout » à « ne pas toucher le Soc (brulures) »
- 8 – Advanced Options : options avancées
- 8.1 – Overscan : a tester si vous avez des bandes noires autour de l’écran
- 8.2 – Hostname : changer le nom de votre raspberry (si vous en avez plusieurs)
- 8.3 – Memory Split : partage de la mémoire entre le processeur et la carte graphique
- 8.4 – SSH : permet de se connecter à distance et/ou de copier des fichiers à distance (application putty et winSCP sous Windows)
- 8.5 – Update : mise à jour de l’utilitaire raspi-config
- 9 – About Raspi-config : A propos…
Parcourez les différents menus pour finaliser l’installation du raspberry. Redémarrez si c’est nécessaire. La commande pour redémarrer est ‘reboot’ et pour éteindre proprement le raspberry ‘poweroff’ (la del verte prêt du connecteur audio clignotera rapidement lorsque le système peut être débranché). Vous pouvez maintenant lire ‘le guide du débutant sous GNU/Linux’ disponible en fin d’article au format OpenOffice.org ou au format PDF. Parmi les différentes commandes présentées dans ce document, il faudra connaitre en particulier la commande ‘aptitude’ qui permet d’installer/désinstaller/rechercher des logiciels. Bonne lecture… Déjà de retour 😉 ! Pour rassurer les plus septiques de la ligne de commande, lancez votre environnement graphique avec la commande ‘startx’ à moins que vous n’ayez décidé de démarrer directement en mode graphique (commande raspi-config). Lancez un terminal (une console) pour retrouver une ligne de commande. A titre d’exercice installez le logiciel ‘synaptic’ : logiciel graphique de recherche/suppression/installation de logiciels. Lancez-le puis installez par son biais le logiciel ‘Geany’ : environnement de développement intégré qui va nous servir dans quelques lignes pour compiler nos premiers exemples en langage C. Notez bien que l’on peut faire tout ce qui précède en ligne de commande sans environnement graphique !
Configuration réseau du RaspberryPi
Par défaut, le raspberry cherche un serveur DHCP sur le réseau auquel il est connecté. Si ce serveur existe, aucun problème la pile réseau du raspberry sera correctement configurée. Cependant vous pouvez avoir besoin de figer cette configuration pour pouvoir intégrer votre raspberry dans votre réseau (établissement scolaire ou entreprise). Pour cela il faut éditer (avec nano par exemple) et modifier le fichier ‘/etc/network/interfaces’ pour qu’il ressemble à celui donné ci-dessous en adaptant bien sur les paramètres IP (lignes address, netmask, gateway, dns-nameservers de la section iface eth0). Les lignes qui commencent par ‘#’ sont des commentaires ou les lignes de la configuration d’origine :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
root@raspberrypi:/home/pi# cat /etc/network/interfaces auto lo iface lo inet loopback #iface eth0 inet dhcp auto eth0 iface eth0 inet static address 192.168.1.2 netmask 255.255.255.0 gateway 192.168.1.1 dns-nameservers 192.168.1.1 allow-hotplug wlan0 iface wlan0 inet manual wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf #iface default inet dhcp |
La configuration du DNS sera automatique grâce à la ligne dns-nameservers. Mais il faut auparavant installer le paquetage resolvconf puis redémarrer :
1 2 |
root@raspberrypi:/home/pi# aptitude install resolvconf root@raspberrypi:/home/pi# reboot |
Pour tester votre configuration réseau, faites donc un ‘ping’ vers les serveurs de google…
Découverte des différents bus de communication SANS programmation
Dans un premier temps vous allez découvrir les GPIO, le bus I2C, le bus SPI, la voie série sans programmation. Cela permet de valider les parties « matériels » d’un montage AVANT de passer au « logiciel.
Les E/S Tout Ou Rien (ES TOR) ou GPIO (General Purpose Input Output)
J’ai déjà un article sur ce thème, même s’il ne s’agit pas de la même carte, le principe de base s’applique sur le raspberry (en fait sur toutes les cartes GNU/Linux embarqué récentes et correctement supporté par le noyau). En résumé, il faut:
- informer le noyau Linux que l’on souhaite ‘exporter’ une broche
- configurer celle-ci en entrée ou en sortie
- lire ou écrire sur celle-ci
Connectez par exemple la DEL rouge du shield de test à la broche GPIO4 (P1.7) et le bouton poussoir associé à celle-ci à la broche GPIO17 (P1.11) ainsi que la masse des cartes puis tapez les commandes suivantes en étant ‘root’ (commande sudo su):
1 2 3 |
root@raspberrypi:/home/pi# echo 4 > /sys/class/gpio/export root@raspberrypi:/home/pi# echo 17 > /sys/class/gpio/export root@raspberrypi:/home/pi# ls /sys/class/gpio/ |
Maintenant suivant si vous voulez mettre cette broche en entrée ou en sortie il faut tapez une des lignes suivantes:
1 2 |
root@raspberrypi:/home/pi# echo "out" > /sys/class/gpio/gpio4/direction root@raspberrypi:/home/pi# echo "in" > /sys/class/gpio/gpio17/direction |
Enfin pour lire (appuyez sur le BP) ou écrire sur cette broche (éteindre allumer la del) :
1 2 3 |
root@raspberrypi:/home/pi# cat /sys/class/gpio/gpio17/value root@raspberrypi:/home/pi# echo "0" > /sys/class/gpio/gpio4/value root@raspberrypi:/home/pi# echo "1" > /sys/class/gpio/gpio4/value |
Le bus One-Wire
Ce bus est très souvent utilisé avec des capteurs de températures (type DS18B20) mais sachez qu’il existe de nombreux pilotes sous Linux pour d’autres périphériques. Le raspberry ne possède pas de pilote matériel onewire, en conséquence c’est le pilotage d’une broche TOR qui permet de dialoguer sur ce bus. Par défaut, lors de la compilation du noyau Linux, la broche affecté au bus onewire est la GPIO4 (P1.7). Si vous l’avez utilisé pour faire des manipulations en tout-ou-rien, il faut tout d’abord la « dé-exporter », c’est à dire la libérer pour que le noyau puisse installer son pilote 1-wire sur cette broche. Pour libérer une broche GPIO, il faut taper une commande du style:
1 |
root@raspberrypi:/home/pi# echo 4 > /sys/class/gpio/unexport |
A partir de ce moment, vous pouvez charger les pilotes noyau pour la gestion du bus 1-wire et des capteurs de températures:
1 2 |
root@raspberrypi:/home/pi# modprobe w1_gpio root@raspberrypi:/home/pi# modprobe w1_therm |
Pour savoir quels sont les autres pilotes disponibles pour le bus 1-wire, tapez:
1 2 3 |
root@raspberrypi:~# ls /lib/modules/3.6.11+/kernel/drivers/w1/slaves/ w1_bq27000.ko w1_ds2423.ko w1_ds2433.ko w1_ds2780.ko w1_therm.ko w1_ds2408.ko w1_ds2431.ko w1_ds2760.ko w1_smem.ko |
Connectez des DS18B20 au bus 1-wire (platine fournie) puis testez s’ils sont reconnus avec la commande suivante:
1 2 |
root@raspberrypi:/home/pi# ls /sys/bus/w1/devices/ 10-00080225c65d 10-00080225e0b9 w1_bus_master1 |
Dans le cas précédent, deux capteurs de températures ont été trouvé. Pour lire la température, il faut taper une commande du style (en adaptant le numéro de série du capteur) :
1 2 3 |
root@raspberrypi:/home/pi# cat /sys/bus/w1/devices/10-00080225e0b9/w1_slave 31 00 4b 46 ff ff 08 10 95 : crc=95 YES 31 00 4b 46 ff ff 08 10 95 t=24250 |
La température est ici de 24,25°C. Le bus 1-wire est donc validé. Passons au bus i2c.
Le bus I2C
Ce bus est déjà décrit dans un article de ce site. Vous pouvez réaliser des tests avec la platine qui possède l’horloge RTC DS3231 et un capteur de température DS1621/DS1631. MAIS vous pouvez aussi tester une platine qui possède un CAN (MCP3221) et un CNA (MCP4726) sur bus I2C. Cette platine est intéressante dans le sens ou le raspberry n’a pas de CAN intégré et une seule sortie MLI (PWM).
Je vous encourage donc à générer une tension sur le CNA et à relire celle-ci avec le CAN à l’aide des commandes i2cget et i2cread.
La voie série
La voie série matériel est déjà utilisée par le noyau pour proposer un « login » par cette même voie série. Si vous désirez utiliser cette vois série dans vos montages, il faut tout d’abord la « libérer » du noyau. Pour cela, il faut modifier la ligne de commande passer au noyau au démarrage. Vous pouvez l’éditer en tapant la commande suivante en remplaçant ‘cat’ par ‘nano’ :
1 2 |
root@raspberrypi:/home/pi# cat /boot/cmdline.txt dwc_otg.lpm_enable=0 console=ttyAMA0,115200 kgdboc=ttyAMA0,115200 console=tty1 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline rootwait |
Il faut supprimer ‘console=ttyAMA0,115200’ puis sauver ce fichier. De plus, il faut commenter la ligne ‘ T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100’ à la fin du fichier /etc/inittab. Si vous redémarrez votre raspberry, il vous faut absolument :
- soit un écran/clavier pour vous connecter,
- soit vous connectez à distance par ssh (serveur ssh activé sur le raspberry, adresse IP du raspberry connu, logiciel putty coté Windows).
Comme vous l’avez sans doute remarqué, la voie série porte le nom ttyAMA0. Cette voie série est disponible dans le répertoire devices (périphériques en anglais, aussi appelé ‘/dev’ dans l’arborescence Linux). Il nous faut aussi régler la vitesse de transmission et le nombre de bit de données, de parité et de stop. La commande qui permet de régler ces paramètres est ‘stty’. Par exemple, pour lister les paramètres actuels de la voie série, il faut taper la commande suivante:
1 2 3 4 5 6 7 8 9 10 11 |
root@raspberrypi:/home/pi# stty -a -F /dev/ttyAMA0 speed 9600 baud; rows 0; columns 0; line = 0; intr = ^C; quit = ^; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 hupcl -cstopb cread clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke |
Parmi tous ces paramètres la vitesse nous intéresse (ici speed 9600), le nombre de bit de donnée (cs8 : 8 bit de données) et la parité (ici aucune car on a -parenb -parodd : – = absence, par = parité, enb = even = paire, odd = impaire). Donc si l’on veut dialoguer avec un périphérique (par exemple le PC) à 115200 bits/s, il faudra tapez une commande du style:
1 |
root@raspberrypi:/home/pi# stty -F /dev/ttyAMA0 speed 115200 |
Vous pouvez alors envoyer sur la voie série, une chaine de caractères avec la commande de la première ligne ou alors recevoir des caractères avec la commande de la seconde ligne :
1 2 |
root@raspberrypi:/home/pi# echo "mon message ascii" > /dev/ttyAMA0 root@raspberrypi:/home/pi# cat < /dev/ttyAMA0 |
Conclusion : la voie série matériel du raspberry est fonctionnelle pour vos programmes personnels. Donc si votre application ne fonctionne pas, ce sera un problème du coté logiciel et pas matériel !
Le bus SPI
Je n’ai pas trouvé d’applications précompilé pour tester ce bus. Une des meilleures sources d’information est sans doute les sources du noyau Linux et en particulier ce code. Vous pouvez cependant envoyer des caractères vers le bus SPI del manière suivante :
1 |
root@raspberrypi:~/wiringPi/exemples_OD# echo 'U' > /dev/spidev0.0 |
Notez cependant qu’un caractère LineFeed est ajouté derrière le caractère.
Les servomoteurs
Un pilote noyau pour le pilotage de 8 servomoteurs existe. Celui-ci est disponible sur ce site. Téléchargez et copiez le module noyau « servoblaster.ko » sur votre carte SD. Il faut ensuite le charger en mémoire (commande insmod) puis créer son point d’entrée dans les périphériques (commande mknod, ici le chiffre important est 248) :
1 2 3 4 5 6 7 8 9 10 11 12 13 |
root@raspberrypi:/home/pi# insmod servoblaster.ko root@raspberrypi:/home/pi# cat /proc/devices | grep servoblaster 248 servoblaster root@raspberrypi:/home/pi# mknod -m 0666 /dev/servoblaster c 248 0 root@raspberrypi:/home/pi# cat /dev/servoblaster 0=0 1=0 2=0 3=0 4=0 5=0 6=0 7=0 |
1 2 3 4 5 6 7 8 9 |
Servo number GPIO number P1 header 0 4 P1-7 1 17 P1-11 2 18 P1-12 3 21 P1-13 4 22 P1-15 5 23 P1-16 6 24 P1-18 7 25 P1-22 |
Je relie la masse et la sortie servomoteur 0 (GPIO 4) sur un oscilloscope. Pour fixer la durée de l’impulsion à 2ms sur la sortie servomoteur 0, il faut taper la commande suivante que vous pouvez ensuite vérifiez avec la seconde commande:
1 2 3 4 5 6 7 8 9 10 |
root@raspberrypi:/home/pi# echo 0=200 > /dev/servoblaster root@raspberrypi:/home/pi# cat /dev/servoblaster 0=200 1=0 2=0 3=0 4=0 5=0 6=0 7=0 |
1 |
root@raspberrypi:/home/pi# rmmod servoblaster |
Après avoir testé les différents bus et E/S sans programmation, nous allons passer à la programmation en langage C avec l’aide de la bibliothèque WiringPi.
Programmation en langage C des E/S et des bus du RaspberryPi
La librairie qui permet un accès rapide aux fonctionnalités du Raspberry est sans aucun doute la librairie WiringPi. Il faut donc se rendre de toute urgence sur le site de celle-ci… En résumé, cette bibliothèque de fonctions vous permet de :
- gérer les E/S (GPIO),
- gérer le bus I2C,
- gérer le bus SPI,
- gérer une sortie en mode PWM matériel,
- gérer n’importe quelle sortie en mode PWM logiciel,
- gérer les échanges sur la voie série,
- gérer les cartes PiFace, GertBoard, des afficheurs LCD compatible HD44780,
- etc… (découvrez le site par vous même…)
Installation de la librairie WiringPi
Il faut tout d’abord télécharger et installez cette librairie. Les étapes sont données sur cette page. Si l’installation par clonage du dépôt git (commande ‘git clone’) ne fonctionne pas dans votre lieu de travail (parefeu) il faut télécharger une archive de la bibliothèque (retrouver dans le texte le « Plan B »).
Une fois que la bibliothèque est compilée et installée, testez les commandes suivantes :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
root@raspberrypi:~/wiringPi# gpio -v gpio version: 2.07 Copyright (c) 2012-2013 Gordon Henderson This is free software with ABSOLUTELY NO WARRANTY. For details type: gpio -warranty This Raspberry Pi is a revision 2 board. root@raspberrypi:~/wiringPi# gpio readall +----------+-Rev2-+------+--------+------+-------+ | wiringPi | GPIO | Phys | Name | Mode | Value | +----------+------+------+--------+------+-------+ | 0 | 17 | 11 | GPIO 0 | OUT | Low | | 1 | 18 | 12 | GPIO 1 | OUT | Low | | 2 | 27 | 13 | GPIO 2 | IN | Low | | 3 | 22 | 15 | GPIO 3 | OUT | Low | | 4 | 23 | 16 | GPIO 4 | OUT | Low | | 5 | 24 | 18 | GPIO 5 | OUT | Low | | 6 | 25 | 22 | GPIO 6 | OUT | Low | | 7 | 4 | 7 | GPIO 7 | OUT | Low | | 8 | 2 | 3 | SDA | ALT0 | High | | 9 | 3 | 5 | SCL | ALT0 | High | | 10 | 8 | 24 | CE0 | ALT0 | High | | 11 | 7 | 26 | CE1 | ALT0 | High | | 12 | 10 | 19 | MOSI | ALT0 | Low | | 13 | 9 | 21 | MISO | ALT0 | Low | | 14 | 11 | 23 | SCLK | ALT0 | Low | | 15 | 14 | 8 | TxD | ALT0 | High | | 16 | 15 | 10 | RxD | ALT0 | High | | 17 | 28 | 3 | GPIO 8 | IN | Low | | 18 | 29 | 4 | GPIO 9 | IN | Low | | 19 | 30 | 5 | GPIO10 | IN | Low | | 20 | 31 | 6 | GPIO11 | IN | Low | +----------+------+------+--------+------+-------+ |
- soit tout faire en ligne de commande dans une console (fonctionne même à distance depuis un PC),
- soit saisir votre code, le compiler et l’exécuter depuis un EDI (Environnement de Développement Intégré) : par exemple Geany que vous avez installé au début de l’article.
Pour le premier test, je vais décrire les deux solutions.
Premier test de la librairie WiringPi : faire clignoter une DEL
C’est le grand classique habituel, utilisez le shield arduino fourni pour avoir une DEL… Si vous êtes en ligne de commande, tapez le code suivant à l’aide de l’éditeur nano. Si vous êtes en mode graphique, lancez Geany puis saisissez le même code. Dans les deux cas, pensez à sauvegarder ce code sous le nom ‘clignot_del.c’.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <stdio.h>// Fonction printf #include <wiringPi.h>// Fonctions WiringPi int main (void) // Fonction principale { printf ("Premier test - Clignotement DEL\nFin par Ctrl-C\n"); // Message d'accueil wiringPiSetupGpio() ; // Choix de la numérotation des broches du RPi pinMode (4, OUTPUT) ; // Choix mode Sortie de la broche GPIO 4 for (;;) // Boucle infinie { digitalWrite (4, HIGH) ; // DEL allumée delay (500) ; // Attente 500ms digitalWrite (4, LOW) ; // DEL eteinte delay (500) ; // Attente 500ms } return 0 ; // Code retour } |
1 2 3 4 5 6 7 8 9 10 11 |
root@raspberrypi:~/wiringPi/exemples_OD# gcc -o clignot_del -lwiringPi clignot_del.c root@raspberrypi:~/wiringPi/exemples_OD# file clignot_del clignot_del: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.26, BuildID[sha1]=0xb310b97d6ea78ac5192ca80ddcdb41923336a21b, not stripped root@raspberrypi:~/wiringPi/exemples_OD# ls -lh total 12K -rwxr-xr-x 1 root root 5,9K juin 8 20:32 clignot_del -rw-r--r-- 1 root root 299 juin 8 20:30 clignot_del.c root@raspberrypi:~/wiringPi/exemples_OD# ./clignot_del Premier test - Clignotement DEL Fin par Ctrl-C ^C |
1 2 3 4 5 |
root@raspberrypi:~/wiringPi/exemples_OD# strip clignot_del root@raspberrypi:~/wiringPi/exemples_OD# ls -lh total 8,0K -rwxr-xr-x 1 root root 3,7K juin 8 20:40 clignot_del -rw-r--r-- 1 root root 299 juin 8 20:30 clignot_del.c |
Deuxième test : Lire l’état d’une broche et la MLI matériel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
#include <stdio.h> #include <wiringPi.h> int main(void) { int val_mli=512; printf("Second test - MLI materiel DEL\nFin par Ctrl-C\n"); printf("Appuyez sur les boutons\n"); wiringPiSetupGpio(); pwmSetMode(PWM_MODE_MS); pinMode(18, PWM_OUTPUT); pinMode(17, INPUT); pinMode(27, INPUT); for (;;) { if ( digitalRead(17) == 1 ) { val_mli+=10; if ( val_mli>1023 ) val_mli=1023; printf("++++ val_mli=%d\n",val_mli); } if ( digitalRead(27) == 1 ) { val_mli-=10; if ( val_mli<1) val_mli=1; printf("---- val_mli=%d\n",val_mli); } pwmWrite( 18, val_mli ); delay(20); } return 0; } |
L’explication des fonctions spéciales au RaspberryPi se trouvent sur cette page.
Troisième test : la MLI logiciel
Quasiment dans le même registre, la mise en oeuvre de la MLI logiciel sur une DEL RGB. Les fonctions logicielles sur la MLI sont décrites sur cette page :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include #include #include #include int main(void) { int sinus[64],i; printf("Troisieme test - MLI logiciel DEL RGB\nFin par Ctrl-C\n"); wiringPiSetupGpio(); softPwmCreate( 22, 100, 100); softPwmCreate( 23, 100, 100); softPwmCreate( 24, 100, 100); for (i=0; i<64; i++) sinus[i] = (int)(50 * sin ( 2*3.14*i/64) + 50); i=0; for (;;) { softPwmWrite( 22, sinus[i] ); softPwmWrite( 23, sinus[(i+21)%63] ); softPwmWrite( 24, sinus[(i+42)%63] ); delay( 100 ); i++; if (i == 64) i = 0; } return 0; } |
Vous remarquerez que j’ai inclus le fichier « math.h » pour avoir la fonction ‘sin’. De plus, si vous utilisez les sorties logicielles MLI, la documentation indique qu’elles utilisent les « thread » de Linux. Donc la ligne de compilation pour cet exemple évolue légèrement:
1 |
root@raspberrypi:~/wiringPi/exemples_OD# gcc -o pwm_soft_delRGB -lwiringPi -lpthread -lm pwm_soft_delRGB.c |
Vous devez donc rajouter les librairies mathématiques ( -lm ) et des processus légers ( -lpthread ). Cablez les GPIO 22, 23 et 24 sur la DEL RGB disponible sur le shield et lancez votre programme. Pendant l’exécution de ce programme, la fréquence mesurée sur une des GPIO est de 100Hz et l’occupation processeur pour la génération des trois MLI logicielles est de 1,5% ( utilisez la commande ‘top’).
Quatrième test – Le bus I2C – Capteur de temp. DS1621
Remarque: Le DS1621 fonctionne avec une tension d’alimentation de 5V. Celle-ci est fourni par la broche P1.2. Cependant cela ne pose pas de problème sur le bus i2c car les résistances de rappel au +3,3V de ce même bus sont câblées sur le raspberry et que les sorties des esclaves i2c sont à collecteur ouvert.
Avez-vous bien lu l’article sur l’utilisation du bus I2C sur ce même site. Il faut en effet s’assurer que les modules i2c_bcm2708 et i2c_dev sont bien gérés par le noyau (vérifiez-le avec la commande ‘lsmod’). Si les modules sont correctement chargés, testez s’il y a des esclaves connectés sur votre bus I2C avec la commande ‘i2cdetect -y 1’. Par exemple, j’ai un capteur de température DS1621 à l’adresse 0x48 dans la capture suivante :
1 2 3 4 5 6 7 8 9 10 |
root@raspberrypi:~/wiringPi/exemples_OD# i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- |
Je ne détaillerai pas ici la séquence d’initialisation du DS1621, ni la lecture de la température (cependant cette documentation peut vous faire gagner du temps !). Lisez le code C ci-dessous pour cela:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include #include #include // bibliothèque pour la gestion de l'I2C int main(void) { int fd,temp; printf("Quatrieme test - Bus I2C - DS1621\nFin par Ctrl-C\n"); wiringPiSetupGpio(); if ( (fd=wiringPiI2CSetup(0x48)) < 0 ) { // Il faut tester si l'initialisation du bus I2C a fonctionné printf("Erreur initialisation du bus I2C !"); return -1; } wiringPiI2CWriteReg8( fd, 0xAC, 0x08 ); // Initialisation DS1621 en mode conversion continu wiringPiI2CWrite( fd, 0xEE ); // Debut de conversion delay(500); for (;;) { temp = wiringPiI2CReadReg16( fd, 0xAA ); printf("Temperature (hexa 16bits) : 0x%04X soit pour la partie entiere : %d\n", temp, temp&0x00FF); delay(1000); } return 0; } |
1 2 3 4 5 6 7 8 |
root@raspberrypi:~/wiringPi/exemples_OD# gcc -o i2c_ds1621 -lwiringPi i2c_ds1621.c root@raspberrypi:~/wiringPi/exemples_OD# ./i2c_ds1621 Quatrieme test - Bus I2C - DS1621 Fin par Ctrl-C Temperature (hexa 16bits) : 8016 soit pour la partie entiere : 22 Temperature (hexa 16bits) : 8016 soit pour la partie entiere : 22 Temperature (hexa 16bits) : 8016 soit pour la partie entiere : 22 ^C |
Cinquième test – Bus I2C – CAN et CNA
1 2 3 4 5 6 7 8 9 10 |
root@raspberrypi:~/wiringPi/exemples_OD# i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- 4d -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: 60 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- |
En lisant les documentations des convertisseurs ( CAN:MCP3221, CNA:MCP4726 ) on trouve que l’adresse 0x4D correspond au CAN MCP3221 (voir doc page 16) et l’adresse 0x60 au CNA MCP4726 (voir doc page 46).
Dans le code qui suit, on utilisera qu’une seule fonction du CNA : Write volatile DAC register (voir p49 et 50) et une fonction du CAN : Executing a conversion ( voir p16) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include #include #include int main(void) { int fd,val_cna,val_can,val_temp; float tension_out,tension_in; printf("Cinquieme test - Bus I2C - CAN&CNA\nFin par Ctrl-C\n"); wiringPiSetupGpio(); for (;;) { printf("Donnez une tension comprise entre 0V et 3.3V : "); scanf("%f",&tension_out); val_cna = (unsigned short)((tension_out/3.3)*4096); fd = wiringPiI2CSetup(0x60); // on dialogue avec le CNA // Il faut écrire une valeur 16 bit // B15 B14 = C2 C1 = command bits = 0 0 // B13 B12 = P1 P0 = power on bit = 0 0 // B11..B0 = données du DAC // wiringPi ne donne pas de fonction pour écrire un mot de 16 bits // donc on détourne la fonction WriteReg8 même si on écrit pas // dans un registre wiringPiI2CWriteReg8( fd, val_cna>>8, val_cna&0x00FF ); delay(1500); fd = wiringPiI2CSetup(0x4d); // On dialogue avec le CAN // Si on met le registre 0, en fait on lit 2 octets // Attention le résultat est stocké en LSB,MSB val_can = wiringPiI2CReadReg16( fd, 0 ); val_temp = (val_can&0xFF)<<8; val_can = val_temp | ((val_can&0xFF00)>>8); tension_in = (val_can * 3.3)/4096; // 4096 = 2^12 printf("Relecture par le CAN : %f V\n",tension_in); } return 0; } |
1 2 3 4 5 6 7 8 9 10 11 |
root@raspberrypi:~/wiringPi/exemples_OD# gcc -o i2c_CAN_CNA -lwiringPi i2c_CAN_CNA.c root@raspberrypi:~/wiringPi/exemples_OD# ./i2c_CAN_CNA Cinquieme test - Bus I2C - CAN&CNA Fin par Ctrl-C Donnez une tension comprise entre 0V et 3.3V : 1 Relecture par le CAN : 1.002246 V Donnez une tension comprise entre 0V et 3.3V : 2 Relecture par le CAN : 2.006909 V Donnez une tension comprise entre 0V et 3.3V : 2.88 Relecture par le CAN : 2.881055 V Donnez une tension comprise entre 0V et 3.3V : ^C |
Les résultats concordent. Nos convertisseurs fonctionnent correctement.
Sixième test – le bus SPI
Pour tester le bus SPI, je dispose d’une platine comme décrite dans cette article (partie bus SPI). Il faut donc cabler :
- l’alimentation en +3,3V et la masse,
- le signal LE (Latch Enable) : nous prendrons la sortie GPIO 4 pour cela,
- les signaux MOSI et SCLK,
- le signal OE (output enable) sera cablé à la masse pour que les dels soient toujours activées.
En tant qu’exemple on va juste faire « tourner » un ensemble de deux dels (premier exemple réalisé avec LIFA). Le code source est donc le suivant :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
#include #include #include int main(void) { unsigned char spi_data[2]; const unsigned char data[] = { 1,1,2,2,4,4,8,8,16,16,32,32,64,64,128,128 }; int j=0; printf("Sixième test - Bus SPI - Anneau de DELs\nFin par Ctrl-C\n"); wiringPiSetupGpio(); wiringPiSPISetup( 0, 500000 ); // Initialisation du premier bus SPI (0) à 500KHz pinMode(4, OUTPUT); digitalWrite(4, LOW); for (;;) { spi_data[0] = data[j]; spi_data[1] = data[j+1]; wiringPiSPIDataRW(0, spi_data, 2); // Le même tableau sert à l'envoi et la réception des données digitalWrite(4, HIGH); delayMicroseconds(10); digitalWrite(4, LOW); delay(100); j+=2; j%=16; } return 0; } |
Rien de très spécial à dire sur ce code. J’ai vérifié à l’oscilloscope la fréquence SCLK est bien de 500KHz. Le signal SPI CE0 ( GPIO 8 ) passe bien à zéro lorsqu’on écrit sur cette interface. Il peut donc être utilisé pour piloter une broche CS (Chip Select) si le besoin s’en fait sentir. La documentation du bus SPI est disponible sur cette page. Bien retenir que le tableau que vous passez pour l’émission est aussi celui du stockage des données reçues. C’est pour cette raison que dans le code il y a deux tableaux différents !
La compilation se fait toujours de la même manière :
1 |
root@raspberrypi:~/wiringPi/exemples_OD# gcc -o spi_dels -lwiringPi spi_dels.c |
Conclusion: le bus SPI est très vraisemblablement la solution si vous devez communiquer rapidement avec un périphérique (par exemple un CAN ou CNA rapide). Rappel, pour modifier la vitesse du bus SPI, modifiez la valeur dans la fonction wiringPiSPISetup.
Logiquement il reste la partie sur la communication avec la voie série. Mais il y a plusieurs exemples dans le répertoire « examples » et les fonctions ressemblent à celles d’arduino. Donc pour l’instant je fais l’impasse.
Nous allons passer à l’interaction entre tout ce que l’on vient de voir et un serveur web à travers des scripts CGI.
Commandes des E/S ou des différents bus à travers une interface web
La première chose à faire et d’installer un serveur web. Il en existe de multiples sous Linux, le plus connu étant Apache. Cependant on souhaite économiser un peu les ressources du raspberry. Pour cela on va s’orienter vers un serveur web plus léger mais qui propose une interface avec les scripts CGI. Nous pouvons citer lighttpd, boa, nanohttpd, etc…
L’heureux serveur http est…apache2
J’ai eu un problème avec les scripts CGI sur lighttpd que je n’ai pu résoudre pour l’instant, aussi je passe à apache2. Vous allez tout simplement l’installer avec la commande suivante:
1 |
root@raspberrypi:~/wiringPi/exemples_OD# aptitude install apache2 |
Ensuite connectez-vous sur votre serveur web tout beau, tout neuf depuis un navigateur (local ou distant). Vous verrez alors qu’il reste quelques petites étapes de configuration avant qu’il corresponde à nos attentes. Les modifications à faire sont les suivantes:
- vos pages web doivent être sous le répertoire /var/www/
- les scripts CGI doivent être sous /usr/lib/cgi-bin/
On va tester un petit script codé en C. Une description théorique des scripts CGI est disponible sur Wikipédia.
Premier script CGI codé en langage C
Un script CGI est lancé par le serveur web (ici apache2) et tout ce qui est « imprimé » par la fonction printf est redirigé vers le serveur web qui renvoie le tout vers le client. Vous pouvez aussi consulter cet article ou encore celui-ci. Dans ce premier exemple, on va basculer l’état d’une sortie TOR à chaque fois que l’on lance le script.
Le code C de ce script CGI est le suivant:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include #include int main(void) { wiringPiSetupGpio(); pinMode(4, OUTPUT); printf("Content-type: text/html\n\n"); printf("Commande d'une DEL"); if (digitalRead(4) == 0) { digitalWrite(4, HIGH); printf("<span style="color: #ff0000;">GPIO4 maintenant a l'etat haut !</span>"); } else { digitalWrite(4, LOW); printf("<span style="color: #00ff00;">GPIO4 maintenant a l'etat bas !</span>"); } printf(""); return 0; } |
Quelques commentaires :
- on utilise la GPIO4 en sortie pour commander une del par exemple,
- la ligne printf(« Content… est très importante car elle indique à votre navigateur ce qu’il va recevoir comme données. Ici ce sera une page html. Les -deux- retours chariots ( n ) doivent être IMPÉRATIVEMENT présent car ils indiquent le commencement des données. C’est une source de problème très répandu sur les forums.
- ensuite on commence la structure d’une page web classique,
- on teste l’état de la broche 4 (oui oui on relie l’état de cette broche même si elle est en sortie) et en fonction de son niveau logique,
- on passe à l’état complémentaire et on en informe l’utilisateur final.
Cet exemple est compilé avec la ligne ci-dessous. Par contre il faut que cet exécutable est le bit setuid de positionner : ce bit permet d’exécuter le programme concerné avec les droits du créateur du fichier et pas celui qui le lance. En clair, c’est le serveur apache qui va lancer votre exécutable et il tourne avec l’identité ‘www-data’. Or pour modifier l’état d’une broche il faut avoir des droits ‘root’ ! Ce n’est pas une « bonne pratique » car si votre programme a des « bugs », ils peuvent être exploités pour obtenir l’identité ‘root’ sur votre raspberry. Dans notre cas, on va dire que l’on a rien à cacher et à protéger 😉
Enfin on finit par déplacer cet exécutable dans le répertoire /usr/lib/cgi-bin car c’est le seul endroit ou le serveur web apache à le droit d’exécuter des scripts CGI (dans sa configuration de base sur Debian). Les commandes sont donc les suivantes :
1 2 3 |
root@raspberrypi:~/wiringPi/exemples_OD# gcc -o cde_del.cgi -lwiringPi cde_del.cgi.c root@raspberrypi:~/wiringPi/exemples_OD# chmod +s cde_del.cgi root@raspberrypi:~/wiringPi/exemples_OD# mv cde_del.cgi /usr/lib/cgi-bin/ |
Connectez-vous alors à l’adresse de votre raspberry depuis un navigateur (Ex: http://addr_ip_raspberry/cgi-bin/cde_del.cgi). Si vous avez connecté une del sur la broche concerné elle changera d’état à chaque accès:
Premier script CGI (bis)
On va s’intéresser de nouveau au capteur de température 1wire mais en accédant au système de fichiers virtuels comme dans la première partie de l’article. Saisissez le code C ci-dessous:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include #include int main() { FILE* fichier = NULL; char chaine[100] = ""; printf("Content-type: text/plain\n\n"); fichier = fopen("/sys/bus/w1/devices/10-00080225c65d/w1_slave","r"); while (fgets(chaine, 100, fichier) != NULL) printf("%s", chaine); fclose(fichier); return 0; } |
Ce programme récupère le contenu du fichier qui donne la température depuis un capteur 1wire puis la renvoie vers le client à travers le serveur apache. C’est en gros ce que vous faisiez au début de l’article en ligne de commande. Compilez ce programme, changez ces droits d’exécution puis copiez-le dans le répertoire des scripts CGI:
1 2 3 |
root@raspberrypi:~/wiringPi/exemples_OD# gcc -o temp_1w.cgi temp_1w.cgi.c root@raspberrypi:~/wiringPi/exemples_OD# chmod a+s temp_1w.cgi root@raspberrypi:~/wiringPi/exemples_OD# cp temp_1w.cgi /usr/lib/cgi-bin/ |
Connectez-vous alors à l’adresse suivante depuis un navigateur : http://addr_ip_raspberry/cgi-bin/temp_1w.cgi
Et voilà… ce principe est alors reproductible avec quasiment toutes les commandes que l’on a vu en début d’article…
Deuxième exemple de script CGI : un bouton, deux boutons…un formulaire
On va égayer un peu notre page avec des boutons « ON » et « OFF » pour commander notre GPIO à distance. Pour cela, il faut créer un formulaire HTML (ne pas hésiter maintenant à utiliser des balises html5 : pour l’instant navigateur compatible : chrome et firefox). L’utilisation d’un formulaire est décrite sur cette page ou sur celle-ci. On crée donc notre page html pure comme suit :
1 |
root@raspberrypi:~/wiringPi/exemples_OD# cat cde_del.html |
On sauvegarde cette page sous le nom ‘cde_del.html’ et on la copie dans le répertoire des pages web géré par apache, à savoir /var/www.
On utilise une méthode POST pour passer les données du formulaire, donc on va récupérer la longueur de la chaine d’arguments du formulaire dans une variable d’environnement nommée CONTENT_LENGTH et son contenu depuis l’entrée standard (stdin). Pour traiter ce formulaire le code C suivant est proposé :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include #include #include #include int main(void) { char* lenstr; char ch_formulaire[100]; long len; wiringPiSetupGpio(); pinMode(4, OUTPUT); printf("Content-type: text/plain\n\n"); lenstr = getenv("CONTENT_LENGTH"); if (lenstr == NULL || sscanf(lenstr,"%ld",&len)!=1) printf("Erreur de traitement du formulaire"); else { fgets(ch_formulaire, len+1, stdin); printf("Recu du formulaire : %sn",ch_formulaire); if (strcmp(ch_formulaire,"GPIO4=ON") == 0) digitalWrite(4,HIGH); else digitalWrite(4,LOW); } return 0; } |
1 2 3 |
root@raspberrypi:~/wiringPi/exemples_OD# gcc -o cde_del2.cgi -lwiringPi cde_del2.cgi.c root@raspberrypi:~/wiringPi/exemples_OD# cp cde_del2.cgi /usr/lib/cgi-bin/ root@raspberrypi:~/wiringPi/exemples_OD# chmod +s /usr/lib/cgi-bin/cde_del2.cgi |
Connectez-vous sur la page : http://addr_ip_raspberry/cde_del.html puis cliquez sur un des boutons ON ou OFF. On passe alors à la page de traitement de ce formulaire. Vous remarquerez que les données du formulaires sont passées sous la forme clé=valeur (ici GPIO4=ON ou GPIO=OFF).
Un exemple complet…enfin par rapport à notre cahier des charges initiales !
A venir 🙂
Bonjour,
Bravo pour ce très bon tutoriel.
J’ai un compteur (base DS2423, hobby-boards) en 1-wire. J’ai effectué la manip que vous décrivez et j’ai 2 problèmes :
– la ligne modprobe w1_therm, je la fait avec w1_ds2423 et j’obtiens « Operation non permitted »; je la résout en faisant sudo.
– suite à ça lorsque je liste les capteurs avec « ls /sys/bus/w1/devices/ » je ne trouve pas mon compteur.
Auriez vous une idée pour solutionner?
Merci.
Merci beaucoup pour cette article qui m’as bien aidé (-:
Salut,
Merci pour ton tuto très complet !!
Je rencontre un problème concernant l’affichage d’une image dans un cgi, voilà j’ai repris ton code « GPIO4 maintenant a l’etat haut ! » et « GPIO4 maintenant a l’etat bas ! » qui change de couleur, mais je voudrais mettre une image du genre un voyant vert ou rouge à la place du texte mais ça ne fonctionne pas :
printf(« Content-Type: text/html;\n\n »);
printf(« Commande du relais »);
if (digitalRead(RELAY) == ON)
{
digitalWrite(RELAY, OFF);
printf(« Le relais est active ! »);
printf(« »);
}
else
{
digitalWrite(RELAY, ON);
printf(« Le relais est desactive ! »);
printf(« »);
}
printf(« »);
Merci d’avance pour ton aide !
Salut pour ton problème c’est tout simplement tu va changer ce qui entre print comme ca
printf(« »)
ou
printf(« ») si tu veu appler une image sur internet selon ton bosoin
j’ai ajouter la height et width pour maîtrisé la taile d’image
donc ton il va rassembler a ca
#include
#include
int main(void)
{
wiringPiSetupGpio();
pinMode(4, OUTPUT);
printf(« Content-type: text/html\n\n »);
printf(« Commande d’une DEL »);
if (digitalRead(4) == 0) {
digitalWrite(4, HIGH);
printf(« »);
} else {
digitalWrite(4, LOW);
printf(« »);
}
printf(« »);
return 0;
}
@Sebastien
bonjour,
Bravo pour ce tuto très complet.
J’ai remarqué qu’à partir du troisième test de la programmation en C, il manque les librairies inclues.
Les lignes ne contiennent que « #include ».
Merci encore pour ce très bon travail.