Les 5
GPIO: een LED laten knipperen
Pinnen configureren als uitgang, een LED aansturen, wachten met een vertragingslus, en registers versus een HAL.
🎯 Na deze les kun je
- een GPIO-pin configureren als uitgang met het DDR-register
- een pin hoog en laag maken met het PORT-register
- uitleggen hoe een vertragingslus werkt en wat de nadelen zijn
- registercode en HAL-code met elkaar vergelijken
De "hallo wereld" van embedded is een knipperende LED. Het lijkt een klein ding, maar als dat werkt, weet je dat je toolchain klopt, je klok klopt, je pin klopt en je firmware echt draait. In deze les begrijp je elke regel ervan.
GPIO-registers
GPIO (General Purpose Input/Output) zijn pinnen die je zelf aan, uit of uitlezen kunt. Op de ATmega328P zijn ze gegroepeerd in poorten B, C en D. Elke poort heeft drie registers:
| Register | Betekenis per bit |
|---|---|
DDRx |
Data Direction: 0 = ingang, 1 = uitgang |
PORTx |
bij een uitgang: 0 = laag (0 V), 1 = hoog (5 V). Bij een ingang: pull-up aan/uit (les 6) |
PINx |
de werkelijke toestand van de pin lezen |
Na een reset staan alle DDR-bits op 0: alle pinnen zijn ingang. Dat is een veilige keuze: een pin die per ongeluk uitgang is, kan kortsluiting maken met wat eraan hangt.
De schakeling
Een LED heeft een voorschakelweerstand nodig, anders trekt hij te veel stroom en gaan de LED of de pin kapot. Met 5 V, een rode LED (~2 V) en 10 mA: R = (5 − 2) / 0,010 = 300 Ω; neem 330 Ω. De Uno heeft op D13 (PB5) al een LED met weerstand op het bordje.
Een pin van de ATmega328P mag maximaal 40 mA leveren (aanbevolen: 20 mA), en de hele chip niet meer dan 200 mA. Een motor of relais sluit je nooit direct op een pin aan; daar heb je een transistor of driver voor nodig (les 10).
Uitgewerkt voorbeeld
#include <avr/io.h>
#include <util/delay.h>
#define LED_PIN PORTB5
int main(void) {
DDRB |= (1 << DDB5); /* 1. PB5 als uitgang */
for (;;) {
PORTB |= (1 << LED_PIN); /* 2. LED aan */
_delay_ms(200);
PORTB &= (uint8_t)~(1 << LED_PIN); /* 3. LED uit */
_delay_ms(800);
}
}
Voorspel: hoe vaak per seconde knippert de LED, en hoe lang is hij aan? Eén keer per seconde (200 + 800 ms), 200 ms aan.
Een pin omdraaien kan ook door een 1 te schrijven naar het PINx-register: PINB = (1 << PINB5);. Dat is een eigenaardigheid van de AVR: schrijven naar PIN draait de pin om in één instructie. Handig, maar minder leesbaar dan PORTB ^= ....
Hoe werkt _delay_ms?
_delay_ms(200) rekent met F_CPU uit hoeveel klokslagen 200 ms is (3,2 miljoen bij 16 MHz) en genereert een lus die precies zo lang duurt. Het is een bezig-wachtlus (busy wait): de CPU doet al die tijd niets anders.
Dat is prima voor een eerste programma, maar het heeft grote nadelen:
- Tijdens het wachten kan je programma niet reageren op een knop of seriële invoer.
- De CPU verbruikt volle stroom terwijl hij niets doet.
- Interrupts (les 7) die tussendoor draaien, maken de vertraging langer.
In les 7 vervang je dit door een timer, en in les 13 schrijf je niet-blokkerende code die meerdere dingen tegelijk doet.
HAL versus registers
Je kunt hetzelfde schrijven met een HAL (Hardware Abstraction Layer): een bibliotheek die de registers verbergt. Arduino is daar het bekendste voorbeeld van:
pinMode(13, OUTPUT);
digitalWrite(13, HIGH);
| Registers | HAL (zoals Arduino) | |
|---|---|---|
| Leesbaar | minder | meer |
| Snel en klein | ja: één instructie | digitalWrite kost tientallen instructies |
| Overdraagbaar | nee, chip-specifiek | ja, dezelfde code op andere chips |
| Begrijpen wat er gebeurt | ja | verborgen |
In deze cursus werk je met registers, omdat je dan begrijpt wat er gebeurt. In les 20 bouw je zelf een kleine abstractielaag, zodat je de voordelen van beide krijgt.
Typische fouten
- DDR vergeten: je schrijft
PORTB |= (1 << PORTB5)maar de pin is nog ingang. Je zet dan de interne pull-up aan (les 6) en de LED gloeit hooguit zwakjes. - Verkeerde poort: Arduino-pin D5 is PD5, niet PB5. Kijk in je pinouttabel (les 2).
- LED andersom: een LED geleidt maar in één richting. Het lange pootje (anode) gaat naar de plus-kant.
Oefeningen
- Laat de LED op PB5 twee keer kort knipperen (100 ms aan, 100 ms uit) en daarna een seconde uit blijven, als een hartslag.
- Sluit een tweede LED aan op PD6 (Arduino D6) en laat beide om en om knipperen.
- Waarom kan je programma uit oefening 1 niet tegelijk reageren op een knop?
Modelantwoord
- Een mogelijke uitwerking:
#include <avr/io.h>
#include <util/delay.h>
int main(void) {
DDRB |= (1 << DDB5);
for (;;) {
for (uint8_t i = 0; i < 2; i++) {
PORTB |= (1 << PORTB5);
_delay_ms(100);
PORTB &= (uint8_t)~(1 << PORTB5);
_delay_ms(100);
}
_delay_ms(1000);
}
}
- Zet ook
DDRD |= (1 << DDD6);en draai in de lus beide om: begin met de ene aan en de andere uit, en doe danPORTB ^= (1 << PORTB5); PORTD ^= (1 << PORTD6);gevolgd door een vertraging. _delay_msblokkeert: zolang de lus wacht, wordt er geen code uitgevoerd die de knop leest.
Lab: knipperende LED
- Laat de LED op PB5 een SOS-signaal geven in morse: drie kort (150 ms), drie lang (450 ms), drie kort, met 150 ms tussen de tekens en 1 s pauze na elk SOS.
- Gebruik alleen registers, geen Arduino-functies.
- De check draait je firmware in de simulator en controleert de tijden met een marge van 5%.
beetje check embedded-c-les5
Samenvatting
- Elke poort heeft
DDRx(richting),PORTx(uitvoer/pull-up) enPINx(lezen). - Na een reset is elke pin ingang; zet een bit in
DDRxom er een uitgang van te maken. _delay_msis een bezig-wachtlus: simpel, maar je programma doet ondertussen niets anders.- Registers zijn snel en precies; een HAL is leesbaarder en overdraagbaar.
Volgende les: de andere kant op, pinnen uitlezen met knoppen.
Lab
Knipperende LED
💻 Dit lab doe je op je eigen computer met Docker. Start de lab-container met (geeft de opdracht een eigen startcommando, gebruik dan dat):
$ docker run -it --rm registry.wizg.it/webhosting/beetje-labs:embedded-c-les5
Klaar? Controleer je werk met:
$ beetje check embedded-c-les5
📝 Quiz: GPIO en een knipperende LED
Dit was de laatste gratis les
Je hebt les 1–5 van Een beetje Embedded C gratis gevolgd. Wil je verder? Met één aankoop (€ 29,00, eenmalig) krijg je de overige 20 lessen, de live labs en het certificaat. Geen abonnement.