Zeit­er­fas­sung mit RFID und SD-Karten-Modul

// benötigte Bibliotheken einbinden
#include "MFRC522.h"
#include "SPI.h"
#include "SdFat.h"
#include "RTClib.h"
#include "SSD1306Ascii.h"
#include "SSD1306AsciiWire.h"

// Name des RTC-Moduls (rtc)
RTC_DS3231 rtc; 

// Adresse des OLED-Displays
#define I2C_ADDRESS 0x3C

// Name des OLED-Displays festlegen
SSD1306AsciiWire oled;

// Bezeichnung der SD-Karte
SdFat SD;

// Bezeichnung der CSV-Datei
File Zeiterfassung;

// Anschlüsse RFID definieren
#define SDA 7
#define RST 9

// RFID-Empfänger benennen und Datenpins zuordnen
MFRC522 mfrc522(SDA, RST);

// Daten-Pin SD-Karte
int DatenPin = 10;

// Trennzeichen für die CSV-Datei
const String TrennZeichen = ",";

String Mitarbeiter;

void setup() 
{
  Serial.begin(9600);
  SPI.begin();

  // OLED mit 128x64 Pixeln starten
  Wire.begin();
  oled.begin(&Adafruit128x64, I2C_ADDRESS);

  // Schriftart festlegen
  oled.setFont(Arial14);
  oled.println(F("Zeiterfassung"));

  // Initialisierung des RFID-Empfängers
  mfrc522.PCD_Init();

  /*
    wenn Datum und Zeit nicht korrekt -> Datum/Zeit setzen
    Jahr, Monat, Tag, Stunde, Minute, Sekunde
    Beispiel:  2022 August 31. 10 Uhr 30 Minuten 30 Sekunden
    rtc.adjust(DateTime(2022, 8, 31, 10, 31, 30));
 */
  // RTC-Modul starten
  rtc.begin();

  // SD-Karte starten
  if (!SD.begin(DatenPin)) 
  {
    Serial.println(F("Initialisierung fehlgeschlagen!"));
  } 
  else Serial.println(F("SD-Karte gestartet!"));

  // rtc.now() -> aktuelle Zeit holen
  DateTime aktuell = rtc.now();

  // Format des Datums festlegen
  char Datum[] = "DD.MM.YYYY";

  // Datum in Zeichenkette (String) umwandeln und anzeigen
  Serial.print(aktuell.toString(Datum));

  // Format der Zeitangabe festlegen
  char Zeit[] = "hh:mm:ss";

  // Zeitangabe in Zeichenkette (String) umwandeln und anzeigen
  Serial.print(aktuell.toString(Zeit));
}

void loop() 
{  
  // vom RFID ermittelter Wert der Karte als Folge von Dezimalzahlen
  String WertDEZ;

  // String Mitarbeiter löschen, damit falsche Karte erkannt wird
  Mitarbeiter = "";

  // Wenn keine Karte in Reichweite ist ..
  if (!mfrc522.PICC_IsNewCardPresent()) 
  {
    // .. wird die Abfrage wiederholt.
    return;
  }

  // Wenn kein RFID-Sender ausgewählt wurde ..
  if (!mfrc522.PICC_ReadCardSerial()) 
  {
    // .. wird die Abfrage wiederholt.
    return;
  }
  Serial.println(F("Karte entdeckt!"));

  // Dezimal-Werte in String WertDEZ schreiben
  for (byte i = 0; i < mfrc522.uid.size; i++) 
  {
    WertDEZ = WertDEZ + String(mfrc522.uid.uidByte[i], DEC) + " ";
  }

  // dezimalen Wert anzeigen
  Serial.println("Wert in dezimal: " + WertDEZ);

  // Leerzeichen am Ende entfernen
  WertDEZ.trim();

  /*
    Karten abfragen und Namen der Mitarbeiter*innen zuordnen
    Dezimal-Werte durch die eigenen Werte ersetzen
  */  
  if (WertDEZ == "195 106 18 23") Mitarbeiter = "Klaus Drolshagen";
  if (WertDEZ == "227 77 233 22") Mitarbeiter = "Eva Hilger";
  if (WertDEZ == "131 125 21 23") Mitarbeiter = "Claudia Kruse";

  /*
    Namen abfragen
    wenn (if) Mitarbeiter == Klaus Drolshagen oder (||) Mitarbeiter == Eva Hilger || . . 
    werden Die Daten angezeigt und in die Datei geschrieben
  */ 
  if (Mitarbeiter == "Klaus Drolshagen" || Mitarbeiter == "Eva Hilger" || Mitarbeiter == "Claudia Kruse") 
  {
    // Daten in die Datei schreiben
    DatenSchreiben();
  }

  // falsche Karte
  else 
  {
    Serial.println(F("Falsche Karte!"));
    oled.clear();
    oled.print(F("Falsche Karte!"));
  } 
  
  // Pause, damit die Daten nicht mehrfach in die Datei geschrieben werden
  delay(1000);
}

void DatenSchreiben() 
{
  // Meldungen im Seriellen Monitor
  Serial.println(F("Schreibe Daten in Zeiterfassung.csv ... "));

  // Name der Mitarbeiterin/des Mitarbeiters
  Serial.println("Mitarbeiter*in: " + Mitarbeiter);
  Serial.println(F("-----------------------------"));

  // rtc.now() -> aktuelle Zeit holen
  DateTime aktuell = rtc.now();
  char Datum[] = "DD.MM.YYYY ";

  // Datum in Zeichenkette (String) umwandeln und anzeigen
  Serial.print(aktuell.toString(Datum));

  // Format der Zeitangabe festlegen
  char Zeit[] = "hh:mm:ss";

  // Zeitangabe in Zeichenkette (String) umwandeln und anzeigen
  Serial.println(aktuell.toString(Zeit));

  // Ausgabe OLED
  oled.clear();
  oled.println(Mitarbeiter);
  oled.println(aktuell.toString(Datum));
  oled.println(aktuell.toString(Zeit));
  
  /*
    Zeiterfassung ist das Datei-Objekt
    FILE_WRITE -> Datei zum Schreiben öffnen
    wenn die Datei noch nicht existiert, wird sie neu erstellt
    ansonsten werden die neuen Daten ans Ende angehängt
  */
  Zeiterfassung = SD.open("Zeiterfassung.csv", FILE_WRITE);
  if (Zeiterfassung) 
  {
    // Überschrift nach jedem Datensatzwiederholen 
    Zeiterfassung.print(F("Mitarbeiter*in:"));
    Zeiterfassung.print(TrennZeichen);
    Zeiterfassung.print(F("Datum:"));
    Zeiterfassung.print(TrennZeichen);
    Zeiterfassung.print(F("Zeit"));
    Zeiterfassung.println();

    // Daten in die Datei schreiben: Mitarbeiter*in, Datum und Zeit
    // Werte durch Trennzeichen (,) trennen
    Zeiterfassung.print(Mitarbeiter);
    Zeiterfassung.print(TrennZeichen);
    Zeiterfassung.print(Datum);
    Zeiterfassung.print(TrennZeichen);
    Zeiterfassung.print(Zeit);
    Zeiterfassung.println();
    Zeiterfassung.println();
  }

  // Datei schließen
  Zeiterfassung.close();
  Serial.println(F("Speichern abgeschlossen."));
  Serial.println();
}

Letzte Aktualisierung:

Tem­pe­ra­tur mit DS18B20 (TO92) mes­sen auf OLED anzeigen

// benötigte Bibliotheken
#include "OneWire.h"
#include "DallasTemperature.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"

// Bildschirmgröße definieren
#define BildschirmBreite 128  
#define BildschirmHoehe 64  

#define OLED_RESET 4  

// Adresse: 0x3C oder 0x3D
#define Adresse 0x3c  

// Name des Displays und Startparameter
Adafruit_SSD1306 oled(BildschirmBreite, BildschirmHoehe, &Wire, OLED_RESET);

// Pin des Sensors an OneWire übergeben
#define ONE_WIRE_BUS 9

// oneWire-Instanz erstellen
OneWire oneWire(ONE_WIRE_BUS);

// oneWire-Instanz an den Sensor übergeben
DallasTemperature TemperaturSensor(&oneWire);

void setup()
{
  // Temperatursensor starten
  TemperaturSensor.begin();

   // OLED starten
  oled.begin(SSD1306_SWITCHCAPVCC, Adresse);
  oled.clearDisplay();

  // Schriftfarbe und -größe
  oled.setTextColor(WHITE);
  oled.setTextSize(3);

  // erweiterte Codepage (255 Zeichen)
  oled.cp437(true);
  Serial.begin(9600);
}

void loop()
{
  TemperaturSensor.requestTemperatures(); 
  
  // getTempCByIndex(0) -> 0 = 1. angeschlossener Sensor
  float TemperaturLesen = TemperaturSensor.getTempCByIndex(0);

  // überprüfen, ob das Lesen der Temperatur erfolgreich war
  if (TemperaturLesen != DEVICE_DISCONNECTED_C)
  {
    String Temperatur  = String(TemperaturLesen);

    // . in , umwandeln
    Temperatur.replace(".", ",");
   
    // Temperatur anzeigen
    oled.clearDisplay();
    oled.setCursor(0, 0);
    oled.print(Temperatur + "");

    // Sonderzeichen ° anzeigen
    oled.write(248);
    oled.write("C");
    oled.display();

    // kurzes delay zu Demozwecken
    delay(3000);

    // Ausgabe Serieller Plotter
    Serial.print("Temperatur:");
    Serial.print(Temperatur);
    Serial.println(",");
  }
  else
  {
    Serial.println("Temperatur nicht lesbar!");
  }
}

Letzte Aktualisierung:

Auto­ma­ti­sche Tür mit Hall-Sensoren

#include "Servo.h"
#include "Bounce2.h"

#include <U8g2lib.h>
U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

// geschlossene Schranke
#define SchrankeGeschlossenBreite 100
#define SchrankeGeschlossenHoehe 28
static unsigned char SchrankeGeschlossen[] = 
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x0f, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff,
  0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc,
  0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00,
  0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01,
  0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff,
  0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff,
  0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc,
  0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00,
  0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03,
  0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c,
  0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00,
  0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03,
  0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff,
  0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff,
  0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc,
  0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00,
  0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x01,
  0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff, 0xff,
  0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc, 0xff,
  0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00, 0xfc,
  0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03, 0x00,
  0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c, 0x03,
  0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00, 0x0c,
  0x03, 0x00, 0xfc, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0x03, 0x00,
  0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00
};

// offene Schranke
#define SchrankeOffenBreite 100
#define SchrankeOffenHoehe 50
static unsigned char SchrankeOffen[] = 
{
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xe0, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0xfc, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x80, 0xff, 0x87, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xf0, 0x7f, 0x80, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0xe0, 0xff, 0x01, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xfc, 0x3f, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x0f, 0x00, 0x00, 0x0e, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x0f, 0x00, 0x00, 0x0e, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x0e,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0x1f, 0x00, 0x00,
  0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x1f, 0x00,
  0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x3f,
  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0xff, 0xff,
  0x3f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x87, 0xff,
  0xff, 0x7f, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x80,
  0xff, 0xff, 0x7f, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x1f,
  0x00, 0xff, 0xff, 0x7f, 0x00, 0x80, 0x0f, 0x00, 0x00, 0x00, 0xc0, 0xff,
  0x03, 0x00, 0xff, 0xff, 0xff, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0xf8,
  0xff, 0x00, 0x00, 0xfe, 0xff, 0xff, 0x00, 0xfe, 0x0f, 0x00, 0x00, 0x80,
  0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0xff, 0xe0, 0xff, 0x01, 0x00, 0x00,
  0xf0, 0xff, 0xff, 0x01, 0x00, 0xfe, 0xff, 0xff, 0xfd, 0x3f, 0x00, 0x00,
  0x00, 0xfe, 0xff, 0xff, 0x01, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x07, 0x00,
  0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x7f, 0x00,
  0x00, 0x00, 0xfc, 0xff, 0xff, 0xff, 0x03, 0x00, 0xfc, 0xff, 0xff, 0x0f,
  0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0xf8, 0xff, 0xff,
  0x01, 0x00, 0x00, 0xf0, 0xff, 0xfc, 0xff, 0xff, 0x07, 0x00, 0xf8, 0xff,
  0x3f, 0x00, 0x00, 0x00, 0xff, 0x0f, 0xfc, 0xff, 0xff, 0x07, 0x00, 0xf0,
  0xff, 0x07, 0x00, 0x00, 0x00, 0xff, 0x01, 0xf8, 0xff, 0xff, 0x0f, 0x00,
  0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0xf8, 0xff, 0xff, 0x0f,
  0x00, 0xfc, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0xf8, 0xff, 0xff,
  0x0f, 0x80, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf0, 0xff,
  0xff, 0x1f, 0xf0, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xf0,
  0xff, 0xff, 0x1f, 0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
  0xe0, 0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
  0x00, 0xe0, 0xff, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x03, 0x00, 0xe0, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x03, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x07, 0x00, 0xc0, 0xff, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x07, 0x00, 0xc0, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x80, 0xff, 0x3f, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x80, 0xff, 0x07, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0xe0, 0xff, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0xfc, 0x1f, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x80, 0xff, 0x03,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0xf0, 0x7f,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xfe,
  0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
  0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0xff, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00
};

// Pins Hall-Sensoren
#define Sensor_1  8
#define Sensor_2  9

// Bounce starten
Bounce Start_1 = Bounce();
Bounce Start_2 = Bounce();

// Bezeichnung des Motors
Servo Motor;

void setup()
{
  pinMode(Sensor_1, INPUT_PULLUP);
  pinMode(Sensor_2, INPUT_PULLUP);

  // Sensoren zuordnen
  Start_1.attach(Sensor_1);
  Start_2.attach(Sensor_2);

  // Intervall festlegen
  Start_1.interval(20);
  Start_2.interval(20);

  // Motor dem Pin zuordnen
  Motor.attach(7);

  // Motor in "geschlossen"-Position fahren
  Motor.write(5);

  // u8g2 starten
  u8g2.begin();

  // Farbe weiß
  u8g2.setDrawColor(1);

  // Display nicht rotieren
  u8g2.setDisplayRotation(U8G2_R0);

  // geschlossene Schranke anzeigen
  u8g2.firstPage();
  do
  {
    u8g2.drawXBM(10, 20, SchrankeGeschlossenBreite, SchrankeGeschlossenHoehe, SchrankeGeschlossen);
  }
  while (u8g2.nextPage());
}

void loop()
{
  // Sensor für das Öffnen der Schranke abfragen
  if (Start_1.update())
  {
    if (Start_1.read() == LOW)
    {
      // offene Schranke anzeigen
      u8g2.firstPage();
      do
      {
        u8g2.drawXBM(20, 1, SchrankeOffenBreite, SchrankeOffenHoehe, SchrankeOffen);
      }
      while (u8g2.nextPage());

      // Schranke öffnen
      Motor.write(90);
    }
  }

  // Sensor für das Schlie0en der Schranke abfragen
  if (Start_2.update())
  {
    if (Start_2.read() == LOW)
    {
      {
        // geschlossene Schranke anzeigen
        u8g2.firstPage();
        do
        {
          u8g2.drawXBM(10, 20, SchrankeGeschlossenBreite, SchrankeGeschlossenHoehe, SchrankeGeschlossen);
        }
        while (u8g2.nextPage());

        // Schranke schließen
        Motor.write(5);
      }
    }
  }
}

Letzte Aktualisierung:

Gro­ve mp3-Player

#include "SoftwareSerial.h"
#include "MP3Player_KT403A.h"

// RX/TX festlegen
SoftwareSerial mp3(2, 3);

// Zuweisung nach Ablesen des Analogwerts Tastenpad
int Taster;

// gelesener Wert Tastenpad
int Analogwert;

void setup()
{
  // SoftwareSerial starten
  mp3.begin(9600);

  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial)
  {
    ;
  }

  delay(100);

  // SD-Karte zuweisen
  SelectPlayerDevice(0x02);

  // Lautstärke setzen (14 bis 30)
  SetVolume(20);             
  
  Serial.println("Steuerung:");
  Serial.println("------------------");
  Serial.println("a -> alle abspielen");
  Serial.println("n -> folgender Song");
  Serial.println("v -> vorheriger Song");
  Serial.println("a -> alle abspielen");
  Serial.println("p -> Pause");
  Serial.println("w -> weiter abspielen");
  Serial.println("a -> alle abspielen");
  Serial.println("+ -> lauter");
  Serial.println("- -> leiser");
}

void loop()
{
  // serielle Eingabe lesen
  char Kommando = 0;
  while (Serial.available())
  {
    Kommando = Serial.read();

    switch (Kommando)
    {
      case 'p':
        PlayPause();
        Serial.println("Pause");
        break;
        
      case 'w':
        PlayResume();
        Serial.println("Weiter");
        break;
        
      case 'n':
        PlayNext();
        Serial.println("Folgenden Song abspielen");
        break;
        
      case 'z':
        PlayPrevious();
        Serial.println("Vorherigen Song abspielen");
        break;
        
      case 'a':
        PlayLoop();
        Serial.println("alle Songs spielen");
        break;
        
      case '+':
        IncreaseVolume();
        Serial.println("lauter");
        break;
        
      case '-':
        DecreaseVolume();
        Serial.println("leiser");
        break;
        
      default:
        break;
    }
  }

  // gedrückte Taste abfragen
  Taster = Tasterabfrage();

  // Taste links -> voheriger Titel
  if (Taster == 1)
  {
    PlayPrevious();
    Serial.println("Vorherigen Song abspielen");
  }

  // Taste oben Mitte -> lauter
  if (Taster == 2)
  {
    IncreaseVolume();
    Serial.println("lauter");
  }

  // Taste unten Mitte -> leiser
  if (Taster == 3)
  {
    DecreaseVolume();
    Serial.println("leiser");
  }

  // Taste rechts -> nächster Titel
  if (Taster == 4)
  {
    PlayNext();
    Serial.println("Folgenden Song abspielen");
  }
  
  // Taste außen -> Pause
  if (Taster == 5)
  {
    PlayPause();
    Serial.println("Pause");
  }
}

int Tasterabfrage() 
{
  int Analogwert = analogRead(A0);

  // kurzes delay() -> doppelten Tastendruck so weit wie möglich verhindern
  delay(200);
  // Serial.println(Analogwert);

  /* für die Abfrage von Wertebereichen muss
     A0 gibt je nach Taster einen Wert aus
     über den Seriellen Monitor wird dieser Wert angezeigt
     und kann dann eventuell angepasst werden
  */
  switch (Analogwert) {
    case 0 ... 20:
      Taster = 1;
      break;
      
    case 30 ... 60:
      Taster = 2;
      break;
      
    case 70 ... 120:
      Taster = 3;
      break;
      
    case 150 ... 200:
      Taster = 4;
      break;
      
    case 300 ... 400:
      Taster = 5;
      break;
      
    default:
      return 0;
  }

  // gedrückten Taster zurückgeben
  return Taster;
}

Letzte Aktualisierung:

Tür­öff­ner RFID

// eingebaute Bibliothek einbinden
#include "Servo.h"

// RFID-Bibiothek hinzufügen
#include "MFRC522.h"

// Anschlüsse definieren
#define SDA 10
#define RST 9

// Schranke nach Betreten wieder schließen
bool Status = false;

// RFID-Empfänger benennen
MFRC522 mfrc522(SDA, RST);

// Bezeichnung des Motors
Servo Motor;

void setup()
{
  // Pin des Motors zuordnen
  Motor.attach(7);
  Serial.begin(9600);

  SPI.begin();

  // Initialisierung des RFID-Empfängers
  mfrc522.PCD_Init();

  // Motor in "geschlossen"-Position fahren
  Motor.write(5);
}

void loop()
{
  String WertHEX;
  String WertDEZ;

  // Wenn keine Karte in Reichweite ist ..
  if (!mfrc522.PICC_IsNewCardPresent())
  {
    // .. wird die Abfrage wiederholt.
    return;
  }

  // Wenn kein RFID-Sender ausgewählt wurde ..
  if (!mfrc522.PICC_ReadCardSerial())
  {
    // .. wird die Abfrage wiederholt.
    return;
  }

  Serial.println(F("  Karte entdeckt!"));

  // HEX-Werte/Dezimal-Werte in Strings schreiben
  for (byte i = 0; i < mfrc522.uid.size; i++)
  {
    WertHEX = WertHEX + String(mfrc522.uid.uidByte[i], HEX) + " ";
    WertDEZ = WertDEZ + String(mfrc522.uid.uidByte[i], DEC) + " ";

    // Kleinbuchstaben des HEX-Wertes in Großbuchstaben umwandeln
    WertHEX.toUpperCase();
  }

  Serial.println();

  // hexadezimal/dezimal anzeigen
  Serial.println("  Wert in hexadezimal: " + WertHEX);
  Serial.println("  Wert in dezimal: " + WertDEZ);

  // Leerzeichen am Ende entfernen
  WertDEZ.trim();

  // WertDEZ mit korrektem Wert vergleichen -> Schranke öffnen
  if (WertDEZ.compareTo("80 236 29 59") == 0)
  {
    Serial.println("  korrekte Karte -> Schranke \u00f6ffnen");
    Motor.write(90);
    Status = !Status;
  }

  if (WertDEZ.compareTo("80 236 29 59") == 0 && !Status)
  {
    Serial.println("  korrekte Karte/Zutritt erfolgt -> Schranke schlie\u00dfen");
    Motor.write(5);
  }

  // wenn die Karte falsch ist
  else if (WertDEZ.compareTo("80 236 29 59") != 0)
  {
    Motor.write(5);
    Serial.println("  falsche Karte -> Schranke geschlossen lassen");
    Status = false;
  }

  delay(500);
}

Letzte Aktualisierung:

LEDs mit einem Tas­ter steuern

#include "OneButton.h"

int TASTER = 13;

// Array für die LEDs
int LED[5] = {3, 4, 5, 6, 7};

// Name des Tasters
OneButton NameTaster(TASTER, true);

// LEDs sind beim Start ausgeschaltet
bool Status = LOW;

void setup()
{
  // LEDs als OUTPUT setzen
  for (int i = 0; i <= 5; i++)
  {
    pinMode(LED[i], OUTPUT);
  }

  pinMode(TASTER, INPUT_PULLUP);

  // Aktionen dem Modus des Tasters zuordnen
  NameTaster.attachClick(einKlick);
  NameTaster.attachDoubleClick(DoppelKlick);
  NameTaster.attachLongPressStop(langerDruckStopp);

  /*
    Anzahl der Millisekunden bei den jeweiligen Aktionen festlegen
    Standardwerte:
    PressTicks: 1000
    ClickTicks: 600
    DebounceTicks: 50
    wenn die Standardwerte gesetzt werden sollen
    können die nächsten Zeilen auskommentiert werden
  */
  NameTaster.setPressTicks(800);
  NameTaster.setClickTicks(400);
  NameTaster.setDebounceTicks(50);
}

void loop()
{
  // Taster alle 10 Millisekunden abfragen
  NameTaster.tick();
  delay(10);
}

void einKlick()
{
  /*
    Status == true (1) -> einschalten
    Status == false (0) -> ausschalten
    Status umkehren
  */
  Status = !Status;
  for (int i = 0; i <= 5; i++)
  {
    // aktuelle LED i ein- oder ausschalten
    digitalWrite(LED[i], Status);
  }
}

void DoppelKlick()
{
  for (int i = 0; i <= 4; i++)
  {
    // aktuelle LED i einschalten
    digitalWrite(LED[i], HIGH);
    delay(200);

    // aktuelle LED i ausschalten
    digitalWrite(LED[i], LOW);
  }

  // ...und zurück
  for (int i = 4; i >= 0; i --)
  {
    // aktuelle LED i einschalten
    digitalWrite(LED[i], HIGH);
    delay(200);

    // aktuelle LED i ausschalten
    digitalWrite(LED[i], LOW);
  }
}

void langerDruckStopp()
{
  // alle LEDs blinken 5-mal
  // d -> Anzahl der Durchläufe

  for (int d = 0; d <= 6; d++)
  {
    // einschalten
    for (int i = 0; i <= 4; i++)
    {
      digitalWrite(LED[i], HIGH);
    }
    delay(200);

    // ausschalten
    for (int i = 0; i <= 4; i++)
    {
      digitalWrite(LED[i], LOW);
    }
    delay(200);
  }
}

Letzte Aktualisierung:

Ampel mit Beschleu­ni­gungs­sen­sor ADXL335 schalten

enum Ampel
{
  // Startwert festlegen
  ROT = 5,
  GELB,
  GRUEN
};

/* 
  wenn der Sensor zur y-Achse zeigt
  letztes Signal rot  -> ROTGELB = true  -> Ampel zeigt rot und gelb
  letztes Signal grün -> ROTGELB = false -> Ampel zeigt nur gelb 
 */
bool ROTGELB = true;

void setup()
{
  for (int i = ROT; i <= GRUEN; i++)
  {
    pinMode(i, OUTPUT);
  }
  Serial.begin(9600);
}

void loop()
{
  // analoge Eingänge lesen
  int xAchse = analogRead(A0);
  int yAchse = analogRead(A1);
  int zAchse = analogRead(A2);

  // Sensor zeigt auf die x-Achse -> Ampel rot, ROTGELB = true
  if (xAchse > 400)
  {
    digitalWrite(GELB, LOW);
    digitalWrite(GRUEN, LOW);
    digitalWrite(ROT, HIGH);
    ROTGELB = true;
  }

  // Sensor zeigt auf die y-Achse
  // wenn ROTGELB = false -> nur die gelbe LED leuchtet
  if (yAchse > 400 && !ROTGELB)
  {
    digitalWrite(GRUEN, LOW);
    digitalWrite(ROT, LOW);
    digitalWrite(GELB, HIGH);
  }

  // wenn ROTGELB = true -> die rote und die gelbe LED leuchten
  if (yAchse > 400 && ROTGELB)
  {
    digitalWrite(GRUEN, LOW);
    digitalWrite(ROT, HIGH);
    digitalWrite(GELB, HIGH);
  }

  /* 
    Sensor zeigt auf die z-Achse
    ROTGELB muss auf false gesetzt werden, 
    damit bei Aktivierung des y-Achse nur die gelbe LED leuchtet
  */
  if (zAchse > 400 )
  {
    digitalWrite(ROT, LOW);
    digitalWrite(GELB, LOW);
    digitalWrite(GRUEN, HIGH);
    ROTGELB = false; 
  }

  delay(20);
}

Letzte Aktualisierung:

Fuß­ball­tipp

// die Mannschaften
// Größe der Arrays: muss als Konstante definiert werden
const byte AnzahlMannschaften = 18;

// Array wird benötigt, um zwei unterschiedliche Mannschaften zu bestimmen
int ZufallsZahlen[AnzahlMannschaften];

// Arrays für Punkte und Tore
int AnzahlPunkte[AnzahlMannschaften];
int AnzahlTore[AnzahlMannschaften];

// Array der Mannschaften
String Mannschaften[AnzahlMannschaften] =
{
  "Mainz 05", "RB Leipzig", "Arminia Bielefeld", "Union Berlin",
  "VFL Bochum", "VFL Wolfsburg", "Borussia Dortmund", "Bayern München",
  "Eintracht Frankfurt", "Hertha BSC", "Borussia Mönchengladbach",
  "1. FC Köln", "SC Freiburg", "Greuther Fürth",
  "Bayer Leverkusen", "FC Augsburg", "1899 Hoffenheim", "VFB Stuttgart"
};

// Anzahl der Tore Minimum/Maximum
int Minimum = 0;
int Maximum = 4;

void setup()
{
  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial);
  delay(1000);

  // Info
  Serial.println("Ergebnisse tippen: -> <s>");
  Serial.println("Gesamtpunkte anzeigen: -> <t>");
  Serial.println("-------------------------------------------");

  // Zufallsgenerator starten
  randomSeed(analogRead(A0));
}

void loop()
{
  // auf serielle Eingabe warten
  while (Serial.available() > 0)
  {
    // Eingabe im Seriellen Monitor lesen
    char Zeichen = Serial.read();
    {
      // Spielpaarung ziehen
      if (Zeichen == 's')
      {
        // 2 unterschiedliche Mannschaften bestimmen
        for (int i = 0; i < 2; i++)
        {
          /*
            die Mannschaft gilt solange als bereits gezogen
            bis in der for-Schleife nachgewiesen wird, dass sie neu ist
            und BereitsGezogen den Wert false hat
          */
          bool BereitsGezogen = true;
          while (BereitsGezogen)
          {
            // Zahl ziehen
            ZufallsZahlen[i] = random(0, AnzahlMannschaften);
            BereitsGezogen = false;
            /*
              Zufallszahl mit den bereits gezogenen Zahlen vergleichen
              i wird in der ersten for-Schleife hochgezählt
              alle bisherigen Zahlen (ii) werden mit den bisher gezogenen Zahlen
              (außer der gerade gezogenen) verglichen (ii < i)
              ist sie identisch, erhält BereitsGezogen den Wert true
              es wird erneut eine Zufallszahl bestimmt
              wenn die Zahl neu ist, (BereitsGezogen hat noch den Wert false)
              wird die while-Schleife verlassen und die nächste Zahl
              gezogen
            */
            for (int ii = 0; ii < i; ii++)
            {
              if (ZufallsZahlen[i] == ZufallsZahlen[ii]) BereitsGezogen = true;
            }
          }
        }

        /*
          nach Aufruf der Funktion steht ein Array mit 2 Elementen zur Verfügung
          es beinhaltet die zufällig ausgewählten Mannschaften:
          ZufallsZahlen[0] und ZufallsZahlen[1]
          hiermit wird die Paarung des Spiels bestimmt
        */
        Serial.print(Mannschaften[ZufallsZahlen[0]]);
        Serial.print(" - " + Mannschaften[ZufallsZahlen[1]]);

        // Anzahl der Tore bestimmen
        AnzahlTore[ZufallsZahlen[0]] = random(Minimum, Maximum);
        AnzahlTore[ZufallsZahlen[1]] = random(Minimum, Maximum);

        // Sieger ermitteln: Sieger erhält 3 Punkte
        // Sieger 1. Mannschaft
        if (AnzahlTore[ZufallsZahlen[0]] > AnzahlTore[ZufallsZahlen[1]])
        {
          AnzahlPunkte[ZufallsZahlen[0]] = AnzahlPunkte[ZufallsZahlen[0]] + 3;
        }

        // Sieger 2. Mannschaft
        else if (AnzahlTore[ZufallsZahlen[0]] < AnzahlTore[ZufallsZahlen[1]])
        {
          AnzahlPunkte[ZufallsZahlen[1]] = AnzahlPunkte[ZufallsZahlen[1]] + 3;
        }
        // unentschieden: beide Mannschaften 1 Punkt
        else if (AnzahlTore[ZufallsZahlen[0]] == AnzahlTore[ZufallsZahlen[1]])
        {
          AnzahlPunkte[ZufallsZahlen[0]] = AnzahlPunkte[ZufallsZahlen[0]] + 1;
          AnzahlPunkte[ZufallsZahlen[1]] = AnzahlPunkte[ZufallsZahlen[1]] + 1;
        }

        // Ergebnis anzeigen
        Serial.print(" ");
        Serial.print(AnzahlTore[ZufallsZahlen[0]]);
        Serial.print(" : ");
        Serial.println(AnzahlTore[ZufallsZahlen[1]]);

        // Punkte anzeigen
        Serial.print(Mannschaften[ZufallsZahlen[0]]);
        Serial.println(": " + String(AnzahlPunkte[ZufallsZahlen[0]]) + " Punkt(e)");
        Serial.print(Mannschaften[ZufallsZahlen[1]]);
        Serial.println(": " + String(AnzahlPunkte[ZufallsZahlen[1]]) + " Punkt(e)");
      }

      // Gesamtpunkte anzeigen
      if (Zeichen == 't')
      {
        // Mannschaften nach Anzahl der Punkte sortieren
        ZahlenSortieren();
        Serial.println("-------------------------------------------");
        // Mannschaften in der Reihenfolge der Punkte anzeigen
        // die Mannschaft mit den meisten Punkte zuerst
        for (int i = AnzahlMannschaften - 1; i >= 0; i--)
        {
          Serial.print(Mannschaften[i]);
          Serial.println(": " + String(AnzahlPunkte[i]) + " Punkt(e)");
        }
        Serial.println("-------------------------------------------");
      }
    }
  }
}

void ZahlenSortieren()
{
  // unsortierten Bereich des Arrays durchlaufen
  for (int i = 0; i < (AnzahlMannschaften - 1); i++)
  {
    // bei jedem Durchlauf wird das jeweils letzte Element weggelassen
    for (int ii = 0; ii < (AnzahlMannschaften - (i + 1)); ii++)
    {
      /*
        wenn die aktuelle Zahl größer als die nachfolgende Zahl ist
        -> aktuelle AnzahlPunkte temporär speichern
        -> aktuelle Mannschaft temporär speichern
        -> AnzahlPunkte/Mannschaften vertauschen
        -> temporäre AnzahlPunkte/Mannschaften
           den nachfolgenden AnzahlPunkte/Mannschaften zuweisen
      */
      if (AnzahlPunkte[ii] > AnzahlPunkte[ii + 1])
      {
        int zwischengespeicherteZahl = AnzahlPunkte[ii];
        String zwischengespeicherteMannschaft = Mannschaften[ii];
        AnzahlPunkte[ii] = AnzahlPunkte[ii + 1];
        Mannschaften[ii] = Mannschaften[ii + 1];
        AnzahlPunkte[ii + 1] = zwischengespeicherteZahl;
        Mannschaften[ii + 1] = zwischengespeicherteMannschaft;
      }
    }
  }
}

Wür­feln ein­stel­li­ge 7-Seg­ment-Anzei­ge mit Fernbedienung

#include "IRremote.hpp"

byte Zahlen[6] = {
  B01100000,  // 1
  B11001101,  // 2
  B11101001,  // 3
  B01100011,  // 4
  B10101011,  // 5
  B10101111,  // 6
};

int EmpfaengerPin = 11;
int LAUTSPRECHER = 10;

void setup() 
{
  // Pins auf OUTPUT setzen
  for (int i = 2; i <= 9; i++) {
    pinMode(i, OUTPUT);
  }
  IrReceiver.begin(EmpfaengerPin);

  // Zufallsgenerator starten
  Serial.begin(9600);
  randomSeed(analogRead(A0));
}

void loop()
{
  /*
    der Bereich der Zahlen 1 bis 6
    als oberer Wert muss 7 angegeben werden,
    weil immer nach unten gerundet wird
  */
  int Minimum = 1;
  int Maximum = 7;

  // Daten lesen -> beliebige Taste gedrückt
  if (IrReceiver.decode())
  {
    /*
      printIRResultMinimal zeigt die verwendete Taste
      P = Protokoll
      C = Kommando in Hex
      
      auskommentiert lassen wenn die Tastencodes bekannt sind
    
      Serial.print(F("P = Protokoll C = Taste hexadezimal: "));
      IrReceiver.printIRResultMinimal(&Serial);
      Serial.print(F(" Dezimal: "));
      Serial.println(IrReceiver.decodedIRData.command);
    */
    delay(100);

    // nächsten Wert lesen
    IrReceiver.resume();

    // Würfeleffekt
    // in schneller Folge werden 10 Zufallszahlen angezeigt
    for (int i = 0; i < 10; i++)
    {
      // gewürfelte Zahl anzeigen
      byte Zahl = ZufallsZahl(Minimum, Maximum);
      delay(100);
      ZahlZeigen(Zahlen[Zahl - 1]);

    }
    tone(LAUTSPRECHER, 1000, 10);
  }
}

void ZahlZeigen(byte ArrayZahl)
{
  // Bits des Arrays ArrayZahl prüfen
  // von Pin 2 bis Pin 9 durchlaufen
  for (int i = 2; i <= 9; i++) {
    /*
      vergleicht das Byte ArrayZahl mit dem Byte B10000000
      befindet sich an beiden Positionen eine 1
      das Ergebnis der Prüfung ist also nicht 0
      -> Segment einschalten
      ist eine der Positionen eine 0
      das Ergebnis der Prüfung ist 0
      -> Segment ausschalten
      1 Bit nach links schieben -> nächstes Bit prüfen
      nach 8 Durchläufen sind alle Segmente (Pins) richtig geschaltet
    */
    if ((ArrayZahl & B10000000) != 0) digitalWrite(i, HIGH);
    else digitalWrite(i, LOW);
    ArrayZahl = ArrayZahl << 1;
  }
}

int ZufallsZahl(int Minimum, int Maximum)
{
  int Zahl = random(Minimum, Maximum);
  return Zahl;
}

Letzte Aktualisierung:

Pin-Ein­ga­be LCD Servo

#include "Adafruit_Keypad.h"
#include "Servo.h"
#include "LiquidCrystal_I2C.h"

LiquidCrystal_I2C lcd(0x27, 20, 4);

// Bezeichnung des Motors
Servo Motor;

// Größe des Tastenfeldes
// 3 Spalten
const byte SPALTEN = 3;

// 4 Zeilen
const byte REIHEN = 4;

// die Ziffern/Zeichen:
// Array 3 x 4
char Tasten[REIHEN][SPALTEN] =
{
  { '#', '0', '*' },
  { '9', '8', '7' },
  { '6', '5', '4' },
  { '3', '2', '1' }
};

// die Pins für die 3 Spalten
byte SpaltenPins[SPALTEN] = { 3, 4, 5 };

// die Pins für die 4 Zeilen
byte ReihenPins[REIHEN] = { 6, 7, 8, 9 };

// TastenFeld ⇒ Name des Keypads
// -> Zuordnung der Pins zu den REIHEN und SPALTEN des Arrays
Adafruit_Keypad Tastenfeld = Adafruit_Keypad(makeKeymap(Tasten), ReihenPins, SpaltenPins, REIHEN, SPALTEN);

String Vergleich;
String Pin;

// char-Array für die eingegebenen Zeichen
char Zeichen[5];

// Position im Array Zeichen
int Position = 0;

// Position der angezeigten Spalte LCD
int PositionSpalte = 0;

// Pin des Servos
int ServoPin = 12;

void setup()
{
  // Pin dem Servo zuordnen
  Motor.attach(ServoPin);

  // Tastenfeld starten
  Tastenfeld.begin();

  // LCD einschalten
  lcd.init();
  lcd.backlight();

  Serial.begin(9600);

  // auf serielle Verbindung warten
  while (!Serial) {
    ;
  }
  delay(500);

  // nur beim Start anzeigen
  Serial.println("Bitte 4-stelligen Pin eingeben:");
  Serial.println("Pin-Eingabe mit # abschlie\u00dfen");
  Serial.println("Korrektur mit * ");

  // Zufallsgenerator starten
  randomSeed(analogRead(A0));

  // neuen Pin erstellen
  neuerPin();

  // Servo in Ausgangsposition fahren
  Motor.write(0);
}

void loop()
{
  // gedrückte Taste lesen
  Tastenfeld.tick();

  while (Tastenfeld.available())
  {
    keypadEvent Taste = Tastenfeld.read();

    // wenn die Taste losgelassen wurde
    // Wert abgefragter Taste zu char umwandeln
    if (Taste.bit.EVENT == KEY_JUST_RELEASED)
    {
      lcd.setCursor(0, 0);
      lcd.print("Pin eingeben:      ");

      // Zeilen LCD löschen
      ZeileLoeschen(1);
      ZeileLoeschen(3);

      Motor.write(0);

      // eingegebenes Zeichen an der aktuellen Position speichern
      Zeichen[Position] = (char)Taste.bit.KEY;

      // Zeichen anzeigen
      Serial.print(Zeichen[Position]);

      lcd.setCursor(PositionSpalte, 2);
      lcd.print(Zeichen[Position]);

      // nächstes Zeichen -> Position erhöhen
      // Position Spalte LCD erhöhen
      Position++;
      PositionSpalte++;

      // Korrektur ASCII-Wert 42 = *
      if (Taste.bit.KEY == 42)
      {
        // char-Array Zeichen leeren
        for (int i = 0; i < sizeof(Zeichen); i++)
        {
          Zeichen[i] = NULL;
        }

        // Variablen zurücksetzen, Zeilen LCD löschen
        Position = 0;
        PositionSpalte = 0;
        ZeileLoeschen(0);
        ZeileLoeschen(2);

        Serial.println("\tKorrektur: ");
        lcd.setCursor(0, 0);

        lcd.print("Korrektur: ");
      }

      // Zeichen ASCII-Wert 35 = #
      if (Taste.bit.KEY == 35)
      {
        // char-Array in String umwandeln
        Vergleich = String(Zeichen);

        // letzte Zeichen des Strings sind 0 und # -> müssen entfernt werden
        Vergleich = Vergleich.substring(0, Vergleich.length() - 2);

        Serial.println();
        Serial.print(Vergleich);

        // Zeilen LCD löschen
        ZeileLoeschen(0);
        ZeileLoeschen(2);

        lcd.setCursor(0, 0);
        lcd.print("Pin: " + Vergleich + " ");

        // Eingabe mit Pin vergleichen
        if (Vergleich == Pin)
        {
          Serial.println("\korrekter Pin - Schranke \u00f6ffnen!");
          lcd.setCursor(0, 1);
          lcd.print("-> korrekter Pin!");
          delay(2000);
          lcd.setCursor(0, 1);
          lcd.print("Schranke \357ffnen!");
          Motor.write(90);
        }
        else
        {
          Serial.println("\tFalscher Pin - kein Zugriff");

          lcd.setCursor(0, 1);
          lcd.print("-> falscher Pin!");
        }

        // Variable zurücksetzen
        Position = 0;
        PositionSpalte = 0;

        // neuen Pin erstellen
        neuerPin();
      }
    }
  }
}

String neuerPin()
{
  // zufälligen PIN bestimmen
  Pin = "";
  Serial.println("---------------------------------------");

  for (int i = 0; i < sizeof(Zeichen) - 1; i++)
  {
    int Zahl = random(0, 10);
    Pin = Pin + String(Zahl);
  }

  // Pin anzeigen
  Serial.println("neuer Pin: " + Pin);

  lcd.setCursor(0, 3);
  lcd.print("neuer Pin: " + Pin);

  return Pin;
}

void ZeileLoeschen(int Zeile)
{
  for (int i = 0; i < 20; i++)
  {
    lcd.setCursor(i, Zeile);

    lcd.print(" ");
  }
}

Letzte Aktualisierung: