Een 7-segmentklok bouwen met Arduino Nano, DS3231 RTC en LDR-automatische helderheid
Onderdelen en benodigdheden
| Onderdeel | Aantal | Opmerking |
|---|---|---|
| Arduino Nano R3 | 1 | Werkt ook met Arduino Uno of Elegoo Uno |
| Adafruit 7-Segment Backpack - 1,2" hoge cijfers | 1 | Optioneel als je de bundle koopt |
| Adafruit 1,2" 4-Digit 7-Segment Display met I2C Backpack - Groen | 1 | |
| Adafruit DS3231 RTC | 1 | Of DS1307 (minder nauwkeurig, geen temperatuur) |
| Weerstand 100k ohm | 1 | Voor LDR |
| Fotoweerstand (LDR) | 1 | |
| Breadboard | 1 | |
| Draadjes (jumper wires) | 10-14 stuks | |
| Knopcelbatterij CR1220 | 1 | Voor RTC-backup |
Apps en online diensten
- Arduino IDE
Over dit project
Inleiding
In een tijd waarin je altijd een klok op je pols hebt (horloge of smartphone), lijkt een Arduino-klok misschien saai. Maar dit project biedt een zelfstandige klok zonder internetverbinding – ideaal voor een slaapkamer waar geen WiFi gewenst is.
Keuze van de RTC
Er zijn veel RTC-modules beschikbaar. De keuze viel op de DS3231 (nauwkeuriger, met ingebouwde temperatuursensor) en de goedkoper DS1307. Beide werken met deze code; voor de DS1307 moet je de temperatuurweergave uitschakelen (commentarieer displayTemp() in de loop).
Aanpassing van de sketch
De oorspronkelijke code is herstrukturiseerd en uitgebreid met Engelse commentaren. Het grote 7-segmentdisplay toont tijd en temperatuur afwisselend. De helderheid past zich automatisch aan aan de omgevingslichtsterkte via de LDR. Ook is zomer-/wintertijdomschakeling geïmplementeerd.
Initialiseren van de klok
Met een CR1220-batterij kun je de RTC instellen via de korte Adafruit-tutorial. De tijd wordt niet via internet gesynchroniseerd, maar via de lokale PC-tijd bij het uploaden van de sketch.
Functies
- Tijd- en temperatuurweergave: Wisselinterval instelbaar via variabelen.
- Knipperende punten: De linker puntjes knipperen met de seconden (boven/onder).
- Zomer-/wintertijd: Automatische omschakeling op de laatste zondag van maart en oktober.
- Automatische helderheid: LDR meet omgevingslicht; display dimt 's nachts.
- Foutafhandeling: Bij communicatiefout met DS3231 verschijnt "bEEF" op het display.
Uitbreiding
Toekomstige uitbreidingen: alarmfunctie, Bluetooth/Blynk-besturing. De printplaatversie (v1.1) is voltooid en getest.
Code
MyClock v1.0 (C/C++)
// MyClock v1.0
// Ingo Lohs
// Hardware: getest met Arduino Uno en Nano (ATmega328P [Old Bootloader]) via Arduino IDE v1.8.8
#include <Wire.h>
#include <Adafruit_GFX.h>
#include "Adafruit_LEDBackpack.h"
#define DS3231_I2C_ADDRESS 0x68
int ldr_sensor = A0;
int ldr_value = 0;
int brightness_matrix;
int threshold_brightness = 400;
int blinkrate_value = 0;
int delay_matrix_time = 20;
int delay_matrix_temp = 2000;
int blinky_dot = 2;
Adafruit_7segment matrix = Adafruit_7segment();
byte decToBcd(byte val) { return ((val/10*16) + (val%10)); }
byte bcdToDec(byte val) { return ((val/16*10) + (val%16)); }
void setup() {
Serial.begin(9600);
Wire.begin();
matrix.begin(0x70);
}
void loop() {
lightBrightness();
matrixBlinkrate();
displayTime();
displayTemp();
}
void lightBrightness() {
ldr_value = analogRead(ldr_sensor);
Serial.print("LDR: "); Serial.println(ldr_value);
if (ldr_value <= threshold_brightness) {
brightness_matrix = 0; // helder bij daglicht
} else {
brightness_matrix = 15; // dim in het donker
}
}
void matrixBlinkrate() {
matrix.blinkRate(blinkrate_value);
}
void displayTime() {
matrix.setBrightness(brightness_matrix);
matrix.clear();
for (uint16_t i = 0; i < delay_matrix_time; i++) {
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
getDateDs3231(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
byte se = second, mi = minute, ho = hour, we = dayOfWeek, dm = dayOfMonth, mo = month, ye = year;
// Zomertijd: laatste zondag maart om 02:00
if ((dayOfWeek == 7) && (dayOfMonth >= 25) && (month == 3) && (hour == 2)) {
setDS3231time(se, mi, 3, we, dm, mo, ye);
}
// Wintertijd: laatste zondag oktober
if ((dayOfWeek == 7) && (dayOfMonth >= 25) && (month == 10) && (hour == 1) && (year != 1)) {
setDS3231time(se, mi, ho, we, dm, mo, 1);
}
if ((dayOfWeek == 7) && (dayOfMonth >= 25) && (month == 10) && (hour == 3) && (year == 1)) {
setDS3231time(se, mi, 2, we, dm, mo, 0);
}
// Uren weergeven
if (hour > 9) {
matrix.writeDigitNum(0, (hour / 10), false);
matrix.writeDigitNum(1, (hour % 10), false);
} else {
matrix.writeDigitNum(1, hour, false);
}
// Knipperende linker puntjes
if (se <= 30) blinky_dot = 10; // onder + dubbele punt
else if (se > 30) blinky_dot = 6; // boven + dubbele punt
matrix.writeDigitRaw(2, blinky_dot);
// Minuten
matrix.writeDigitNum(3, (minute / 10), false);
matrix.writeDigitNum(4, (minute % 10), false);
matrix.writeDisplay();
// Dubbele punt knippert per halve seconde
delay(500);
matrix.drawColon(false);
matrix.writeDisplay();
delay(500);
}
}
void displayTemp() {
matrix.setBrightness(brightness_matrix);
matrix.clear();
byte temp = get3231Temp();
int abs_temp = abs(temp);
matrix.writeDigitNum(1, (abs_temp % 10), false);
if (temp < 0) matrix.writeDigitRaw(0, 64); // minteken
if (temp <= -10) matrix.writeDigitRaw(2, 12);
if (temp >= 10) matrix.writeDigitNum(0, (abs_temp/10), false);
if (temp <= -10) matrix.writeDigitNum(0, (abs_temp/10), false);
matrix.writeDigitRaw(3, 99); // °
matrix.writeDigitRaw(4, 57); // C
matrix.writeDisplay();
Serial.print("Temperatuur in C: "); Serial.println(get3231Temp());
delay(delay_matrix_temp);
}
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte dayOfMonth, byte month, byte year) {
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0);
Wire.write(decToBcd(second));
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.write(decToBcd(dayOfWeek));
Wire.write(decToBcd(dayOfMonth));
Wire.write(decToBcd(month));
Wire.write(decToBcd(year));
Wire.endTransmission();
}
void getDateDs3231(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) {
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
}
float get3231Temp() {
byte tMSB, tLSB;
float temp3231;
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0x11);
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
if (Wire.available()) {
tMSB = Wire.read();
tLSB = Wire.read();
temp3231 = (tMSB & B01111111);
temp3231 += ((tLSB >> 6) * 0.25);
return temp3231;
} else {
Serial.println("DS3231 Sensor Error - cant read temperature");
matrix.print(0xBEEF, HEX);
matrix.writeDisplay();
delay(5000);
}
}
MyClock v1.1 (C/C++)
Update: correctie zomer-/wintertijdlogica (dag van week 1 = zondag ipv 7). Volledige code op GitHub.
Schema

Productieproces
- Arduino POV-klok: Bouw een Persistence-of-Vision LED-display
- Bouw een retro Numitron-klok met Arduino: Eenvoudig, betrouwbaar en energiezuinig
- Een stijlvolle wandklok bouwen met Adafruit 60-LED Neopixel Ring & Arduino
- Bouw een Arduino Real-Time Clock voor Islamitische Gebedstijden
- Bouw een Aangepaste LED Hoofdklok met Alarm – Zichtbaar vanaf 12 Meter
- Arduino Temperatuurbewaking & Realtime Klok met 3.2" TFT-display
- Twee Stappenmotors Sturen met Arduino Nano & Joystick – Simpele Tutorial
- DIY Arduino Smartwatch: Bouw Je Eigen Apple Watch-stijl Tijdwijzer
- Bouw een Precieze 7-Segment Klok met Arduino Pro Mini & DS1302 RTC
- Bouw een handgehoude Geiger-teller met Arduino Nano
- Bouw een betrouwbare wekker met DS1302 RTC en Arduino UNO