Handboek · hoofdstuk 25Van analoog naar digitaal
Van een spanning naar een getal, en van een getal terug naar licht
De wereld is analoog: een temperatuur of een lichtsterkte kan elke waarde aannemen, op elk moment. Een microcontroller kent alleen enen en nullen. In dit hoofdstuk leer je hoe die twee elkaar vinden: hoe je met bits getallen schrijft, hoe een ADC een spanning in 1024 trapjes meet, hoe vaak je moet meten om niets te missen, en hoe een digitale pin met PWM toch 'een beetje' aan kan staan. Met dat laatste dim je de groeilampen van de klimaatmodule zo, dat ze het daglicht precies aanvullen.

- Je kan het verschil tussen een analoog en een digitaal signaal uitleggen: bemonsteren in de tijd en afronden in niveaus.
- Je kan getallen omzetten tussen decimaal, binair en hexadecimaal, en uitleggen wat een bit en een byte zijn.
- Je kan de resolutie en het bereik van een ADC berekenen, een spanning omrekenen naar een ADC-waarde en omgekeerd, en uitleggen hoe een ADC met opvolgende benadering werkt.
- Je kan een bemonsteringsfrequentie kiezen en herkennen wanneer aliasing optreedt.
- Je kan een PWM-signaal beschrijven met periode, frequentie en duty cycle, en de gemiddelde spanning en het vermogen berekenen.
- Je kan met analogWrite een led, een ledstrip of groeilampen dimmen via een MOSFET, en de verliezen schatten.
Een wereld in enen en nullen
In 1948 publiceerde de Amerikaanse wiskundige en ingenieur Claude Shannon een artikel met een bescheiden titel, 'A Mathematical Theory of Communication'. Hij toonde dat je elke boodschap (tekst, een telefoongesprek, een beeld) kan meten in één eenheid: het aantal ja-neevragen dat je nodig hebt om ze te beschrijven. Die eenheid noemde hij, met een woord van zijn collega John Tukey, de bit, van binary digit.
Een jaar later bewees Shannon ook hoe vaak je een geluid of een ander signaal moet meten om het perfect te kunnen terugmaken: meer dan twee keer per trilling van de snelste toon erin. Harry Nyquist had het idee al in 1928 aangevoeld. Op die regel rust de muziek-cd uit 1982: 44 100 metingen per seconde, elk in 16 bits, genoeg voor tonen tot boven 20 000 Hz, de grens van het menselijk gehoor.
Een microcontroller doet op kleine schaal hetzelfde. Hij meet een spanning, maakt er een getal van 10 bits van, rekent ermee, en stuurt dan weer iets 'analoogs' aan: een led die half brandt, een motor die half zo snel draait. Hoe dat heen en terug gaat, is het onderwerp van dit hoofdstuk.
Elke sensor van Habitat komt binnen via een ADC, en elke actuator die meer kan dan aan en uit, wordt met PWM gestuurd. Wie weet hoe groot een ADC-stap is en hoe vaak je moet meten, weet ook welke metingen je kan vertrouwen.

Analoog en digitaal
Wat je al weet. Een digitale pin is hoog of laag (F24); analogRead geeft een getal van 0 tot 1023 (F25), en dat getal hoort bij een spanning in stappen van 4,88 mV (hoofdstuk 22).
Een analoog signaal kan elke waarde aannemen, op elk moment: de temperatuur in de kweekruimte stijgt niet in sprongetjes van een graad, en ze bestaat ook tussen twee metingen. Een digitaal signaal is op twee manieren beperkt:
- in de tijd: je meet maar op bepaalde ogenblikken, bijvoorbeeld elke seconde (bemonsteren);
- in de waarde: je rondt af op een eindig aantal niveaus (kwantiseren), bij een ADC van 10 bit op 1024 niveaus.
De grafiek toont het met een bewust grove versie: om de seconde gemeten en afgerond op stappen van 2 °C. Wat tussen twee metingen gebeurt, is verloren, en elke meting is tot 2 °C te laag. Met meer niveaus en vaker meten komt de digitale versie dichter bij het origineel, maar het kost meer bits. De kunst is te kiezen wat genoeg is.
Een digitaal signaal kan je zonder verlies kopiëren, versturen, opslaan en bewerken: een 1 blijft een 1, ook na een lange draad met wat ruis. Een analoge spanning verandert bij elke stap een beetje. Daarom meet je zo dicht mogelijk bij de sensor, en reken je daarna digitaal verder.
Het binaire talstelsel
Ons talstelsel is decimaal: tien cijfers, en elke plaats is tien keer zoveel waard als de plaats rechts ervan. In 407 staat de 4 voor . Een computer heeft maar twee toestanden (spanning of geen spanning) en rekent daarom binair: twee cijfers, 0 en 1, en elke plaats is twee keer zoveel waard. Eén binair cijfer is een bit; acht bits samen zijn een byte.
Van binair naar decimaal: tel de gewichten op van de plaatsen met een 1. In de figuur: .
Van decimaal naar binair: deel telkens door 2 en noteer de rest. De resten, van onder naar boven gelezen, zijn de bits. Voor 200:
| deling | quotiënt | rest |
|---|---|---|
| 200 : 2 | 100 | 0 |
| 100 : 2 | 50 | 0 |
| 50 : 2 | 25 | 0 |
| 25 : 2 | 12 | 1 |
| 12 : 2 | 6 | 0 |
| 6 : 2 | 3 | 0 |
| 3 : 2 | 1 | 1 |
| 1 : 2 | 0 | 1 |
De resten van onder naar boven: 1100 1000.
Met bits schrijf je verschillende waarden, van 0 tot . Een byte gaat dus van 0 tot 255, en een ADC van 10 bit van 0 tot 1023:
| bits | 1 | 2 | 3 | 4 | 8 | 10 | 12 | 16 |
|---|---|---|---|---|---|---|---|---|
| niveaus | 2 | 4 | 8 | 16 | 256 | 1024 | 4096 | 65 536 |
| grootste getal | 1 | 3 | 7 | 15 | 255 | 1023 | 4095 | 65 535 |
Op de Uno en de Mega is een int 16 bits: van −32 768 tot 32 767 (één bit voor het teken). millis() geeft een unsigned long van 32 bits: tot 4 294 967 295 ms, ongeveer 49,7 dagen. Daarna begint de teller weer bij 0: daarom schrijf je altijd nu - start >= wachttijd (hoofdstuk 23 en 29). Ook tekst is binair: de letter A wordt verstuurd als de byte 65.
Omrekenen tussen decimaal, binair en hexadecimaal
(a) Schrijf 1023 binair. (b) Welk decimaal getal is ? (c) Een Arduino-programma bevat 0x3FF en 0xB6. Welke getallen zijn dat? (d) Hoeveel bits heb je minstens nodig om de ADC-waarden van 0 tot 1023 op te slaan, en hoeveel bytes neemt dat in?
- tabel met machten van 2; hexadecimale cijfers 0-9, A = 10 … F = 15
- 1023 binair
- decimaal
- 0x3FF en 0xB6
- bits en bytes voor 0-1023
- 1(a) : tien enen, . (Met delen door 2 kom je hetzelfde uit: elke rest is 1.)
- 2(b) .
- 3(c) Hexadecimaal (grondtal 16) gebruikt 0-9 en A-F. Eén hexcijfer is precies vier bits, dus een byte is twee hexcijfers. , of per vier bits: . .
- 4(d) is te weinig, precies genoeg: 10 bits. Computers bewaren per hele byte, dus 2 bytes (16 bits, waarvan 6 ongebruikt).
De ADC: resolutie en bereik
Een ADC (analoog-digitaalomzetter) verdeelt een spanningsgebied, van 0 V tot de referentiespanning , in gelijke stappen. Twee getallen bepalen wat hij kan:
- het bereik: van 0 tot . Negatieve spanningen worden 0, spanningen boven worden 1023. (Boven de voedingsspanning mag een pin nooit komen: dan kan hij stukgaan.)
- de resolutie: de grootte van één stap, .
De grafiek toont het principe met maar 3 bits: 8 niveaus, stappen van 0,625 V. Een ADC van 10 bits heeft hetzelfde trappetje, maar met 1024 treden van 4,88 mV.
Resolutie is niet hetzelfde als nauwkeurigheid (hoofdstuk 1). Een stap van 4,88 mV zegt hoe fijn je kan aflezen, niet of het getal klopt. Als de referentie 4,95 V is in plaats van 5,00 V, is elke meting 1 % te hoog, hoe fijn de trapjes ook zijn. En ruis op de sensor maakt de laatste bit vaak onzeker.
De referentie kiezen. Wie kleine spanningen meet, verspilt het grootste deel van de treden. Met analogReference(INTERNAL) meet een Uno tegen een ingebouwde referentie van ongeveer 1,1 V (op de Mega INTERNAL1V1 of INTERNAL2V56): de stap wordt . Het bereik krimpt dan wel tot 1,1 V. De interne referentie ligt per chip ergens tussen 1,0 en 1,2 V: ijk ze. En gooi de eerste metingen na het omschakelen weg.
Habitat: hoe fijn meet de TMP36 van de meetkas?
De TMP36 op A1 van de meetkas (F25) geeft . (a) Hoeveel graden is één ADC-stap met de standaardreferentie van 5 V? (b) En met de interne referentie van 1,1 V? Tot welke temperatuur kan je dan meten? (c) Welke ADC-waarde geeft 25,0 °C in beide gevallen? (d) Is 1,1 V een goed idee voor de kas, die op een zonnige dag 32 °C haalt?
- (V, °C)
- 10 bit; of
- °C per stap
- bereik met 1,1 V
- ADC-waarde bij 25 °C
- keuze
- 1(a) Eén stap is 4,88 mV; de sensor geeft 10 mV per graad: per stap.
- 2(b) Met 1,1 V: , dus per stap, bijna vijf keer fijner. Hoogste meetbare spanning 1,1 V: .
- 3(c) Bij 25,0 °C is . Met 5 V: . Met 1,1 V: .
- 4(d) Ja: tot 60 °C is ruim genoeg voor de kas (32 °C), ook in de volle zon. Maar de TMP36 zelf is maar op ongeveer ±2 °C nauwkeurig (daarom de ijkcorrectie van −1,5 °C uit F25): de fijnere stap maakt de meting vloeiender (kleine veranderingen worden zichtbaar), niet juister.
Binnen in de ADC: tien vragen voor tien bits
In hoofdstuk 22 bleef open hoe de ADC zijn getal vindt. De ADC van de ATmega werkt met opvolgende benadering, het spelletje 'raad mijn getal' met ja-neevragen. Hij heeft een kleine digitaal-analoogomzetter die een proefspanning maakt, en een comparator die zegt of de gemeten spanning groter of kleiner is.
- Eerst houdt hij de ingangsspanning vast op een condensatortje van ongeveer 14 pF (hoofdstuk 24): de sample and hold.
- Dan probeert hij het hoogste bit: is stappen (2,5 V)? Ja: dat bit blijft 1. Nee: het wordt 0.
- Daarna het volgende bit (256), dan 128, en zo verder tot het laatste bit (1).
Na tien vragen staan alle tien bits vast. Voor :
| vraag | bit | proefgetal | proefspanning | U ≥ proef? | tussenstand |
|---|---|---|---|---|---|
| 1 | 9 (512) | 512 | 2,5000 V | ja: 1 | 10 0000 0000 |
| 2 | 8 (256) | 768 | 3,7500 V | nee: 0 | 10 0000 0000 |
| 3 | 7 (128) | 640 | 3,1250 V | ja: 1 | 10 1000 0000 |
| 4 | 6 (64) | 704 | 3,4375 V | nee: 0 | 10 1000 0000 |
| 5 | 5 (32) | 672 | 3,2812 V | nee: 0 | 10 1000 0000 |
| 6 | 4 (16) | 656 | 3,2031 V | nee: 0 | 10 1000 0000 |
| 7 | 3 (8) | 648 | 3,1641 V | ja: 1 | 10 1000 1000 |
| 8 | 2 (4) | 652 | 3,1836 V | ja: 1 | 10 1000 1100 |
| 9 | 1 (2) | 654 | 3,1934 V | ja: 1 | 10 1000 1110 |
| 10 | 0 (1) | 655 | 3,1982 V | ja: 1 | 10 1000 1111 |
Resultaat: , en inderdaad is . Elke vraag halveert het gebied waarin het antwoord ligt: na tien vragen is dat één stap breed. Op een Arduino kost één analogRead 13 tikken van de ADC-klok van 125 kHz: 104 µs, dus hoogstens ongeveer 9600 metingen per seconde.
Bemonsteren: hoe vaak moet je meten?
Een microcontroller meet niet voortdurend, maar op vaste ogenblikken. Het aantal metingen per seconde is de bemonsteringsfrequentie , in hertz; de tijd ertussen is . Hoe vaak is genoeg? Dat hangt af van hoe snel het signaal verandert. De temperatuur van het voedingsreservoir verandert in uren: eens per minuut is ruim. Een wisselspanning van 50 Hz verandert elke milliseconde: daar heb je honderden metingen per seconde nodig.
Te traag meten is erger dan weinig informatie. De grafiek toont een signaal van 9 Hz, gemeten met . Tussen twee metingen gaat het signaal bijna één keer volledig rond. De metingen liggen daardoor netjes op een traag signaal van 1 Hz, dat er in werkelijkheid niet is. Dat heet aliasing: een snel signaal doet zich voor als een traag. Je kan het achteraf niet meer herkennen: de metingen van het signaal van 9 Hz zijn precies dezelfde als die van een signaal van 1 Hz. Je ziet het ook in films, waar de wielen van een auto soms achteruit lijken te draaien: de camera bemonstert 24 beelden per seconde.
De schijnbare frequentie is de afstand tot het dichtstbijzijnde veelvoud van : 9 Hz ligt op 1 Hz van 10 Hz, dus je ziet 1 Hz. Een signaal van 50 Hz dat je precies 50 keer per seconde meet, lijkt zelfs stil te staan (0 Hz): je meet elke keer op hetzelfde punt van de golf.
| toepassing | bemonstering | bits | datastroom |
|---|---|---|---|
| temperatuur van de kweekruimte | 1 keer per 10 s | 10 | 1 bit/s |
| klimaatmodule: 7 analoge sensoren (A0-A6) | 1 keer per 10 s | 7 × 16 (2 bytes) | 120 960 bytes per dag |
| telefoongesprek | 8000 per s | 8 | 64 000 bit/s |
| muziek-cd (stereo) | 44 100 per s | 2 × 16 | 1 411 200 bit/s |
Meer metingen en meer bits kosten geheugen. De datalogger van de klimaatmodule (hoofdstuk 30) bewaart zeven analoge waarden om de 10 s: 2 bytes per waarde is 120 960 bytes per dag, ongeveer 44 MB per jaar. Als tekst (CSV) met datum en tijd per regel wordt dat al snel vier keer meer.
Habitat: de lampstroom meten terwijl de lampen gedimd zijn
De stroomsensor ACS712 op A4 meet de stroom van de batterij (hoofdstuk 16), en het programma telt de lading op om de laadtoestand te kennen. Het meet eenmaal per seconde. Straks worden de groeilampen gedimd met PWM van 490,2 Hz en een duty cycle van 72 % (verder in dit hoofdstuk): de lampstroom springt 490 keer per seconde tussen 0 en 14,8 A. (a) Wat meet het programma? (b) Hoe groot is de gemiddelde stroom echt? (c) Hoe los je het op?
- PWM: ;
- lampen aan: ; één meting per seconde
- wat de metingen tonen
- het echte gemiddelde
- een betere meetmethode
- 1(a) Elke meting valt op een willekeurige plaats in een PWM-periode: ofwel 'aan' (14,8 A), ofwel 'uit' (0 A). Tussen twee metingen verlopen er 490,196 perioden. Het deel achter de komma, 0,196, schuift het meetpunt elke seconde 19,6 % van een periode op. De metingen vormen zo een schijnbaar signaal van 0,196 Hz: een patroon dat zich elke 5,1 s herhaalt.
- 2(b) Gemiddeld: . Eén meting is dus 4,1 A te veel of 10,7 A te weinig.
- 3(c) Meet niet één keer, maar een geheel aantal PWM-perioden lang en neem het gemiddelde: bijvoorbeeld 100 metingen in 20,4 ms, precies tien perioden (één
analogReadduurt 104 µs, dus kies 204 µs tussen twee metingen). Of filter de sensorspanning eerst met een RC-filter, zoals in de proef van dit hoofdstuk.
Van digitaal naar analoog: PWM
De Uno en de Mega hebben geen DAC (digitaal-analoogomzetter): een pin kan niet 2,5 V geven, alleen 0 of 5 V. Maar hij kan heel snel wisselen. Dat is pulsbreedtemodulatie (PWM): het signaal gaat met een vaste frequentie aan en uit, en je kiest welk deel van elke periode het aan is: de duty cycle .
Met analogWrite(pin, waarde) kies je de duty cycle in 256 stappen (8 bits): 0 is altijd uit, 255 altijd aan, en daartussen is . Niet elke pin kan het: alleen de pinnen met een tilde (~) op het bord, die aan een ingebouwde timer hangen.
| bord | PWM-pinnen | frequentie |
|---|---|---|
| Uno (meetkas) | 3, 5, 6, 9, 10, 11 | 490 Hz; pin 5 en 6: 980 Hz |
| Mega (klimaatmodule) | 2 tot 13 en 44 tot 46 | 490 Hz; pin 4 en 13: 980 Hz |
Die frequenties zijn afgerond: de klok van 16 MHz, gedeeld door 64 en door 510, geeft (periode 2,040 ms); op de pinnen met 980 Hz is het . Die snelle pinnen delen hun timer met millis() en geven een iets grotere duty cycle dan waarde/255.
Waarom werkt dat? Omdat wat je aanstuurt traag is tegenover 2 ms. Een led flikkert echt 490 keer per seconde, maar je oog middelt dat uit: het ziet het gemiddelde licht. Een motor heeft massa en een spoel: zijn toerental en zijn stroom volgen het gemiddelde (hoofdstuk 26). En een RC-filter maakt er een echte gelijkspanning van (de proef hierna).
Voor een weerstand die aan PWM hangt, is de gemiddelde spanning , maar het gemiddelde vermogen is niet . Tijdens de aan-tijd krijgt de weerstand de volle spanning en het volle vermogen , daarna niets: gemiddeld . Bij 50 % is dat de helft van het volle vermogen, niet een kwart. Hetzelfde voor leds met een voorschakelweerstand: vermogen en licht zijn evenredig met .
De ledstrip van de meetkas dimmen
De ledstrip van de meetkas (12 V, 0,40 A, 4,8 W) hangt nu aan relais K1 op D7: alleen aan of uit. Je vervangt het relais door een IRLZ44N op pin 9 van de Uno, die nog vrij is en PWM kan. (a) Welke waarde geef je aan analogWrite voor 30 % licht? (b) Hoe lang is de strip dan aan per periode? (c) Welk vermogen neemt de strip, en welke gemiddelde stroom trekt ze? (d) Hoeveel energie spaar je per winterdag (4 h licht, F17) als 30 % volstaat?
- ledstrip 12 V, 0,40 A; licht evenredig met de stroom
- Uno pin 9: 490,2 Hz,
- waarde
- vermogen en gemiddelde stroom
- energie per dag
- 1(a) : kies 77 ().
- 2(b) ; .
- 3(c) Tijdens de aan-tijd trekt de strip de volle 0,40 A (4,8 W), daarna niets. Gemiddeld: en .
- 4(d) Vol: ; gedimd: . Je spaart per winterdag, ongeveer een vijfde van het winterverbruik van de hele meetkas (62,9 Wh, F21).
analogWrite(9, 77): 0,62 ms aan per periode van 2,04 ms; 1,45 W en 0,12 A gemiddeld; 13,4 Wh minder per winterdag.Een PWM-signaal gladstrijken en meten
Wordt een PWM-signaal door een RC-filter echt een gelijkspanning van ? En hoeveel rimpel blijft er over?
- Arduino Uno
- weerstand 10 kΩ, elco 10 µF
- multimeter
- breadboard, draadjes
- eventueel een oscilloscoop
- 1Bouw het filter: pin 9 → 10 kΩ → knooppunt → 10 µF → GND. Het knooppunt gaat naar A0 en naar de voltmeter (DC).
- 2Schrijf een programma dat
analogWrite(9, waarde)geeft en daarna 200 keeranalogRead(A0)leest en het laagste en hoogste getal toont. - 3Meet voor de waarden 0, 64, 128, 191 en 255: de voltmeter en het laagste en hoogste A0-getal.
- 4Vergelijk met . Meet ook eens met de voltmeter rechtstreeks op pin 9, zonder filter.
| analogWrite | duty cycle | verwacht | voltmeter | A0 (laagste-hoogste) | rimpel |
|---|---|---|---|---|---|
| 0 | 0,0 % | 0,000 V | 0,00 V | 0-0 | geen |
| 64 | 25,1 % | 1,255 V | 1,25 V | 254-258 | 19 mV |
| 128 | 50,2 % | 2,510 V | 2,51 V | 511-516 | 26 mV |
| 191 | 74,9 % | 3,745 V | 3,75 V | 764-768 | 20 mV |
| 255 | 100,0 % | 5,000 V | 5,00 V | 1023-1023 | geen |
Voorbeeldmeting (berekend met het exacte RC-model). De voltmeter geeft netjes . A0 springt een paar stappen op en neer. Rechtstreeks op pin 9 toont de voltmeter bij waarde 128 ook ongeveer 2,5 V: een multimeter op DC middelt zelf al.
Het filter heeft , vijftig keer langer dan een PWM-periode (2,04 ms). Tijdens de aan-tijd laadt de condensator een beetje bij, tijdens de uit-tijd ontlaadt hij een beetje: gemiddeld blijft hij op hangen. Na ongeveer 5τ = 0,5 s is dat evenwicht bereikt. De rimpel is ongeveer : bij 25 % 19 mV, bij 50 % het grootst (ongeveer 26 mV, vijf ADC-stappen).
Zo maak je met PWM en een RC-filter een eenvoudige DAC. Een grotere τ geeft minder rimpel, maar een tragere reactie op een nieuwe waarde: dat is de afweging van elk filter (hoofdstuk E21).
PWM voor motoren en pompen
Ook een motor stuur je met PWM, via dezelfde MOSFET als in hoofdstuk 23. Tijdens de aan-tijd krijgt de motor de volle 12,8 V en neemt zijn stroom toe; tijdens de uit-tijd neemt de vrijloopdiode de stroom over en neemt ze langzaam af. De spoel van de motor houdt de stroom dus ongeveer constant, en de massa van de rotor houdt het toerental constant: de motor draait alsof hij de gemiddelde spanning kreeg. Zo regel je de pomp van de waterkringloop op D9 traploos, in plaats van 10 minuten per uur vol aan (hoofdstuk 23). Hoe toerental en spanning samenhangen, zie je in hoofdstuk 26.
Twee praktische punten:
- De vrijloopdiode moet snel zijn: bij PWM schakelt ze honderden keren per seconde. Daarom koos hoofdstuk 23 een Schottkydiode (1N5819).
- Een motor op 490 Hz zingt: de wikkelingen trillen mee en je hoort een toon van 490 Hz. Wie dat stoort, zet de timer op een frequentie boven het hoorbare (rond 31 kHz kan dat met een andere deler). Dan schakelt de MOSFET wel zestig keer vaker, en elke schakeling kost een beetje energie (volgend blad).
PWM werkt voor lasten die traag reageren (lampen voor het oog, motoren, verwarming). Een toestel met eigen elektronica, zoals de 5 V-omvormer of een wifi-module, wil een gewone gelijkspanning: 490 keer per seconde aan en uit laat het telkens opnieuw opstarten.

Habitat: de groeilampen traploos dimmen
In hoofdstuk 22 gingen de groeilampen aan onder 4000 lux en uit boven 6000 lux daglicht. Nu wil je dat het kweekbed tijdens de lichtperiode (16 uur) altijd 200 µmol/(m²·s) krijgt: daglicht plus lamplicht. De twee lampen samen geven op 100 % precies 200 (hoofdstuk 22). Ze hangen via één IRLZ44N op een koelplaat (hoofdstuk 23) aan een PWM-pin van de Mega. (a) Kies de pin. (b) Welke PWM-waarde hoort bij 3000 lux daglicht? (c) Hoeveel vermogen nemen de lampen dan, en hoeveel verliest de MOSFET? (d) Hoe warm wordt hij?
- lampen: 190 W, 14,8 A op 12,8 V; ; MOSFET + koelplaat
- zonlicht: 54 lux per µmol/(m²·s); schakeltijd per flank ±3 µs
- vrije PWM-pinnen: D3-D8, D12, D13, D44-D46
- pin
- PWM-waarde
- vermogen lampen en verlies MOSFET
- opwarming
- 1(a) D5: 490 Hz (timer 3), met . D4 en D13 geven 980 Hz en een iets afwijkende duty cycle; D44-D46 verliezen hun PWM als er ooit een servo bij komt (de servobibliotheek gebruikt op de Mega eerst timer 5); D6-D8 houden we vrij voor de dakmotor (hoofdstuk 26).
- 2(b) Daglicht: µmol. Tekort: , dus en de waarde . (Het programma leest via de LDR , rekent dat terug naar 2983 lux en komt op 185: één stap meer, door het afronden van de ADC.)
- 3(c) Lampen: . Geleiding in de MOSFET: tijdens de aan-tijd , gemiddeld .
- 4Schakelen: bij elke flank staan even spanning én stroom over de MOSFET: ongeveer , twee flanken per periode, 490 keer per seconde: . Samen .
- 5(d) boven de omgeving; op 100 % (geen schakelen) .
analogWrite(5, 184) bij 3000 lux. De lampen nemen 137 W; de MOSFET verliest ongeveer 4,3 W en wordt 30 °C warmer dan de omgeving (op 100 %: 39 °C).Habitat: een bewolkte lentedag, aan/uit tegenover gedimd
Wat levert dimmen op? Neem een bewolkte lentedag: de zon komt op om 6.30 u en gaat onder om 19.30 u, met hoogstens 8000 lux daglicht op het kweekbed. De lichtperiode loopt van 6 tot 22 u.
- Aan/uit (hoofdstuk 22): de lampen gaan uit om 10.01 u (boven 6000 lux) en weer aan om 17.20 u (onder 4000 lux). Ze verbruiken 1650 Wh. Het kweekbed krijgt tot 311 µmol als de lampen net nog aan zijn, en maar 111 als ze net uit zijn: een zaagtand.
- Gedimd: de lampen vullen precies aan tot 200. Ze verbruiken 1875 Wh, en het kweekbed krijgt de hele dag 200 µmol: 11,5 mol per m² over de dag, tegenover 10,7 met aan/uit.
- Altijd vol zou 3040 Wh kosten.
Dimmen spaart dus 38 % tegenover altijd vol aan. Op deze dag verbruikt het wel 225 Wh meer dan aan/uit, omdat aan/uit de planten tussen 10.01 en 17.20 u te weinig licht gaf. Op een zonnige dag (meer dan 10 800 lux) zijn de lampen gedimd ook uit. Het energiebeheer van hoofdstuk 20 wordt met PWM ook zachter: in plaats van de lampen uit te schakelen als de batterij laag staat, kan het de lampen op halve kracht zetten.
C++: de groeilampen dimmen
Het programma leest vijf keer per seconde de LDR, rekent het daglicht om naar µmol (hoofdstuk 22), berekent hoeveel de lampen moeten bijgeven en stuurt de PWM-waarde. Het regelt zacht bij: hoogstens één stap per 200 ms. Een wolk die even voor de zon schuift, laat de lampen dus niet meteen aanspringen, en je ziet nooit een sprong in het licht. Zonder echte klok (die komt in hoofdstuk 30) neemt het aan dat het om 6 u gestart is.
// groeilampen.ino - de groeilampen van de klimaatmodule dimmen met PWM (Arduino Mega)// Daglicht: LDR onder een kapje op A1, 1,0 kOhm naar GND (hoofdstuk 22). Lampen: IRLZ44N op D5 (490 Hz).const int LDR = A1;const int LAMPEN = 5;const float R_VAST = 1000.0; // ohmconst float KAPJE = 0.10; // het kapje laat 10 % doorconst float DOEL = 200.0; // umol/(m2 s) op het kweekbed: daglicht + lampen samenconst float LAMPEN_VOL = 200.0; // wat de twee lampen op 100 % gevenconst float LUX_PER_UMOL = 54.0; // zonlichtconst unsigned long DAG_MS = 24UL * 3600UL * 1000UL; int stand = 0; // huidige PWM-waarde, 0 tot 255unsigned long vorige = 0; float daglichtLux() { int n = analogRead(LDR); if (n < 1) n = 1; // niet delen door nul in het donker float r = R_VAST * (1024.0 - n) / n; // weerstand van de LDR (spanningsdeler omgekeerd) float eLdr = 10.0 * pow(r / 15000.0, -1.0 / 0.7); // lux op de LDR (model uit hoofdstuk 22) return eLdr / KAPJE; // lux daglicht} int uurVanDeDag() { // eenvoudige klok: het programma start om 6 uur (echte klok: hoofdstuk 30) return (6 + (millis() % DAG_MS) / 3600000UL) % 24;} void setup() { pinMode(LAMPEN, OUTPUT); analogWrite(LAMPEN, 0); Serial.begin(9600);} void loop() { unsigned long nu = millis(); if (nu - vorige < 200) return; // vijf keer per seconde bijregelen vorige = nu; int doelStand = 0; int uur = uurVanDeDag(); if (uur >= 6 && uur < 22) { // lichtperiode van 16 uur float dag = daglichtLux() / LUX_PER_UMOL; // daglicht in umol/(m2 s) float f = constrain((DOEL - dag) / LAMPEN_VOL, 0.0, 1.0); doelStand = (int)(f * 255 + 0.5); } // zacht bijregelen: hoogstens 1 stap per 200 ms (van 0 naar 255 in 51 s) if (doelStand > stand) stand++; else if (doelStand < stand) stand--; analogWrite(LAMPEN, stand); if (nu % 60000UL < 200) { // eens per minuut melden Serial.print("uur "); Serial.print(uur); Serial.print(", PWM "); Serial.println(stand); }}Een test tegen een gesimuleerde dag geeft bij 3000 lux daglicht de waarde 185: de ADC rondt de LDR-spanning af, zodat het programma 2983 lux ziet (voorbeeld hierboven: 184). In het donker loopt de waarde in 51 s op van 0 naar 255. constrain houdt de fractie tussen 0 en 1: bij meer dan 10 800 lux zou ze negatief worden. De energiebeheerregels van hoofdstuk 20 voeg je toe in opdracht 25.13.
Python: bits, ADC en aliasing narekenen
Drie kleine functies vatten het hoofdstuk samen: omzetten naar binair door te delen door 2, een ADC die naar beneden afrondt en nooit boven 1023 gaat, en de schijnbare frequentie na bemonsteren.
# bits.py - binair, hexadecimaal, de ADC en bemonsteren in een paar functies def naar_binair(getal, bits=8): """Deel telkens door 2: de resten zijn de bits, van achter naar voor.""" resten = [] for _ in range(bits): resten.append(getal % 2) getal = getal // 2 return "".join(str(b) for b in reversed(resten)) def adc(u, u_ref=5.0, bits=10): """Zoals de ADC: 2**bits niveaus, naar beneden afgerond, nooit meer dan het hoogste niveau.""" return min(int(u / u_ref * 2 ** bits), 2 ** bits - 1) def schijnbaar(f, fs): """Schijnbare frequentie na bemonsteren met fs: de afstand tot het dichtste veelvoud van fs.""" k = round(f / fs) return abs(f - k * fs) for g in (5, 182, 200, 255): print(f"{g:4d} = {naar_binair(g)} = 0x{g:02X}")print(f"1023 = {naar_binair(1023, 10)} = 0x{1023:X}") for u in (0.75, 1.25, 3.20, 4.999, 6.0): n = adc(u) print(f"U = {u:5.3f} V -> N = {n:4d} = {naar_binair(n, 10)}") for f in (0.2, 9.0, 11.0, 50.0): print(f"{f:4.1f} Hz, 10 keer per seconde gemeten: lijkt {schijnbaar(f, 10.0):.1f} Hz")Uitvoer (gedraaid bij het bouwen van deze pagina):
5 = 00000101 = 0x05 182 = 10110110 = 0xB6 200 = 11001000 = 0xC8 255 = 11111111 = 0xFF 1023 = 1111111111 = 0x3FF U = 0.750 V -> N = 153 = 0010011001 U = 1.250 V -> N = 256 = 0100000000 U = 3.200 V -> N = 655 = 1010001111 U = 4.999 V -> N = 1023 = 1111111111 U = 6.000 V -> N = 1023 = 1111111111 0.2 Hz, 10 keer per seconde gemeten: lijkt 0.2 Hz 9.0 Hz, 10 keer per seconde gemeten: lijkt 1.0 Hz 11.0 Hz, 10 keer per seconde gemeten: lijkt 1.0 Hz 50.0 Hz, 10 keer per seconde gemeten: lijkt 0.0 Hz
Let op 6,0 V: dat is meer dan de referentie, en de ADC blijft op 1023 staan (in het echt mag een pin nooit boven 5 V komen). En 50 Hz, gemeten met 10 Hz, lijkt 0 Hz: een constante. Wie de netbrom meet met een veelvoud van 50 Hz, ziet ze niet.
Overzicht: van analoog naar digitaal en terug
| symbool | betekenis | eenheid |
|---|---|---|
| aantal bits | – |
| symbool | betekenis | eenheid |
|---|---|---|
| ADC-waarde | – | |
| referentiespanning (5 V, 1,1 V …) | V |
| symbool | betekenis | eenheid |
|---|---|---|
| 10 bit, 5 V: 4,88 mV | V |
| symbool | betekenis | eenheid |
|---|---|---|
| bemonsteringsfrequentie | Hz | |
| snelste verandering in het signaal | Hz |
| symbool | betekenis | eenheid |
|---|---|---|
| duty cycle | – | |
| periode (490 Hz: 2,04 ms) | s |
| bits | 1 | 2 | 3 | 4 | 8 | 10 | 12 | 16 |
|---|---|---|---|---|---|---|---|---|
| niveaus | 2 | 4 | 8 | 16 | 256 | 1024 | 4096 | 65 536 |
| grootste getal | 1 | 3 | 7 | 15 | 255 | 1023 | 4095 | 65 535 |
| decimaal | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| binair | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
| hex | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
| bord | PWM-pinnen | frequentie |
|---|---|---|
| Uno (meetkas) | 3, 5, 6, 9, 10, 11 | 490 Hz; pin 5 en 6: 980 Hz |
| Mega (klimaatmodule) | 2 tot 13 en 44 tot 46 | 490 Hz; pin 4 en 13: 980 Hz |
| Arduino | bereik | betekenis |
|---|---|---|
analogRead(A0) | 0-1023 | 10 bit; 104 µs per meting |
analogReference(INTERNAL) | Uno: referentie ±1,1 V (Mega: INTERNAL1V1, INTERNAL2V56) | |
analogWrite(9, v) | 0-255 | 8 bit PWM, op de 490 Hz-pinnen |
int / unsigned long | 16 / 32 bit | −32 768 tot 32 767 / 0 tot 4 294 967 295 |
Waar analoog en digitaal elkaar raken
Dit hoofdstuk is de brug tussen de elektronica (spanningen, stromen, transistors) en het programmeren (getallen, bits, lussen). Het verbindt ook de wiskunde: machten van 2, afronden, en de periode en frequentie van een signaal, die in Expert terugkomen als sinussen en Fourier.
Digitale pinnen: hoog of laag.
analogRead en de eerste sensoren; de TMP36 van de meetkas.
Resolutie is niet hetzelfde als nauwkeurigheid.
De ADC-omrekening en de LDR die hier de lampen stuurt.
De MOSFET die met PWM schakelt, en de snelle vrijloopdiode.
Het RC-filter dat PWM gladstrijkt, en de sample-and-hold-condensator.
PWM voor het toerental van een motor; servo's met pulsen van 1 tot 2 ms.
analogRead, analogWrite, int en unsigned long in C++.
Hoeveel data de logger maakt, en hoe vaak hij meet.
Nyquist en aliasing precies; frequenties in een signaal.
Bits worden poorten, flipflops en tellers.
PWM op hoge frequentie in omzetters en motorsturingen.
In het kort
- Een digitaal signaal is bemonsterd in de tijd en afgerond op een eindig aantal niveaus.
- Binair: elke plaats is twee keer zoveel waard. Met bits heb je waarden; een byte (8 bits) gaat van 0 tot 255. Eén hexadecimaal cijfer is vier bits.
- Een ADC van 10 bit deelt 0 tot in 1024 stappen: bij 5 V 4,88 mV. Resolutie is geen nauwkeurigheid. Hij vindt zijn getal met tien ja-neevragen.
- Meet meer dan twee keer per periode van de snelste verandering (Nyquist), liefst veel vaker; anders ontstaat aliasing: een snel signaal lijkt traag.
- PWM: een pin die snel aan en uit gaat. De duty cycle bepaalt de gemiddelde spanning en het gemiddelde vermogen .
- analogWrite geeft 256 standen; op de meeste pinnen 490 Hz. Achter een MOSFET dim je zo lampen en regel je motoren; een RC-filter maakt er een gelijkspanning van.
Wat je nu kent
- bit
- Kleinste eenheid van informatie: 0 of 1. Met bits schrijf je verschillende waarden.
- byte
- Groep van 8 bits: 256 waarden, van 0 tot 255.
- binair talstelsel
- Talstelsel met grondtal 2: elke plaats is twee keer zoveel waard als de plaats rechts ervan.
- hexadecimaal
- Talstelsel met grondtal 16 (cijfers 0-9 en A-F); één hexadecimaal cijfer is vier bits.
- resolutie (van een ADC)
- De kleinste spanningsverandering die een ADC kan onderscheiden: , bij 10 bit en 5 V 4,88 mV.
- bemonsteringsfrequentie
- Hoeveel metingen per seconde een digitaal systeem van een signaal neemt.
- aliasing
- Een signaal dat te traag bemonsterd wordt, lijkt een ander, trager signaal.
- PWM
- Pulsbreedtemodulatie: een digitale uitgang die snel aan en uit gaat, zodat het gemiddelde tussen 0 en de volle spanning ligt.
- duty cycle
- Het deel van de periode waarin een PWM-signaal hoog is, in procent.
- DAC
- Digitaal-analoogomzetter: maakt van een getal een spanning.