Het project ligt even een beetje stil, maar ik heb in de tussentijd wel een kleine uitbreiding gemaakt zodat je ‘s nachts niet wordt verblind door een zee aan licht, maar dat je tegelijk overdag de klok ook nog kan aflezen.

Met een fotodiode meet ik het omgevingslicht en dankzij de in de Arduino ingebouwde analoog-digitaalomzetter is het weer een poepsimpel circuitje geworden:

Schakeling voor lichtsensor

De analoge poort A0 lees je eenvoudig uit met de functie analogRead(A0). De waarde uit de analoge poort wordt omgezet naar een 10-bit integer, dus tussen 0 en 1024. Omdat setBrightness een waarde tussen 0 en 255 wil, delen we die door 4 en om te voorkomen dat het licht helemaal uitgaat in het donker zetten we er een minimum op.

void updateBrightness()
{
  int brightnessReading = analogRead(A0) / 4;
  pixels.setBrightness(max(brightnessReading, 1));
}

Dit kan echter — zoals bij veel regelsystemen — leiden tot hysterese, waarbij het licht feller gaat branden omdat het licht wegvalt, maar doordat het licht feller gaat branden het weer lichter wordt en de helderheid bij de volgende keer dat de sensor wordt uitgelezen weer naar beneden wordt bijgesteld, waarna het hele circus opnieuw begint. Dit kunnen we voorkomen door de helderheid afhankelijk te maken van een langere periode.

Hieronder slaan we de ingelezen waarde tijdelijk op in een circulaire buffer van lengte 10, om vervolgens het gemiddelde aan setBrightness te voeren. Het voordeel in het gebruik van zo’n type buffer is dat je waardes erin kan blijven duwen (push()) en als hij vol is valt de oudste waarde eruit. Omdat ik een lopend gemiddelde wil bepalen, haal ik die oudste waarde er zelf uit (shift()) en trek die van het gemiddelde af.

#include <CircularBuffer.h>

CircularBuffer<int, 10> brightnessReadings;
int brightnessAverage = 0;

void updateBrightness()
{
  int brightnessReading = analogRead(A0) / 4;
  brightnessAverage += brightnessReading;

  if (brightnessReadings.isFull()) {
    brightnessAverage -= brightnessReadings.shift();
  }

  brightnessReadings.push(brightnessReading);

  pixels.setBrightness(max(brightnessAverage / brightnessReadings.size(), 1));
}

De waarde die uiteindelijk naar setBrightness gaat is het gemiddelde van de 10 laatste waarden. Een plotse verandering in helderheid wordt daardoor uitgesmeerd over 100 milliseconden (de loop() functie heeft een delay(10) die ervoor zorgt dat die aan het eind van elk rondje 10 milliseconden wacht) en hysterese wordt voorkomen.