Arduino/Analoge uitvoer-PWM
PWM: pulsbreedte-modulatie
De Arduino heeft geen echte analoge uitgang, in de vorm van een Analoog/Digitaal omzetter. Als alternatief daarvoor kun je een digitale waarde omzetten in een PWM-signaal (pulse width modulation, pulsbreedtemodulatie). Het resultaat is een periodiek digitaal signaal waarvan de duty-cycle evenredig is met de digitale waarde. Dit kun je eventueel eenvoudig omzetten in een analoog niveau, of een erg laagfrequent analoog signaal.
Pulsbreedte-modulatie
Je kun een digitale uitgang aan- en uitzetten: dit komt dan overeen met een spanning van 5V of 0V. Als je dit met een vaste regelmaat doet, krijg je een periodiek signaal. Een voorbeeld daarvan is het knipperen van de LED, zoals we gezien hebben in de Blink-sketch:
void loop () {
digitalWrite(ledPin, HIGH); // Led on
delay(1000); // wait 1000 msec
digitalWrite(ledPin, LOW); // Led off
delay(1000); // wait 1000 msec
}
Het overeenkomstige signaal zien we in de figuur hiernaast. Dit is een blokgolf met een periode van 2000 msec, wat overeenkomt met een frequentie van 0,5 Hz (een halve periode per seconde). We kunnen deze blokgolf, en daarmee het knipperen van de LED, op twee manieren aanpassen:
- we kunnen de periode, dat wil zeggen de combinatie van de aan- en uit-periode, veranderen;
- als we beide delay's veranderen in 100 msec, hebben we een frequentie van 5Hz.
- we kunnen de verhouding tussen de aan- en uitperiode veranderen.
De dutycycle van een dergelijk signaal is de verhouding tussen de aan-periode en de totale periode. Deze verhouding drukken we meestal uit als percentage. In het voorbeeld hierboven is de dutycycle 50%.
- als we de LED 150 msec aanzetten, en 50 msec uit, dan is de dutycycle 75% (de totale periode is 200 msec, de frquentie is 5 Hz).
- als we de LED 50 msec aanzetten, en 150 msec uit, dan is de dutycycle 25% (de frequentie is 5 Hz).
Van PWM naar analoog niveau
We kunnen een dergelijk pulsbreedte-signaal omzetten in een analoog niveau, door het gemiddelde te nemen van dit signaal over een langere periode.
- als we de LED voldoende snel laten knipperen, dan verzorgt ons oog automatische deze middeling. Het lichtniveau dat we waarnemen is dan evenredig met de dutycycle van het signaal. Dit is het principe van vrijwel alle licht-dimmers.
- soms helpt een bepaald "traag" natuurkundig verschijnsel hierbij. Een voorbeeld is een gloeilamp: deze heeft tijd nodig om aan- en uit te schakelen. Dit betekent dat je een gloeilamp bij een frequentie van 50Hz niet meer ziet knipperen.
- in andere gevallen kunnen we een zogenaamd laagdoorlaatfilter gebruiken, bijvoorbeeld in de vorm van een weerstand en een condensator.
Je kunt dit vergelijken met een vijver met een vaste afvoer waarin regenwater opgevangen wordt: de vijver vangt de pieken door de regenbuien op, en voert een veel constantere stroom water af naar de benedenloop. Een ander voorbeeld van een laagdoorlaatfilter is een schokdemper: de snelle schokken worden gedempt door een combinatie van een buffer (veer) en een weerstand (vloeistof-weerstand).
- http://arduino.cc/en/Tutorial/PWM
- http://jeelabs.org/2013/06/30/from-pwm-to-voltage/
- http://provideyourown.com/2011/analogwrite-convert-pwm-to-voltage/
Analoge uitvoer: PWM
We kunnen in een Arduino-sketch aangeven dat we een pin als analoge uitvoer willen gebruiken. Dit betekent dat deze uitgang een PWM-signaal met een bepaalde frequentie en een bepaalde duty-cycle te zien geeft. De (byte-)waarde die we wegschrijven naar deze pin geeft de duty-cycle aan: 0 staat voor 0%, 255 staat voor 100%.. De frequentie van dit PWM-signaal kunnen we ook instellen, door het programmeren van de timers. (Dit bespreken we verderop.)
Deze analoge uitvoer is (voor de Arduino Uno) beschikbaar op de pinnen 3, 5, 6, 9, 10, en 11. De frequentie van het PWM-signaal is ongeveer 490 Hz. De werkelijke duty-cycle van de pinnen 5 en 6 is iets groter dan de opgegeven waarde, doordat dezelfde timer gebruikt wordt voor de delay
en millis
-functies.
Setup
pinMode(analogLedPin, OUTPUT);
(Ik begrijp dat dit niet strikt nodig is.)
Besturing (loop)
analogWrite(analogLedPin, level);
Voorbeeld: dimmer
Dit voorbeeld-programma is een dimmer waarbij het niveau ingesteld wordt door een spanning op pin XX, door middel van een potmeter (variabele weerstand). Dit niveau wordt uitgelezen, en omgezet in een waarde voor de duty-cycle van een LED. De waarde die van de analoge ingang gelezen wordt ligt tussen 0 en 1023; de waarde voor de analoge uitgang moet liggen tussen 0 en 255. Dit bereiken we door de ingelezen waarde door 4 te delen.
N.B. we kunnen de PWM-dimmer in software realiseren, zonder de PWM-hardwareondersteuning van de Atmega.
const ledPin = 9; // LED connected to digital pin 9
const inputPin = 3; // potentiometer connected to analog pin 3
void setup () {
pinMode(inputPin, INPUT);
pinMode(ledPin, OUTPUT);
}
void loop () {
int inLevel;
inLevel = analogRead(inputPin);
analogWrite(ledPin, inLevel / 4);
}