LED dimmer met drukknop
Het programma
Het volgende programma maakt dat Arduino met een drukknopje een LEDje aan en uit te zetten en ook kan dimmen, zowel feller als zachter.
int btnpin=4; // de knop zit aan pin 4
int ledpin=6; // het LEDje zit aan pin 6 (een pin met PWM mogelijkheden)
int dimstand=255; // huidige stand van de dimmer
bool dimUp=false; // geeft aan of de dimrichting "up" is
int ledAan=0; // geeft aan of de LED aan of uit is
void setup()
{
pinMode(ledpin,OUTPUT); // maak de ledpin OUTPUT
pinMode(btnpin,INPUT); // maak de btnpin INPUT
Serial.begin(9600); // deze hebben we nodig om te zien hoe het werkt
}
bool isPressed(int timeframe)
// deze functie bepaald of het knopje is ingedrukt binnen het timeframe
// daarbij mag het knopje best wat storen => tussendoor niet ingedrukt lijken
{
bool result = false;
unsigned long t=millis();
do
if (digitalRead(btnpin)) result = true;
while (t+timeframe>millis()); // wacht tot timeframe voorbij is sinds t
return result;
}
void loop()
{
// als de knop kort wordt ingedrukt wordt de lamp omgezet aan=>uit en uit=>aan
// als de knop langer dan een halve seconde wordt ingedrukt gaat de lamp dimmen
// als de dimrichting "up" is wordt steeds meer licht gegeven, anders steeds minder
// als de dimstand o of 255 bereikt draait de dimrichting om
if (digitalRead(btnpin)) // de knop is ingedrukt
{
// test of knopje lang (>500ms) of kort wordt ingedrukt
bool pressed;
unsigned long start=millis(); // start van de test: het aantal milliseconden na de start van het programma
do
pressed = isPressed(20); // speciale "debaouncing" functie
while (pressed and (start+500>millis()));
if (pressed) // in dat geval is het knopje elke 20ms van de 500ms ingedrukt geweest => lang ingedrukt => ga dimmen
{ // => lang ingedrukt => ga dimmen
Serial.print("lang: ");
Serial.print(dimstand,DEC);
Serial.print(" - ");
// ga dimmen; elke 20 ms een stapje
while (isPressed(20))
{
if (dimUp)
{
dimstand++;
if (dimstand==255) dimUp=false;
}
else
{
dimstand--;
if (dimstand==0) dimUp=true;
}
analogWrite(ledpin,dimstand); // stuur een PWM signaal (waarde tussen 0 en 255: 1024/4=256) naar de LED
}
ledAan=1; // hij is nu aan
Serial.println(dimstand,DEC);
}
else // knopje is kort ingedrukt geweest
{
Serial.print("kort: ");
if (ledAan==0)
{
ledAan=dimstand;
}
else
{
ledAan=0;
}
Serial.println(ledAan);
analogWrite(ledpin,ledAan); // doe LED uit of aan op huidige dimstand
}
}
}
Uitleg
Er worden meerdere variabelen gedefinieerd. Uiteraard de variabelen van de pins die worden gebruikt voor het aansluiten van het LEDje en het knopje. Daarnaast is er een variabele die de dimstand onthoudt, een die onthoudt of de dimrichting naar boven is (anders is hij naar beneden) en een die onthoudt of het LEDje aan is of uit. De setup() functie is erg eenvoudig en stelt slects de pin-modi in voor beide pins en start de seriele communicatie.
Dan is er de isPressed(int timeframe) functie die een boolean resultaat teruggeeft. Deze functie test of het knopje, gedurende het timeframe, tenminste even is ingedrukt. Een probleem van dit type knopjes is dat ze bouncen. Dat betekent dat ze niet continu ingedrukt lijken te zijn maar in plaats daarvan wat ruisachtig ja/nee geven. Als je dus op een normale wijze zou testen, zou je maar zelden vinden dat het knopje gedurende 500 ms is ingedrukt. Steeds komen er korte momentjes tussendoor waarop het knopje toch niet is ingedrukt. Bedenk dat zo'n Arduino behoorlijk snel is en dergelijke momentjes er ook tussendoor zal hebbben. Dit kan hardwarematig worden opgelost met wat extra componenten, maar het kan ook softwarematig, bijvoorbeeld met deze isPressed() functie. Als je de functie bekijkt zie je hoe het werkt. De variabele pressed wordt op false ingesteld. Dan wordt de tijd uitgelezen en komt het programma gedurende het timeframe in een loop. Als het knopje ook maar even is ingedrukt gedurende dit timeframe is het resultaat true: de knop is minimaal even ingedrukt geweest (en waarschijnlijk een groot deel van de tijd).
De loop() kijkt eerts of het knopje is ingedrukt. Als dat zo is begint het. Als eerste wordt met een variabele start de begintijd van het proces vastgelegd. Daarna kijkt de functie gedurende 500 ms of het knopje steeds ingedrukt blijft. Daarvoor roept het steeds de functie isPressed() aan. Als ergens binnen die 500ms het knopje wordt losgelaten, wordt de variabele pressed false en springt het programma meteen uit de do-while loop. Er staat immers:
do
pressed = isPressed(20); // speciale "debaouncing" functie
while (pressed and (start+500>millis()));
Als het knopje steeds ingedrukt blijft, is pressed na de do-while loop true. Hij springt dan namelijk vanwege de tijd uit de loop.
Als pressed true is, wordt het knopje lang ingedrukt en gaan we dimmen, anders gaan we het lampje aan of juist uit zetten. Het dimmen gaat door zolang het knopje ingedrukt blijft. Dit is de while (isPressed()) loop:
while (isPressed(20))
{
}