Kaufempfehlung Starter Kit

Als Geschenk an Deine Frau könntest Du mit diesem Programm und einem Servo eine Blume öffnen lassen:

const byte cols = 20;                               // columns/characters per row
const byte rows = 4;                                // how many rows
const byte addr = 0x27;                             // set the LCD address to 0x3F or 0x27
#include <Wire.h>                                   // needed for the I2C interface
#include <NoiascaLiquidCrystal.h>                   // download library from https://werner.rothschopf.net/202009_arduino_liquid_crystal_intro.htm 
#include <NoiascaHW/lcd_PCF8574.h>                  // include the proper IO interface
LiquidCrystal_PCF8574 lcd(Wire, addr, cols, rows);  // create lcd object - with support of special characters

#include <MobaTools.h>
MoToTimer blumenZeitgeber;                          // erzeuge Zeitgeberobjekt
MoToServo blumenServo;                              // erzeuge Servoobjekt
const byte servoWinkelOffen = 160;                  // Winkel der geöffneten Blume
const byte servoWinkelGeschlossen = 20;             // Winkel der geschlossenen Blume
const uint32_t zeitWinkelOffen = 4000;              // Zeit in ms, wie lange die Blume geöffnet bleibt
const byte blumenTasterPin = 7;                     // Taster zum Starten der Bewegung
const byte servoPin =  8;                           // Anschluß für den Servo

void setup()
{
  Wire.begin();                                     // start I2C library
  lcd.begin();                                      // initialize the LCD
  lcd.backlight();                                  // turn on backlight

  pinMode(LED_BUILTIN, OUTPUT);                     // eingebaute LED
  pinMode(blumenTasterPin, INPUT_PULLUP);           // schaltet nach GND, so ist kein externer pullup Widerstand am Taster erforderlich

  blumenServo.attach(servoPin);                     // verwendeter Pin
  blumenServo.setSpeed( 5 );                        // Verfahrgeschwindigkeit in 0,5μs Einheiten einstellen
  blumenServo.write(servoWinkelGeschlossen);        // Startposition
}

void herzschlag()                                   // ein gleichmäßiges Blinken zeigt eine blockadearme Programmierung
{
  static uint32_t vorhin = 0;                       // Zeitmerker
  if (millis() - vorhin >= 111)                     // Zeitintervall in ms abgelaufen?
  {
    vorhin = millis();                              // Zeitmerker mit der aktuellen Zeit stellen
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));  // eingebaute LED blinkt als "Herzschlag"
  }
}

void anzeige(const byte zeile, const char * txt)    // übergebener Text wird in der gewünschten LCD-Zeile angezeigt
{
  lcd.setCursor(0, zeile);                          // Schreibposition wählen
  lcd.print( F("                    ") );           // Zeile löschen
  lcd.setCursor(0, zeile);                          // Schreibposition wählen
  lcd.print( txt );                                 // Text anzeigen
}

void loop() {
  static byte schritt = 0;                          // Schritt der Schrittkette

  switch (schritt)                                  // gehe zum aktuellen Schritt
  {
    case 0:                                         // Starttext ausgeben
      if ( !blumenServo.moving() )                  // wenn die Servobewegung beendet ist
      {
        anzeige(0, "Blume geschlossen");
        anzeige(1, "Tastendruck erwartet");
        schritt++;                                  // zum nächsten Schritt
      }
      break;
    case 1:                                         // nach Tastendruck Bewegung starten
      if ( !digitalRead(blumenTasterPin) )          // Taste gedrückt?
      {
        anzeige(0, "Taste gedrückt");
        anzeige(1, "Blume öffnet");
        blumenServo.write(servoWinkelOffen);        // Blume öffnet langsam
        schritt++;                                  // zum nächsten Schritt
      }
      break;
    case 2:                                         // nach Bewegungsende Öffnungszeit starten
      if ( !blumenServo.moving() )                  // Bewegung beendet?
      {
        anzeige(0, "Blume geöffnet");
        anzeige(1, "");
        blumenZeitgeber.setTime( zeitWinkelOffen ); // Öffnungszeit starten
        schritt++;                                  // zum nächsten Schritt
      }
      break;
    case 3:                                         // nach Öffnungszeitende Blume schließen
      if ( !blumenZeitgeber.running() )             // Öffnungszeit abgelaufen
      {
        anzeige(0, "Zeit abgelaufen");
        anzeige(1, "Blume schließt");
        blumenServo.write(servoWinkelGeschlossen);  // Blume schließt langsam
        schritt = 0;                                // zurück zum ersten Schritt
      }
      break;
    default:                                        // unerlaubter Schritt, sollte nie erreicht werden
      schritt = 0;                                  // zurück zum ersten Schritt
      break;
  }
  herzschlag();
}

@MicroBahner: getestet mit MobaTools-Development2.5.0 ohne Probleme!