Met de programmeertaal C en met de bibliotheek PiGPIO wordt er een stoplicht gemaakt voor het doorlaten van voetgangers na een druk op de knop. Een andere knop zorgt voor het afsluiten van deze dienst op een nette manier. In dit artikel laten we je zien hoe dat moet.
Auteur: Paul Reemeijer
Bij het aansturen of maken van programma’s op en voor de Raspberry Pi wordt er zeer vaak gebruik gemaakt van de programmeertaal Python. Dit is zeker geen slechte keuze en het is met het maken van prototypes voor je idee ook zeker een goed idee om Python te gebruiken. Echter, door een persoonlijke interesse in C ben ik op zoek gegaan of het mogelijk is om de GPIO van de Raspberry PI aan te sturen met C.
Het artikel zal op geen enkel aangehaald onderdeel: de programmeertaal C, de Raspberry Pi, de gebruikte elektronica of de bibliotheek PiGPIO de diepte in gaan. Het is simpelweg niet mogelijk om bijvoorbeeld C tot in de detail door te nemen of het gebruikte voorbeeldprogramma te perfectioneren. Het programma kan “mooier”, maar dat schiet het doel voorbij om helder te zijn in het gebruik van de programmeertaal en de bibliotheek. De bedoeling is om je interesse aan te wakkeren in de mogelijkheden van C op de Pi.
LET OP!
Bij het in gebruik nemen van de GPIO op de Raspberry Pi kan de Raspberry Pi defect raken bij het niet correct aansluiten. Ik heb wel eens kortsluiting veroorzaakt en dit heeft gelukkig niet geresulteerd in een defecte Pi, maar dat is zeker niet vanzelfsprekend.
De afkorting GPIO staat voor General Purpose Input/Output en er zijn er in totaal veertig op de Raspberry Pi aanwezig (met uitzondering van de eerste versie van de Pi). De veertig pinnen hebben verschillende doeleinden.
Zo heb je de GPIO. Dit zijn de standaard pinnen om iets aan- of uit te zetten. Je hebt ook nog I2C-pinnen, die je kunt gebruiken voor bepaalde hardware, die dit ondersteunen. SPI-pinnen zijn te vergelijken met de I2C-pinnen, alleen is dit een ander protocol. UART-pinnen zijn bestemd voor seriële communicatie. Het is echter niet zo dat je bijvoorbeeld de UART-pinnen niet kunt gebruiken voor standaard GPIO.
In mijn zoektocht naar een bibliotheek voor C kwam ik uit bij verschillende bibliotheken, die te gebruiken zijn voor het schrijven van een programma voor je Pi in deze taal. Mijn keuze is uiteindelijk op PiGPIO gevallen, maar WiringPi (http://wiringpi.com/) is ook zeker de moeite waard op te onderzoeken. Voor meer informatie over PiGPIO en de mogelijkheden van de bibliotheek verwijs ik je naar de website http://abyz.me.uk/rpi/pigpio/cif.html.
Voor het bouwen van het voorbeeld uit dit artikel heb je de volgende onderdelen nodig om het programma over te nemen en hiermee te testen.
Deze workshop zou ook op de Raspberry Pi 4 moeten werken. Er wordt echter door de maker van PiGPIO gewaarschuwd dat dit op dit moment niet vanzelfsprekend is. Er wordt wel aan gewerkt om dit op te lossen.
Het installeren van Raspbian is te vinden op de volgende pagina: https://www.raspberrypi.org/downloads/
Gebruik het volgende schema om na te bouwen (zie afbeelding 1).
Het installeren van de PiGPIO bibliotheek op Raspbian gaat als volgt:
wget abyz.me.uk/rpi/pigpio/pigpio.tar tar xf pigpio.tar cd PIGPIO make sudo make install
Op http://abyz.me.uk/rpi/pigpio/download.html staan meer mogelijkheden voor het installeren van PiGPIO.
Op de website van de Raspberry Pi Foundation is de schematische documentatie te vinden over GPIO. Er is alleen een veel makkelijkere manier om het overzicht te krijgen van je eigen specifieke Raspberry Pi zonder gebruik te maken van het internet.
Het programma pinout met het gelijknamige CLI commando, die standaard is geïnstalleerd op Raspbian, kun je aanroepen met, hoe kan het ook anders, het commando:
pinout
De output die je ziet laat heel duidelijk zien welke pin welk nummer heeft (zie afbeelding 2).
Op de website van de makers van pinout (https://pinout.xyz/) is veel meer informatie te vinden over de GPIO van de Raspberry Pi.
Het volgende geldt niet specifiek voor dit artikel, maar is wel van belang voor je (toekomstige) projecten, die je na wilt maken of zelf gaat creëren. Er zijn twee manieren waarop gewerkt wordt met de nummering van de GPIO pinnen, namelijk fysiek of met de Broadcom nummering. Beide manieren zie ik gebruikt worden in voorbeelden. De PiGPIO bibliotheek maakt alleen gebruik van de Broadcom nummering. Dit is een feit en het is dus niet mogelijk om dit te wijzigen voor je programma, als je gebruik maakt van deze bibliotheek.
Het verschil is goed zichtbaar in het pinout screenshot.
Open je favoriete editor voor C. Dit kan bijvoorbeeld VIM zijn, maar als je nog geen editor hebt voor de programmeertaal C, dan zijn Code::Blocks (http://codeblocks.org/) of CodeLite (https://codelite.org/) zeker de moeite waard om naar te kijken.
Heb je een andere voorkeurs-IDE? Kijk dan voor support voor C. Het programmeren werkt nu eenmaal makkelijker met een omgeving, die je ondersteunt en wijst op fouten.
#include <stdio.h> #include <pigpio.h> #include <stdlib.h> void start_traffic_light() { printf("Button for traffic is pushed.\n"); time_sleep(0.5); printf("Letting traffic pass.\n"); gpioWrite(15,0); gpioWrite(21,1); time_sleep(3.0); gpioWrite(21,0); gpioWrite(20,1); time_sleep(1.5); gpioWrite(20,0); gpioWrite(21,0); gpioWrite(15,1); } void shutdown_traffic_light() { printf("Shutting down traffic light.\n"); gpioWrite(15,0); gpioTerminate(); time_sleep(0.5); exit(0); } int main() { int o,q; if (gpioInitialise() < 0) { printf("Gpio initialisation failed\n"); return 1; } if (gpioRead(15) == 0) gpioWrite(15,1); gpioSetMode(12, PI_INPUT); gpioSetPullUpDown(12, PI_PUD_UP); gpioSetMode(14, PI_INPUT); gpioSetPullUpDown(14, PI_PUD_UP); gpioSetMode(15, PI_OUTPUT); gpioSetMode(20, PI_OUTPUT); gpioSetMode(21, PI_OUTPUT); printf("\tTraffic light is operational.\n\n"); while(1) { o = gpioRead(14); q = gpioRead(12); if (o == 0) start_traffic_light(); if (q == 0) shutdown_traffic_light(); } }
De eerste drie regels van het programma zijn de benodigde bibliotheken om het programma te laten werken.
In Main worden een aantal zaken geïnitialiseerd / gedefinieerd, zoals o, q en int. Daarna wordt er met een if statement gecontroleerd of dat de bibliotheek PiGPIO wel geïnitialiseerd kan worden. Zo niet, dan zal het programma stoppen. Nu zeker is dat de bibliotheek te gebruiken is, gaan de GPIO pinnen geconfigureerd worden.
Het if statement op regel 37 zorgt ervoor dat bij het starten van het programma het stoplicht op rood staat. GpioRead kijkt of dat pin 15 uit staat. Indien dat het geval is, dan wordt deze aangezet met gpioWrite(pinnummer,1). In deze functie betekent 1 aan en 0 uit.
Op de pinnen 12 en 14 zitten knoppen aangesloten. Deze worden geïnitialiseerd door middel van de regels:
gpioSetMode(12, PI_INPUT); gpioSetPullUpDown(12, PI_PUD_UP); gpioSetMode(14, PI_INPUT); gpioSetPullUpDown(14, PI_PUD_UP);
gpioSetMode zet de specifieke mode voor pin 12 en pin 14 naar input, zodat de knoppen gebruikt kunnen worden. gpioSetPullUpDown zet voor beide knoppen “hoog” (1) door PI_PUD_UP.
Op pin 15, 20 en 21 zijn de led’s gekoppeld. Deze geven alleen maar licht en gpioSetMode PI_OUTPUT is voldoende om ze op de correcte manier te laten werken. Je zet de led aan of uit door gpioWrite.
Na de initialisaties is er een printf statement, zodat je ook op het scherm feedback hebt, dat er daadwerkelijk op een knop gedrukt kan worden.
In de while wordt er continue gekeken of er op een van de knoppen gedrukt wordt, die zijn gekoppeld aan pin 12 of 14.
Bij een druk op de knop, die aangesloten is op pin 14, zal de functie start_traffic_light worden aangesproken. Deze functie is in het begin voorzien van een printf statement, zodat je weet dat de druk op de knop is geregistreerd.
time_sleep is een functie, die is beschreven in de pigpio.c.
time_sleep zorgt voor een korte pauze, voordat de rode led (pin 15) zal worden uitgeschakeld en groen (pin 21) zal worden aangezet. Na weer een korte pauze te hebben ingelast, zal groen (pin 21) worden uitgeschakeld en oranje (pin 20) worden aangezet. Dit wordt nogmaals herhaald van oranje naar rood.
De code van time_sleep is te achterhalen door pigpio.c te openen en te zoeken naar void time_sleep, zodat je weet wat de achterliggende techniek is achter deze functie. Dit geldt voor alle functies en is een mooi voorbeeld van open source.
Zoals je duidelijk ziet in start_traffic_light is dat 0 ervoor zorgt dat iets uit gaat en dat 1 zorgt voor een inschakeling.
De functie shutdown_traffic_light is er voor om het programma op een nette manier af te sluiten. Bij het afsluiten van het programma door CTRL+C zal dit niet gebeuren. Als je programma niet goed werkt, is CTRL+C zeker nog te gebruiken. De functie shutdown_traffic_light zorgt ervoor dat de rode led uit wordt geschakeld en gpioTerminate regelt dat de gebruikte DMA-kanalen worden gereset, het geheugen weer vrij wordt gegeven en dat alle actieve threads beëindigd worden.
Het compileren van het programma vergt wat meer dan alleen het commando gcc aanroepen en je C programma op te geven. Lukt het niet om gcc te gebruiken, dan is deze zeer waarschijnlijk niet geïnstalleerd. Controleer als eerste of dat dit daadwerkelijk het geval is door het volgende commando uit te voeren op de CLI:
gcc --version
Krijg je geen versie terug? Dan is gcc daadwerkelijk niet geïnstalleerd. Installeer gcc met het commando:
sudo apt-get install gcc
Compileer het programma als volgt:
gcc -Wall -pthread -o prog.com prog.c -lpigpio -lrt
-Wall toont alle waarschuwingen bij het compileren en is niet per se noodzakelijk. -pthread voegt ondersteuning toe voor multithreading. De -o met de naam daarachter is de naam van de executable, die je uiteindelijk gaat uitvoeren.
-lpigpio en -lrt starten beide met -l en deze optie zorgt voor het linken van de libraries pigpio en rt. De rt -ibliotheek (librt) handelt verschillende POSIX.1b interfaces af.
Gcc heeft een zeer uitgebreide manpage. Voor meer achtergrondinformatie over de gebruikte opties of andere opties, die je wilt onderzoeken, raad ik aan om de manpage te openen (man gcc).
Als het compileren zonder problemen is gelukt, voer je het gecompileerde bestand uit:
sudo ./prog.com
Het programma uitvoeren met sudo is noodzakelijk vanwege het gebruik van de GPIO pinnen.
Python is voor prototyping waarschijnlijk nog wel steeds de beste optie, maar hopelijk heeft het artikel je interesse gewekt om met C aan de slag te gaan op de Raspberry Pi en het aansturen van General Purpose Input/Output (GPIO). De bibliotheek PiGPIO heeft ook zeker veel meer in zich, zoals bijvoorbeeld een daemon optie. Leuk dus om thuis verder mee te spelen!
Op de website van de Raspberry Pi Foundation is. Er is alleen een veel makkelijkere manier om het overzicht te krijgen van je eigen specifieke Raspberry Pi zonder gebruik te maken van het internet.
Met het programma pinout krijg je de schematische weergave te vinden over alle GPIO pinnen.