Skip to content

Technik Blog

Programmieren | Arduino | ESP32 | MicroPython | Python | Raspberry Pi | Raspberry Pi Pico

Menu
  • Smarthome
  • Arduino
  • ESP32 & Co.
  • Raspberry Pi & Pico
  • Solo Mining
  • Über mich
  • Deutsch
  • English
Menu

Schritt-für-Schritt zur flexiblen Timer-Schaltung mit DS1302 und OLED-Display

Posted on 15. November 202414. November 2024 by Stefan Draeger

In diesem Beitrag zeige ich dir, wie du eine flexible Timer-Schaltung mit der Real-Time-Clock DS1302 und einem OLED-Display, das über ein Drehreglermodul gesteuert wird, programmierst. Die Schaltung ist mit Arduino-kompatiblen Mikrocontrollern nutzbar und bietet dir die Möglichkeit, individuelle Alarme bequem und flexibel einzustellen. In einem früheren Beitrag habe ich bereits erläutert, wie du das OLED-Display und den Drehregler in der Arduino IDE programmierst, um feste Zeiten zu setzen. Hier gehen wir nun einen Schritt weiter und gestalten eine flexiblere Lösung, die sich ideal für Projekte eignet, bei denen sich die Alarmzeiten regelmäßig anpassen lassen.

Schritt-für-Schritt zur flexiblen Timer-Schaltung mit DS1302 und OLED-Display
Dieses Video auf YouTube ansehen.

Mit dieser Schaltung lassen sich tägliche und wiederkehrende Alarme intuitiv und ohne großen Programmieraufwand festlegen – perfekt für DIY-Projekte, die eine dynamische Zeitsteuerung erfordern.

Die in dieser Schaltung verwendeten Module, die RTC DS1302 und das OLED-Display mit Drehregler, habe ich bereits in früheren Beiträgen auf diesem Blog vorgestellt und verschiedene Anwendungsbeispiele gezeigt:

  • DS1302 RTC mit SPI-Schnittstelle: So programmierst du die Echtzeituhr am Arduino
  • OLED Display und Drehregler: Programmieren in der Arduino IDE

Inhaltsverzeichnis

  • Wie soll die Timer-Schaltung am Arduino funktionieren?
  • Aufbau der Schaltung – RTC DS1302 mit OLED-Display Modul am Arduino Mikrocontroller
  • Programmieren in der Arduino IDE
    • Schritt 1 – installieren der benötigten Bibliotheken für die RTC, OLED-Display & Drehregler
    • Schritt 2 – Definieren der Pins & Initialisieren der Objekte
    • Schritt 3 – Felder & Variablen definieren
    • Schritt 4 – Funktion setup
    • Schritt 5 – Funktion zum zeichnen des Hintergrundes
    • Schritt 6 – Funktion zum anzeigen des aktuellen Datums und der Uhrzeit auf dem Display
    • Schritt 7 – Funktion zum anzeigen des eingestellten Weckers
    • Schritt 8 – Funktion zum zeichnen eines Rechtecks zum anzeigen der Bearbeitung
    • Schritt 9 – Funktion zum Anzeigen des Textes „!! Alarm !!“ auf dem Display
    • Schritt 10 – Funktion zum aktivieren des Alarms und ausgeben eines Tones
    • Schritt 11 – Funktion loop zum behandeln der Aktionen am Drehrehregler und Taster
  • Fertiges Programm – RTC DS1302 Timer-Schaltung mit OLED-Display am Arduino
  • Erweiterung um ein Relais Modul

Wie soll die Timer-Schaltung am Arduino funktionieren?

Die Timer-Schaltung basiert auf einer RTC DS1302, die als Zeitgeber dient und an den Arduino angeschlossen ist. Über einen Drehregler am OLED-Display lässt sich die gewünschte Alarmzeit einstellen. Zu dieser eingestellten Zeit gibt die Schaltung ein Signal an einen kleinen Piezo-Buzzer aus, der den Alarm akustisch meldet. Alternativ lässt sich der Buzzer durch ein Relais ersetzen, um zu bestimmten Zeiten andere Geräte automatisch zu schalten.

Timer-Schaltung am Arduino mit OLED-Display und RTC DS1302
Timer-Schaltung am Arduino mit OLED-Display und RTC DS1302

Aufbau der Schaltung – RTC DS1302 mit OLED-Display Modul am Arduino Mikrocontroller

Beginnen wir mit dem Aufbau der Schaltung: Ich habe sie kompakt auf einem 400-Pin-Breadboard realisiert. Da sowohl das OLED-Modul als auch die RTC 5V benötigen, ist das Breadboard unverzichtbar, weil der Mikrocontroller nur über einen 3,3V- und einen 5V-VCC-Ausgang verfügt.

Für den Aufbau benötigst du:

  • einen Arduino kompatiblen Mikrocontroller,
    • einen Arduino Nano V3*, oder
    • einen Maker Nano
  • ein passendes USB-Datenkabel*,
  • eine RTC DS1302*,
  • einen Piezo Buzzer*,
  • ein OLED-Display Modul mit Drehregler*
Bauteile für die Timer-Schaltung am Arduino kompatiblen Mikrocontroller
Bauteile für die Timer-Schaltung am Arduino kompatiblen Mikrocontroller

Hinweis von mir: Die mit einem Sternchen (*) markierten Links sind Affiliate-Links. Wenn du über diese Links einkaufst, erhalte ich eine kleine Provision, die dazu beiträgt, diesen Blog zu unterstützen. Der Preis für dich bleibt dabei unverändert. Vielen Dank für deine Unterstützung!

Falls du das hier verwendete OLED-Display-Modul mit integriertem Drehregler nicht zur Verfügung hast, kannst du die Bauteile auch separat anschließen. Achte jedoch später im Code darauf, dass dieses Modul den Treiberchip SH11X verwendet und nicht den gängigeren SSD1306.

Schaltung - Arduino mit RTC DS1302, Piezo Buzzer & OLED-Display mit Drehregler Modul
Schaltung – Arduino mit RTC DS1302, Piezo Buzzer & OLED-Display mit Drehregler Modul

Programmieren in der Arduino IDE

Schritt 1 – installieren der benötigten Bibliotheken für die RTC, OLED-Display & Drehregler

Die RTC DS1302, der Drehregler und das OLED-Display erfordern zusätzliche Bibliotheken, die wir zunächst installieren, bevor wir mit der Programmierung beginnen.

Zur Steuerung der RTC DS1302 nutzen wir die VirtuabotixRTC-Bibliothek, die als ZIP-Datei im GitHub-Repository von chrisfryer78/ArduinoRTClibrary verfügbar ist.

Für den Rotary Encoder gibt es verschiedene Bibliotheken. Ich habe gute Erfahrungen mit der Version von CarlosSiles67 gemacht, die du unter CarlosSiles67/Rotary herunterladen kannst.

Das OLED-Display wird durch den Treiberchip SH1106 betrieben, weshalb wir eine spezielle Bibliothek benötigen. Diese findest du entweder im GitHub-Repository von Adafruit oder direkt im Bibliotheksverwalter der Arduino IDE unter dem Namen „Adafruit SH110x“.

Schritt 2 – Definieren der Pins & Initialisieren der Objekte

Im ersten Schritt im Code laden wir die benötigten Bibliotheken und definieren die Pins welche mit dem Mikrocontroller verbunden sind.

#include <virtuabotixRTC.h>

#include <rotary.h>

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>

Für das kleine Programm verwende ich drei Schriftarten wobei eine davon die default ist, andere coole Schriftarten findest du auch unter der Adresse https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts.

#include <Fonts/FreeSans18pt7b.h>
#include <Fonts/FreeSerif12pt7b.h>

Definieren der Pins vom Drehregler, den Tasten, RTC und des Piezo Buzzers.

#define pushPin 9
#define traPin 10
#define trbPin 11

#define confirmPin 5
#define backPin 4

#define clkPin 6
#define datPin 7
#define rstPin 8

#define buzzerPin 13

Initialisieren der Objekte

virtuabotixRTC rtcDS1302(clkPin, datPin, rstPin);

Rotary rotary = Rotary(traPin, trbPin, pushPin);

#define i2c_Address 0x3c
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);

Schritt 3 – Felder & Variablen definieren

Für das speichern der Zustände benötigen wir einige Felder.

//Konstante für die Pause zwischen dem umschalten der Zeit
//wir zeigen auf dem Display lediglich Minutengenau an
//daher ist der Takt 1 Minute (60000 Millisekunden)
const unsigned long PAUSE = 60000;
//Feld zum speichern des Zeitstempels der letzten ausführung
unsigned long lastAction = -1;

//Feld zum speichern des Zeitstempels wann der Alarm das
//letzte Mal ertönt hat. Damit wird ein Konstanter Ton unterbunden.
unsigned long lastActionAlarm = -1;
const int PAUSE_ALARM = 500;

//Zeit für den Wecker
int stunden = 12;
int minuten = 34;
//Felder zum zwischenspeichern der Werte
//diese werden später in die "echten" Felder
//überschrieben
int tempStunden = stunden;
int tempMinuten = minuten;

//Felder zum speichern ob der Alarm aktiviert ist,
//ob gerade die Zeit eingestellt wird
bool setAlarm = false;
bool isAlarmActive = false;
bool isAlarmDeactivated = false;
//Welcher Bestandteil der Zeit (Stunde oder Minute)
//soll bearbeitet werden
int alarmTimeIndex = 0;

Schritt 4 – Funktion setup

Die Funktion setup wird einmalig beim starten des Mikrocontrollers ausgeführt. Hier konfigurieren wir die Pins einmalig.

//Diese Funktion wird einmalig beim Starten / neustarten
//des Mikrocontrollers ausgeführt.
void setup() {
  //beginn der seriellen Kommunikation mit 9600 baud
  Serial.begin(9600);
  //Pin des Taster BACK als Eingang definieren
  pinMode(backPin, INPUT);
  //Pin des Taster CONFIRM als Eingang definieren
  pinMode(confirmPin, INPUT);
  //Pin des Piezo Buzzers als Ausgang definieren
  pinMode(buzzerPin, OUTPUT);
   
  //Initialisieren des Displays
  display.begin(i2c_Address, true);
  //leeren des Display
  display.clearDisplay();
  //Zeichnen des Hintergrundes
  drawBackground();
  //Anzeigen der aktuellen Uhrzeit
  updateTime();
  //Anzeigen des Weckers
  displayTime(stunden, minuten);
}

Schritt 5 – Funktion zum zeichnen des Hintergrundes

Für den Hintergrund zeichnen wir einmal ein abgerundetes Rechteck sowie eine Linie.

//Funktion zum zeichnen des Hintergrundes
void drawBackground() {
  //Ein abgerundetes Rechteck zeichnen
  display.drawRoundRect(2, 2, 125, 62, 5, SH110X_WHITE);
  //Eine Linie zeichnen
  display.drawFastHLine(2, 20, 125, SH110X_WHITE);
}

Schritt 6 – Funktion zum anzeigen des aktuellen Datums und der Uhrzeit auf dem Display

Mit der Funktion updateTime wird die Uhrzeit und das Datum welches oben im Display befindet aktualisiert.

//Funktion zum anzeigen des aktuellen Datums und der Uhrzeit
void updateTime() {
  //ein gefülltes, schwarzes Rechteck über die gezeichneten Felder
  //für das Datum und die Uhrzeit zeichnen
  display.fillRect(4, 4, 120, 16, SH110X_BLACK);
  //die Felder der RTC aktualisieren
  rtcDS1302.updateTime();
  
  //Auslesen und Formatieren der Uhrzeit und des Datums
  char zeit[12];
  sprintf(zeit, "%02d:%02d", rtcDS1302.hours, rtcDS1302.minutes);
  char datum[8];
  sprintf(datum, "%02d.%02d.%02d", rtcDS1302.dayofmonth, rtcDS1302.month, rtcDS1302.year - 2000);
  //Ausgeben der Daten auf der seriellen Schnittstelle
  Serial.print(datum);
  Serial.print(" ");
  Serial.println(zeit);
  //Font auf default setzen
  //(später verwenden wir bestimmte Schriftarten, daher müssen wir dieses hier zurücksetzen)
  display.setFont(NULL);
  //Textgröße 1
  display.setTextSize(1);
  //Schriftfarbe Weiß
  display.setTextColor(SH110X_WHITE);
  //setzen des Cursors
  display.setCursor(10, 8);
  //schreiben des Datums an die Cursorposition
  display.println(datum);
  //setzen des Cursors
  display.setCursor(90, 8);
  //schreiben der Uhrzeit an die Cursorposition
  display.println(zeit);
  //Absenden der Daten an das Display
  //dieser Aufruf ist sehr wichtig, ohne diesen werden keine Daten angezeigt
  display.display();
}

Schritt 7 – Funktion zum anzeigen des eingestellten Weckers

Die eingestellte Zeit des Weckers wird mittig im Display angezeigt.

Display für eine Timer-Schaltung mit RTC am Arduino
Display für eine Timer-Schaltung mit RTC am Arduino
//Funktion zum Anzeigen des Weckers
void displayTime(int stunden, int minuten) {
  //Wenn der Modus zum editieren des Alarms nicht aktiv ist, dann...
  if (!setAlarm) {
    //Zeichnen von gefüllten, schwarten Rechtecken
    display.fillRect(70, 55, 40, 3, SH110X_BLACK);
    display.fillRect(20, 55, 40, 3, SH110X_BLACK);
  }
  
  //ein schwarzes, gefülltes Rechteck über die Felder
  //für Stunden & Minuten zeichnen
  display.fillRect(20, 22, 40, 30, SH110X_BLACK);
  display.fillRect(70, 22, 40, 30, SH110X_BLACK);

  //setzen der Schriftart
  display.setFont(&FreeSans18pt7b);
  //setzen der Schriftgröße 1
  display.setTextSize(1);
  //setzen der Schriftfarbe Weiß
  display.setTextColor(SH110X_WHITE);
  
  //Wenn der Wert der Stunden kleiner 10 ist,
  //dann wird der Text um eine Stelle eingerückt
  display.setCursor(stunden < 10 ? 40 : 20, 51);
  display.println(stunden);
  display.setCursor(60, 51);
  display.println(":");

  //Formatieren der Minuten mit führender Null
  char minutes[2];
  sprintf(minutes, "%02d", minuten);

  display.setCursor(70, 51);
  display.println(minutes);
  display.display();
}

Schritt 8 – Funktion zum zeichnen eines Rechtecks zum anzeigen der Bearbeitung

Wenn der Wecker eingestellt wird, dann soll unter dem zzt. eingestellten Wert (Stunde oder Minute) ein kleines, gefülltes Rechteck gezeichnet werden.

Einstellen einer Zeit am OLED-Display
Einstellen einer Zeit am OLED-Display
//Funktion zum zeichnen eines kleinen weißen Rechtecks
//wenn der Wecker eingestellt wird, anhand dieses Rechtecks
//kann der Benutzer erkennen welcher Bestandteil der Zeit gerade
//bearbeitet wird.
void changeAlarm() {
  if (alarmTimeIndex == 0) {
    display.fillRect(20, 55, 40, 3, SH110X_WHITE);
    display.fillRect(70, 55, 40, 3, SH110X_BLACK);
  } else if (alarmTimeIndex == 1) {
    display.fillRect(70, 55, 40, 3, SH110X_WHITE);
    display.fillRect(20, 55, 40, 3, SH110X_BLACK);
  }
  display.display();
}

Schritt 9 – Funktion zum Anzeigen des Textes „!! Alarm !!“ auf dem Display

Wenn der Alarm aktiviert ist, dann soll der Text „!! Alarm !!“ auf dem Display angezeigt werden.

//Funktion zum anzeigen des Textes "!! Alarm !!" auf dem Display
void showAlarmMsg() {
  display.fillRect(5, 23, 118, 40, SH110X_BLACK);
  display.setFont(&FreeSerif12pt7b);
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(12, 50);
  display.println("!! Alarm !!");
  display.display();
}

Schritt 10 – Funktion zum aktivieren des Alarms und ausgeben eines Tones

Wenn der Zeitpunkt des Alarms ereicht wurde, dann soll ein Ton ausgegeben werden.

//Funktion zum aktivieren des Alarms und abspielen eines Tones
void playAlarm() {
  isAlarmActive = true;
  //ein Ton mit der Frequenz von 450 Hz und der Dauer von 125 ms.
  //abspielen
  tone(buzzerPin, 450, 125);
}

Schritt 11 – Funktion loop zum behandeln der Aktionen am Drehrehregler und Taster

In der Funktion loop werden die Aktionen am Drehregler und den Taster behandelt. Diese sind je nach aktivierten Modus verschieden.

//Diese Funktion wird fortwährend ausgeführt
void loop() {
  //speichern der aktuellen Millisekunden seitdem der Mikrocontroller
  //gestartet wurde
  unsigned long currentMillis = millis();
  //Wenn der Zeitpunkt der nächsten Ausführung erreicht wurde, dann...
  if ((lastAction + PAUSE) < currentMillis) {
    //abspeichern der aktuellen Millisekunden
    lastAction = currentMillis;
    //aktualisieren der Zeit auf dem Display
    updateTime();
     
    //prüfen ob der Alarm aktiviert werden soll
    rtcDS1302.updateTime();
    int currentStunden = rtcDS1302.hours;
    int currentMinuten = rtcDS1302.minutes;
    if ((currentStunden == stunden && currentMinuten == minuten)) {
      isAlarmActive = true;
      showAlarmMsg();
    }
  }

  //Wenn der Alarm aktiviert ist, dann soll dieser Piepen und kein Dauerton sein
  //daher werden zwischen zwei Tönen eine kleine Pause eingelegt
  if ((lastActionAlarm + PAUSE_ALARM) < currentMillis && isAlarmActive) {
    lastActionAlarm = currentMillis;
    tone(buzzerPin, 600, 100);
  }

  //auslesen der aktuellen Drehrichtung des Drehreglers / Rotary Encoder
  char currentPosition = rotary.process();
  //Wenn der Drehregler im Uhrzeigersinn gedreht wird und der Wecker eingestellt wird, dann...
  if (currentPosition == rotary.clockwise() && setAlarm) {
    //Nur wenn der Wert der Stunden größer 0 ist einen abziehen
    if (alarmTimeIndex == 0 && tempStunden > 0) {
      tempStunden = tempStunden - 1;
    } else if (alarmTimeIndex == 1 && tempMinuten > 0) {
      tempMinuten = tempMinuten - 1;
    }
    //einen Ton abspielen
    playKeyTone();
    //anzeigen des neuen Wertes
    displayTime(tempStunden, tempMinuten);
  } else if (currentPosition == rotary.counterClockwise() && setAlarm) {
    //Wenn die Drehrichtung gegen den Uhrzeigersinn ist und der Wecker eingestellt wird, dann...
    if (alarmTimeIndex == 0 && tempStunden < 23) {
      tempStunden = tempStunden + 1;
    } else if (alarmTimeIndex == 1 && tempMinuten < 59) {
      tempMinuten = tempMinuten + 1;
    }
    playKeyTone();
    displayTime(tempStunden, tempMinuten);
  }

  //Der mittlere Taster des Drehreglers dient zum deaktivieren des Alarms UND
  //zum wechseln zwischen Stunde & Minute
  if (rotary.buttonPressedReleased(20)) {
    //Wenn der Alarm aktiviert ist, dann...
    if (isAlarmActive) {
      isAlarmActive = false;
      display.fillRect(5, 23, 118, 40, SH110X_BLACK);
      displayTime(stunden, minuten);
      //An diesem Punkt wird die Funktion verlassen!
      return;
    }

    //Wenn der Wecker nicht eingestellt wird, dann
    if (!setAlarm) {
      //Wecker wird eingestellt
      setAlarm = true;
      changeAlarm();
      playKeyTone();
    } else {
      //Wechseln zwischen den Feldern Stunde & Minute
      alarmTimeIndex = alarmTimeIndex == 0 ? 1 : 0;
      changeAlarm();
      playKeyTone();
    }
  }

  //Wenn die BACK Taste betätigt wird und der Wecker eingestellt wird, dann...
  if ((digitalRead(backPin) == LOW) && setAlarm) {
    //überschreiben der gewählten Zeiten mit den vorherigen Werten
    tempStunden = stunden;
    tempMinuten = minuten;
    //deaktivieren des Modus zum einstellen des Weckers
    setAlarm = false;
    //eine kleine Pause von 150 ms. um den Taster zu entprellen
    delay(150);
    //anzeigen der Stunden & Minuten auf dem Display
    displayTime(stunden, minuten);
    //abspielen eines Tones
    playKeyTone();
  } else if ((digitalRead(backPin) == LOW) && !setAlarm) {
    showAlarmMsg();
  }

  //Wenn die Taste CONFIRM betätigt wird und der Wecker eingestellt wird, dann...
  if ((digitalRead(confirmPin) == LOW) && setAlarm) {
    //überschreiben der Werte für Stunde & Minute mit den gewählten Einstellungen
    stunden = tempStunden;
    minuten = tempMinuten;
    setAlarm = false;
    delay(150);
    displayTime(stunden, minuten);
    playKeyTone();
  }
}

Fertiges Programm – RTC DS1302 Timer-Schaltung mit OLED-Display am Arduino

Kompletter Quellcode des Projektes
// Importieren der benötigten Bibliotheken
// Bibliothek zum einfachen auslesen / setzen
// eines Zeitstempels einer RTC vom Typ DS1302
#include <virtuabotixRTC.h>

// Bibliothek zum auslesen der Drehrichtung am
// Drehregler / Rotary Encoder
#include <rotary.h>

// Für das OLED-Display mit Treiberchip SH110X 
// wird die Adafruit Bibliothek verwendet
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>

// Auf dem Display werden zwei Schriftarten verwendet
// unter https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts
// finden sich weitere verwendbare Schriften und Größen
#include <Fonts/FreeSans18pt7b.h>
#include <Fonts/FreeSerif12pt7b.h>

// Der Drehregler benötigt drei Pins.
#define pushPin 9 //mittlerer Taster
#define traPin 10
#define trbPin 11

// die beiden Taster CONFIRM & BACK
#define confirmPin 5
#define backPin 4

// RTC DS1302
#define clkPin 6
#define datPin 7
#define rstPin 8

//Piezo Buzzer
#define buzzerPin 13

//Objekt für die RTC initialisieren
virtuabotixRTC rtcDS1302(clkPin, datPin, rstPin);

//Objekt für den Drehregler / Rotary Encoder
//mit den Pins initialisieren
Rotary rotary = Rotary(traPin, trbPin, pushPin);

//Initialisieren der OLED Anzeige
//die default Adresse ist 0x3c
//Es wird hier ein Treiberchip SH110X verwendet, solltest
//du eine SSD1306 verwenden so musst du hier eine
//andere Bibliothek verwenden.
#define i2c_Address 0x3c
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);

//Konstante für die Pause zwischen dem umschalten der Zeit
//wir zeigen auf dem Display lediglich Minutengenau an
//daher ist der Takt 1 Minute (60000 Millisekunden)
const unsigned long PAUSE = 60000;
//Feld zum speichern des Zeitstempels der letzten ausführung
unsigned long lastAction = -1;

//Feld zum speichern des Zeitstempels wann der Alarm das
//letzte Mal ertönt hat. Damit wird ein Konstanter Ton unterbunden.
unsigned long lastActionAlarm = -1;
const int PAUSE_ALARM = 500;

//Zeit für den Wecker
int stunden = 12;
int minuten = 34;
//Felder zum zwischenspeichern der Werte
//diese werden später in die "echten" Felder
//überschrieben
int tempStunden = stunden;
int tempMinuten = minuten;

//Felder zum speichern ob der Alarm aktiviert ist,
//ob gerade die Zeit eingestellt wird
bool setAlarm = false;
bool isAlarmActive = false;
bool isAlarmDeactivated = false;
//Welcher Bestandteil der Zeit (Stunde oder Minute)
//soll bearbeitet werden
int alarmTimeIndex = 0;

//Diese Funktion wird einmalig beim Starten / neustarten
//des Mikrocontrollers ausgeführt.
void setup() {
  //beginn der seriellen Kommunikation mit 9600 baud
  Serial.begin(9600);
  //Pin des Taster BACK als Eingang definieren
  pinMode(backPin, INPUT);
  //Pin des Taster CONFIRM als Eingang definieren
  pinMode(confirmPin, INPUT);
  //Pin des Piezo Buzzers als Ausgang definieren
  pinMode(buzzerPin, OUTPUT);
   
  //Initialisieren des Displays
  display.begin(i2c_Address, true);
  //leeren des Display
  display.clearDisplay();
  //Zeichnen des Hintergrundes
  drawBackground();
  //Anzeigen der aktuellen Uhrzeit
  updateTime();
  //Anzeigen des Weckers
  displayTime(stunden, minuten);
}

void playKeyTone() {
  tone(buzzerPin, 600, 75);
}

//Funktion zum zeichnen des Hintergrundes
void drawBackground() {
  //Ein abgerundetes Rechteck zeichnen
  display.drawRoundRect(2, 2, 125, 62, 5, SH110X_WHITE);
  //Eine Linie zeichnen
  display.drawFastHLine(2, 20, 125, SH110X_WHITE);
}

//Funktion zum anzeigen des aktuellen Datums und der Uhrzeit
void updateTime() {
  //ein gefülltes, schwarzes Rechteck über die gezeichneten Felder
  //für das Datum und die Uhrzeit zeichnen
  display.fillRect(4, 4, 120, 16, SH110X_BLACK);
  //die Felder der RTC aktualisieren
  rtcDS1302.updateTime();
  
  //Auslesen und Formatieren der Uhrzeit und des Datums
  char zeit[12];
  sprintf(zeit, "%02d:%02d", rtcDS1302.hours, rtcDS1302.minutes);
  char datum[8];
  sprintf(datum, "%02d.%02d.%02d", rtcDS1302.dayofmonth, rtcDS1302.month, rtcDS1302.year - 2000);
  //Ausgeben der Daten auf der seriellen Schnittstelle
  Serial.print(datum);
  Serial.print(" ");
  Serial.println(zeit);
  //Font auf default setzen
  //(später verwenden wir bestimmte Schriftarten, daher müssen wir dieses hier zurücksetzen)
  display.setFont(NULL);
  //Textgröße 1
  display.setTextSize(1);
  //Schriftfarbe Weiß
  display.setTextColor(SH110X_WHITE);
  //setzen des Cursors
  display.setCursor(10, 8);
  //schreiben des Datums an die Cursorposition
  display.println(datum);
  //setzen des Cursors
  display.setCursor(90, 8);
  //schreiben der Uhrzeit an die Cursorposition
  display.println(zeit);
  //Absenden der Daten an das Display
  //dieser Aufruf ist sehr wichtig, ohne diesen werden keine Daten angezeigt
  display.display();
}

//Funktion zum Anzeigen des Weckers
void displayTime(int stunden, int minuten) {
  //Wenn der Modus zum editieren des Alarms nicht aktiv ist, dann...
  if (!setAlarm) {
    //Zeichnen von gefüllten, schwarten Rechtecken
    display.fillRect(70, 55, 40, 3, SH110X_BLACK);
    display.fillRect(20, 55, 40, 3, SH110X_BLACK);
  }
  
  //ein schwarzes, gefülltes Rechteck über die Felder
  //für Stunden & Minuten zeichnen
  display.fillRect(20, 22, 40, 30, SH110X_BLACK);
  display.fillRect(70, 22, 40, 30, SH110X_BLACK);

  //setzen der Schriftart
  display.setFont(&FreeSans18pt7b);
  //setzen der Schriftgröße 1
  display.setTextSize(1);
  //setzen der Schriftfarbe Weiß
  display.setTextColor(SH110X_WHITE);
  
  //Wenn der Wert der Stunden kleiner 10 ist,
  //dann wird der Text um eine Stelle eingerückt
  display.setCursor(stunden < 10 ? 40 : 20, 51);
  display.println(stunden);
  display.setCursor(60, 51);
  display.println(":");

  //Formatieren der Minuten mit führender Null
  char minutes[2];
  sprintf(minutes, "%02d", minuten);

  display.setCursor(70, 51);
  display.println(minutes);
  display.display();
}

//Funktion zum zeichnen eines kleinen weißen Rechtecks
//wenn der Wecker eingestellt wird, anhand dieses Rechtecks
//kann der Benutzer erkennen welcher Bestandteil der Zeit gerade
//bearbeitet wird.
void changeAlarm() {
  if (alarmTimeIndex == 0) {
    display.fillRect(20, 55, 40, 3, SH110X_WHITE);
    display.fillRect(70, 55, 40, 3, SH110X_BLACK);
  } else if (alarmTimeIndex == 1) {
    display.fillRect(70, 55, 40, 3, SH110X_WHITE);
    display.fillRect(20, 55, 40, 3, SH110X_BLACK);
  }
  display.display();
}

//Funktion zum anzeigen des Textes "!! Alarm !!" auf dem Display
void showAlarmMsg() {
  display.fillRect(5, 23, 118, 40, SH110X_BLACK);
  display.setFont(&FreeSerif12pt7b);
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(12, 50);
  display.println("!! Alarm !!");
  display.display();
}

//Funktion zum aktivieren des Alarms und abspielen eines Tones
void playAlarm() {
  isAlarmActive = true;
  //ein Ton mit der Frequenz von 450 Hz und der Dauer von 125 ms.
  //abspielen
  tone(buzzerPin, 450, 125);
}

//Diese Funktion wird fortwährend ausgeführt
void loop() {
  //speichern der aktuellen Millisekunden seitdem der Mikrocontroller
  //gestartet wurde
  unsigned long currentMillis = millis();
  //Wenn der Zeitpunkt der nächsten Ausführung erreicht wurde, dann...
  if ((lastAction + PAUSE) < currentMillis) {
    //abspeichern der aktuellen Millisekunden
    lastAction = currentMillis;
    //aktualisieren der Zeit auf dem Display
    updateTime();
     
    //prüfen ob der Alarm aktiviert werden soll
    rtcDS1302.updateTime();
    int currentStunden = rtcDS1302.hours;
    int currentMinuten = rtcDS1302.minutes;
    if ((currentStunden == stunden && currentMinuten == minuten)) {
      isAlarmActive = true;
      showAlarmMsg();
    }
  }

  //Wenn der Alarm aktiviert ist, dann soll dieser Piepen und kein Dauerton sein
  //daher werden zwischen zwei Tönen eine kleine Pause eingelegt
  if ((lastActionAlarm + PAUSE_ALARM) < currentMillis && isAlarmActive) {
    lastActionAlarm = currentMillis;
    tone(buzzerPin, 600, 100);
  }

  //auslesen der aktuellen Drehrichtung des Drehreglers / Rotary Encoder
  char currentPosition = rotary.process();
  //Wenn der Drehregler im Uhrzeigersinn gedreht wird und der Wecker eingestellt wird, dann...
  if (currentPosition == rotary.clockwise() && setAlarm) {
    //Nur wenn der Wert der Stunden größer 0 ist einen abziehen
    if (alarmTimeIndex == 0 && tempStunden > 0) {
      tempStunden = tempStunden - 1;
    } else if (alarmTimeIndex == 1 && tempMinuten > 0) {
      tempMinuten = tempMinuten - 1;
    }
    //einen Ton abspielen
    playKeyTone();
    //anzeigen des neuen Wertes
    displayTime(tempStunden, tempMinuten);
  } else if (currentPosition == rotary.counterClockwise() && setAlarm) {
    //Wenn die Drehrichtung gegen den Uhrzeigersinn ist und der Wecker eingestellt wird, dann...
    if (alarmTimeIndex == 0 && tempStunden < 23) {
      tempStunden = tempStunden + 1;
    } else if (alarmTimeIndex == 1 && tempMinuten < 59) {
      tempMinuten = tempMinuten + 1;
    }
    playKeyTone();
    displayTime(tempStunden, tempMinuten);
  }

  //Der mittlere Taster des Drehreglers dient zum deaktivieren des Alarms UND
  //zum wechseln zwischen Stunde & Minute
  if (rotary.buttonPressedReleased(20)) {
    //Wenn der Alarm aktiviert ist, dann...
    if (isAlarmActive) {
      isAlarmActive = false;
      display.fillRect(5, 23, 118, 40, SH110X_BLACK);
      displayTime(stunden, minuten);
      //An diesem Punkt wird die Funktion verlassen!
      return;
    }

    //Wenn der Wecker nicht eingestellt wird, dann
    if (!setAlarm) {
      //Wecker wird eingestellt
      setAlarm = true;
      changeAlarm();
      playKeyTone();
    } else {
      //Wechseln zwischen den Feldern Stunde & Minute
      alarmTimeIndex = alarmTimeIndex == 0 ? 1 : 0;
      changeAlarm();
      playKeyTone();
    }
  }

  //Wenn die BACK Taste betätigt wird und der Wecker eingestellt wird, dann...
  if ((digitalRead(backPin) == LOW) && setAlarm) {
    //überschreiben der gewählten Zeiten mit den vorherigen Werten
    tempStunden = stunden;
    tempMinuten = minuten;
    //deaktivieren des Modus zum einstellen des Weckers
    setAlarm = false;
    //eine kleine Pause von 150 ms. um den Taster zu entprellen
    delay(150);
    //anzeigen der Stunden & Minuten auf dem Display
    displayTime(stunden, minuten);
    //abspielen eines Tones
    playKeyTone();
  } else if ((digitalRead(backPin) == LOW) && !setAlarm) {
    showAlarmMsg();
  }

  //Wenn die Taste CONFIRM betätigt wird und der Wecker eingestellt wird, dann...
  if ((digitalRead(confirmPin) == LOW) && setAlarm) {
    //überschreiben der Werte für Stunde & Minute mit den gewählten Einstellungen
    stunden = tempStunden;
    minuten = tempMinuten;
    setAlarm = false;
    delay(150);
    displayTime(stunden, minuten);
    playKeyTone();
  }
}

Erweiterung um ein Relais Modul

Du kannst diese Schaltung auch recht einfach um ein Relais Modul erweitern, dazu schließt du dieses an eines der freien digitalen Pins an und musst lediglich in der Funktion wo der Alarm aktiviert wird, den Pin vom Relais auf LOW setzen. Wenn der Alarm wieder deaktiviert wird, musst du diesen Pin auf HIGH setzen.

Erweiterte Timer-Schaltung mit einem zusätzlichen Relais Modul
Erweiterte Timer-Schaltung mit einem zusätzlichen Relais Modul
Quellcode für die erweiterte Schaltung mit einem Relais modul
// Importieren der benötigten Bibliotheken
// Bibliothek zum einfachen auslesen / setzen
// eines Zeitstempels einer RTC vom Typ DS1302
#include <virtuabotixRTC.h>

// Bibliothek zum auslesen der Drehrichtung am
// Drehregler / Rotary Encoder
#include <rotary.h>

// Für das OLED-Display mit Treiberchip SH110X
// wird die Adafruit Bibliothek verwendet
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH110X.h>

// Auf dem Display werden zwei Schriftarten verwendet
// unter https://learn.adafruit.com/adafruit-gfx-graphics-library/using-fonts
// finden sich weitere verwendbare Schriften und Größen
#include <Fonts/FreeSans18pt7b.h>
#include <Fonts/FreeSerif12pt7b.h>

// Der Drehregler benötigt drei Pins.
#define pushPin 9  //mittlerer Taster
#define traPin 10
#define trbPin 11

// die beiden Taster CONFIRM & BACK
#define confirmPin 5
#define backPin 4

// RTC DS1302
#define clkPin 6
#define datPin 7
#define rstPin 8

//Piezo Buzzer
#define buzzerPin 13

//Relais
#define relaisPin 12

//Objekt für die RTC initialisieren
virtuabotixRTC rtcDS1302(clkPin, datPin, rstPin);

//Objekt für den Drehregler / Rotary Encoder
//mit den Pins initialisieren
Rotary rotary = Rotary(traPin, trbPin, pushPin);

//Initialisieren der OLED Anzeige
//die default Adresse ist 0x3c
//Es wird hier ein Treiberchip SH110X verwendet, solltest
//du eine SSD1306 verwenden so musst du hier eine
//andere Bibliothek verwenden.
#define i2c_Address 0x3c
Adafruit_SH1106G display = Adafruit_SH1106G(128, 64, &Wire, -1);

//Konstante für die Pause zwischen dem umschalten der Zeit
//wir zeigen auf dem Display lediglich Minutengenau an
//daher ist der Takt 1 Minute (60000 Millisekunden)
const unsigned long PAUSE = 60000;
//Feld zum speichern des Zeitstempels der letzten ausführung
unsigned long lastAction = -1;

//Feld zum speichern des Zeitstempels wann der Alarm das
//letzte Mal ertönt hat. Damit wird ein Konstanter Ton unterbunden.
unsigned long lastActionAlarm = -1;
const int PAUSE_ALARM = 500;

//Zeit für den Wecker
int stunden = 12;
int minuten = 34;
//Felder zum zwischenspeichern der Werte
//diese werden später in die "echten" Felder
//überschrieben
int tempStunden = stunden;
int tempMinuten = minuten;

//Felder zum speichern ob der Alarm aktiviert ist,
//ob gerade die Zeit eingestellt wird
bool setAlarm = false;
bool isAlarmActive = false;
bool isAlarmDeactivated = false;
//Welcher Bestandteil der Zeit (Stunde oder Minute)
//soll bearbeitet werden
int alarmTimeIndex = 0;

//Diese Funktion wird einmalig beim Starten / neustarten
//des Mikrocontrollers ausgeführt.
void setup() {
  //beginn der seriellen Kommunikation mit 9600 baud
  Serial.begin(9600);
  //Pin des Taster BACK als Eingang definieren
  pinMode(backPin, INPUT);
  //Pin des Taster CONFIRM als Eingang definieren
  pinMode(confirmPin, INPUT);
  //Pin des Piezo Buzzers als Ausgang definieren
  pinMode(buzzerPin, OUTPUT);
  //Pin des Relais als Ausgang definieren
  pinMode(relaisPin, OUTPUT);

  //Initialisieren des Displays
  display.begin(i2c_Address, true);
  //leeren des Display
  display.clearDisplay();
  //Zeichnen des Hintergrundes
  drawBackground();
  //Anzeigen der aktuellen Uhrzeit
  updateTime();
  //Anzeigen des Weckers
  displayTime(stunden, minuten);
}

void playKeyTone() {
  tone(buzzerPin, 600, 75);
}

//Funktion zum zeichnen des Hintergrundes
void drawBackground() {
  //Ein abgerundetes Rechteck zeichnen
  display.drawRoundRect(2, 2, 125, 62, 5, SH110X_WHITE);
  //Eine Linie zeichnen
  display.drawFastHLine(2, 20, 125, SH110X_WHITE);
}

//Funktion zum anzeigen des aktuellen Datums und der Uhrzeit
void updateTime() {
  //ein gefülltes, schwarzes Rechteck über die gezeichneten Felder
  //für das Datum und die Uhrzeit zeichnen
  display.fillRect(4, 4, 120, 16, SH110X_BLACK);
  //die Felder der RTC aktualisieren
  rtcDS1302.updateTime();

  //Auslesen und Formatieren der Uhrzeit und des Datums
  char zeit[12];
  sprintf(zeit, "%02d:%02d", rtcDS1302.hours, rtcDS1302.minutes);
  char datum[8];
  sprintf(datum, "%02d.%02d.%02d", rtcDS1302.dayofmonth, rtcDS1302.month, rtcDS1302.year - 2000);
  //Ausgeben der Daten auf der seriellen Schnittstelle
  Serial.print(datum);
  Serial.print(" ");
  Serial.println(zeit);
  //Font auf default setzen
  //(später verwenden wir bestimmte Schriftarten, daher müssen wir dieses hier zurücksetzen)
  display.setFont(NULL);
  //Textgröße 1
  display.setTextSize(1);
  //Schriftfarbe Weiß
  display.setTextColor(SH110X_WHITE);
  //setzen des Cursors
  display.setCursor(10, 8);
  //schreiben des Datums an die Cursorposition
  display.println(datum);
  //setzen des Cursors
  display.setCursor(90, 8);
  //schreiben der Uhrzeit an die Cursorposition
  display.println(zeit);
  //Absenden der Daten an das Display
  //dieser Aufruf ist sehr wichtig, ohne diesen werden keine Daten angezeigt
  display.display();
}

//Funktion zum Anzeigen des Weckers
void displayTime(int stunden, int minuten) {
  //Wenn der Modus zum editieren des Alarms nicht aktiv ist, dann...
  if (!setAlarm) {
    //Zeichnen von gefüllten, schwarten Rechtecken
    display.fillRect(70, 55, 40, 3, SH110X_BLACK);
    display.fillRect(20, 55, 40, 3, SH110X_BLACK);
  }

  //ein schwarzes, gefülltes Rechteck über die Felder
  //für Stunden & Minuten zeichnen
  display.fillRect(20, 22, 40, 30, SH110X_BLACK);
  display.fillRect(70, 22, 40, 30, SH110X_BLACK);

  //setzen der Schriftart
  display.setFont(&FreeSans18pt7b);
  //setzen der Schriftgröße 1
  display.setTextSize(1);
  //setzen der Schriftfarbe Weiß
  display.setTextColor(SH110X_WHITE);

  //Wenn der Wert der Stunden kleiner 10 ist,
  //dann wird der Text um eine Stelle eingerückt
  display.setCursor(stunden < 10 ? 40 : 20, 51);
  display.println(stunden);
  display.setCursor(60, 51);
  display.println(":");

  //Formatieren der Minuten mit führender Null
  char minutes[2];
  sprintf(minutes, "%02d", minuten);

  display.setCursor(70, 51);
  display.println(minutes);
  display.display();
}

//Funktion zum zeichnen eines kleinen weißen Rechtecks
//wenn der Wecker eingestellt wird, anhand dieses Rechtecks
//kann der Benutzer erkennen welcher Bestandteil der Zeit gerade
//bearbeitet wird.
void changeAlarm() {
  if (alarmTimeIndex == 0) {
    display.fillRect(20, 55, 40, 3, SH110X_WHITE);
    display.fillRect(70, 55, 40, 3, SH110X_BLACK);
  } else if (alarmTimeIndex == 1) {
    display.fillRect(70, 55, 40, 3, SH110X_WHITE);
    display.fillRect(20, 55, 40, 3, SH110X_BLACK);
  }
  display.display();
}

//Funktion zum anzeigen des Textes "!! Alarm !!" auf dem Display
void showAlarmMsg() {
  display.fillRect(5, 23, 118, 40, SH110X_BLACK);
  display.setFont(&FreeSerif12pt7b);
  display.setTextSize(1);
  display.setTextColor(SH110X_WHITE);
  display.setCursor(12, 50);
  display.println("!! Alarm !!");
  display.display();
}

//Diese Funktion wird fortwährend ausgeführt
void loop() {
  //speichern der aktuellen Millisekunden seitdem der Mikrocontroller
  //gestartet wurde
  unsigned long currentMillis = millis();
  //Wenn der Zeitpunkt der nächsten Ausführung erreicht wurde, dann...
  if ((lastAction + PAUSE) < currentMillis) {
    //abspeichern der aktuellen Millisekunden
    lastAction = currentMillis;
    //aktualisieren der Zeit auf dem Display
    updateTime();

    //prüfen ob der Alarm aktiviert werden soll
    rtcDS1302.updateTime();
    int currentStunden = rtcDS1302.hours;
    int currentMinuten = rtcDS1302.minutes;
    if ((currentStunden == stunden && currentMinuten == minuten)) {
      isAlarmActive = true;
      digitalWrite(relaisPin, LOW);
      showAlarmMsg();
    }
  }

  //auslesen der aktuellen Drehrichtung des Drehreglers / Rotary Encoder
  char currentPosition = rotary.process();
  //Wenn der Drehregler im Uhrzeigersinn gedreht wird und der Wecker eingestellt wird, dann...
  if (currentPosition == rotary.clockwise() && setAlarm) {
    //Nur wenn der Wert der Stunden größer 0 ist einen abziehen
    if (alarmTimeIndex == 0 && tempStunden > 0) {
      tempStunden = tempStunden - 1;
    } else if (alarmTimeIndex == 1 && tempMinuten > 0) {
      tempMinuten = tempMinuten - 1;
    }
    //einen Ton abspielen
    playKeyTone();
    //anzeigen des neuen Wertes
    displayTime(tempStunden, tempMinuten);
  } else if (currentPosition == rotary.counterClockwise() && setAlarm) {
    //Wenn die Drehrichtung gegen den Uhrzeigersinn ist und der Wecker eingestellt wird, dann...
    if (alarmTimeIndex == 0 && tempStunden < 23) {
      tempStunden = tempStunden + 1;
    } else if (alarmTimeIndex == 1 && tempMinuten < 59) {
      tempMinuten = tempMinuten + 1;
    }
    playKeyTone();
    displayTime(tempStunden, tempMinuten);
  }

  //Der mittlere Taster des Drehreglers dient zum deaktivieren des Alarms UND
  //zum wechseln zwischen Stunde & Minute
  if (rotary.buttonPressedReleased(20)) {
    //Wenn der Alarm aktiviert ist, dann...
    if (isAlarmActive) {
      isAlarmActive = false;
      digitalWrite(relaisPin, HIGH);
      display.fillRect(5, 23, 118, 40, SH110X_BLACK);
      displayTime(stunden, minuten);
      //An diesem Punkt wird die Funktion verlassen!
      return;
    }

    //Wenn der Wecker nicht eingestellt wird, dann
    if (!setAlarm) {
      //Wecker wird eingestellt
      setAlarm = true;
      changeAlarm();
      playKeyTone();
    } else {
      //Wechseln zwischen den Feldern Stunde & Minute
      alarmTimeIndex = alarmTimeIndex == 0 ? 1 : 0;
      changeAlarm();
      playKeyTone();
    }
  }

  //Wenn die BACK Taste betätigt wird und der Wecker eingestellt wird, dann...
  if ((digitalRead(backPin) == LOW) && setAlarm) {
    //überschreiben der gewählten Zeiten mit den vorherigen Werten
    tempStunden = stunden;
    tempMinuten = minuten;
    //deaktivieren des Modus zum einstellen des Weckers
    setAlarm = false;
    //eine kleine Pause von 150 ms. um den Taster zu entprellen
    delay(150);
    //anzeigen der Stunden & Minuten auf dem Display
    displayTime(stunden, minuten);
    //abspielen eines Tones
    playKeyTone();
  } else if ((digitalRead(backPin) == LOW) && !setAlarm) {
    showAlarmMsg();
  }

  //Wenn die Taste CONFIRM betätigt wird und der Wecker eingestellt wird, dann...
  if ((digitalRead(confirmPin) == LOW) && setAlarm) {
    //überschreiben der Werte für Stunde & Minute mit den gewählten Einstellungen
    stunden = tempStunden;
    minuten = tempMinuten;
    setAlarm = false;
    delay(150);
    displayTime(stunden, minuten);
    playKeyTone();
  }
}

Schreibe einen Kommentar Antworten abbrechen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Fragen oder Feedback?

Du hast eine Idee, brauchst Hilfe oder möchtest Feedback loswerden?
Support-Ticket erstellen

Newsletter abonnieren

Bleib auf dem Laufenden: Erhalte regelmäßig Updates zu neuen Projekten, Tutorials und Tipps rund um Arduino, ESP32 und mehr – direkt in dein Postfach.

Jetzt Newsletter abonnieren

Unterstütze meinen Blog

Wenn dir meine Inhalte gefallen, freue ich mich über deine Unterstützung auf Tipeee.
So hilfst du mit, den Blog am Leben zu halten und neue Beiträge zu ermöglichen.

draeger-it.blog auf Tipeee unterstützen

Vielen Dank für deinen Support!
– Stefan Draeger

Kategorien

Tools

  • Unix-Zeitstempel-Rechner
  • ASCII Tabelle
  • Spannung, Strom, Widerstand und Leistung berechnen
  • Widerstandsrechner
  • 8×8 LED Matrix Tool
  • 8×16 LED Matrix Modul von Keyestudio
  • 16×16 LED Matrix – Generator

Links

Blogverzeichnis Bloggerei.de TopBlogs.de das Original - Blogverzeichnis | Blog Top Liste Blogverzeichnis trusted-blogs.com

Stefan Draeger
Königsberger Str. 13
38364 Schöningen

Tel.: 01778501273
E-Mail: info@draeger-it.blog

Folge mir auf

  • Impressum
  • Datenschutzerklärung
  • Disclaimer
  • Cookie-Richtlinie (EU)
©2025 Technik Blog | Built using WordPress and Responsive Blogily theme by Superb
Cookie-Zustimmung verwalten
Wir verwenden Technologien wie Cookies, um Geräteinformationen zu speichern und/oder darauf zuzugreifen. Wir tun dies, um das Surferlebnis zu verbessern und um personalisierte Werbung anzuzeigen. Wenn Sie diesen Technologien zustimmen, können wir Daten wie das Surfverhalten oder eindeutige IDs auf dieser Website verarbeiten. Wenn Sie Ihre Zustimmung nicht erteilen oder zurückziehen, können bestimmte Funktionen beeinträchtigt werden.
Funktional Immer aktiv
Die technische Speicherung oder der Zugang ist unbedingt erforderlich für den rechtmäßigen Zweck, die Nutzung eines bestimmten Dienstes zu ermöglichen, der vom Teilnehmer oder Nutzer ausdrücklich gewünscht wird, oder für den alleinigen Zweck, die Übertragung einer Nachricht über ein elektronisches Kommunikationsnetz durchzuführen.
Vorlieben
Die technische Speicherung oder der Zugriff ist für den rechtmäßigen Zweck der Speicherung von Präferenzen erforderlich, die nicht vom Abonnenten oder Benutzer angefordert wurden.
Statistiken
Die technische Speicherung oder der Zugriff, der ausschließlich zu statistischen Zwecken erfolgt. Die technische Speicherung oder der Zugriff, der ausschließlich zu anonymen statistischen Zwecken verwendet wird. Ohne eine Vorladung, die freiwillige Zustimmung deines Internetdienstanbieters oder zusätzliche Aufzeichnungen von Dritten können die zu diesem Zweck gespeicherten oder abgerufenen Informationen allein in der Regel nicht dazu verwendet werden, dich zu identifizieren.
Marketing
Die technische Speicherung oder der Zugriff ist erforderlich, um Nutzerprofile zu erstellen, um Werbung zu versenden oder um den Nutzer auf einer Website oder über mehrere Websites hinweg zu ähnlichen Marketingzwecken zu verfolgen.
Optionen verwalten Dienste verwalten Verwalten von {vendor_count}-Lieferanten Lese mehr über diese Zwecke
Einstellungen anzeigen
{title} {title} {title}