Millis() innerhalb void loop auf Null setzen

Hallo Arduino-Gemeinde,

ich hoffe ihr könnt mir vielleicht bei mein Problem helfen. Es betrifft in gewisser Weise das Thema switch-case, Funktionen und millis() in Kombination.

Ich habe vor ein Sketch abspielen zu lassen, dass im loop vier Funktionen abspielen lassen soll, wenn der Taster gedrückt wird. Wenn nicht, wird solange eine andere Funktion in einer Art Warteschleife abgespielt. Alle Funktionen, sowie Tasterabfrage, beinhalten switch-case, die per millis durchgespielt werden. Nach einer Minute soll quasi wieder zum Ursprung marschiert werden und darauf gewartet werden, dass der Taster gedrückt wird und daraufhin sollen die Funktionen wieder von vorne anfangen. Aktuell ist das Problem, dass, sobald der Taster wieder aktiviert wird, dort weiter gemacht wird, wo meine Funktionen bzw. die Aktoren gestoppt haben. Könnt ihr mir ein Vorschlag machen, wie ich die millis() am Ende eines Intervalls auf Null setzen kann?

Ich wäre um jede Hilfe dankbar!

Bis dahin beste Grüße und schönes WE!!

Ja, könnte ich!
Sehe aber keinen Sinn darin.

Ich bin mir sicher, dass man das erledigen kann, ohne den Millis Wert zu ändern.
Suche mal nach der Nachtwächter Erklärung.

1 Like

Warum ?

Um das Programm bzw. meine Funktionen wieder von vorne beginnen zu lassen. Aber ich habe gerade die Nachtwächter-Erklärung grob angeschaut. Ich versuche es mal damit.

Wenn Du uns Dein nicht funktionierendes Programm zeigst, können wir besser einschätzen, wo Du hinsichtlich Deiner Programmierkenntnisse stehst. Das ermöglicht eine gezieltere Hilfe.

Ich bin eher mittlerer Anfänger, was Arduino-Programmierung betrifft,...von daher ein bisschen Nachsicht.

Ich versuche es mit der Nachtwächter-Logik. Wenn ich damit nicht weiter komme, werde ich mal mein loop hier posten und kurz dazu was erläutern.

Was Dir vorschwebt, könnte man so realisieren, zaehler kannst Du auf 0 setzen:

uint32_t millisAlt;
uint32_t zaehler;

void setup() {
  Serial.begin(115200);
  delay(500);
  Serial.println("Start ...");
}

void loop() {
  if (millis() != millisAlt)
  {
    millisAlt = millis();
    zaehler++;
  }

  if (zaehler == 1000)
  {
    Serial.print(millis());
    Serial.print('\t');
    Serial.println(zaehler);
    zaehler = 0;
  }
}

Aber der "Nachtwächter" ist besser.

1 Like

Aha, willst du nicht auf Renés Antwort warten?

Ja doch, dauerte mir aber zu lange :rofl:

So, also irgendwie komme ich nicht weiter. Bin leider noch zu unerfahren :man_shrugging:. Ich bitte im Voraus um Entschuldigung für den Code-Chaos. Im Großen und Ganzen funktioniert mein Ablauf, nur leider, sobald den Taster wieder direkt drücke, macht mein loop bzw. machen meine Funktionen dort weiter, wo sie zuletzt aufgehört haben.

#include <Servo.h>
#include <FastLED.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>

#include <Fonts/FreeMonoBoldOblique12pt7b.h>
#include <Fonts/FreeSerif9pt7b.h>
#include <Fonts/Org_01.h>

#define NUM_LEDS  16
#define LED_PIN   6
#define TFT_DC 9
#define TFT_CS 10
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define COLOR_ORDER GRB
 
Adafruit_GC9A01A tft (TFT_CS, TFT_DC);

CRGB leds[NUM_LEDS];

uint8_t paletteIndex = 0;

int servopin = 7;
int tasterpin = 2;

int servotakt = 1;
int servopos = 90;


int Stufe;
int Instanz;
int Sequence;
int Lied;
int Anzeige;
int Tasterstatus = 0;

DEFINE_GRADIENT_PALETTE( fairygarden_gp ) {
    0,  55, 19,103,
   51,  95, 32,133,
  101, 167, 44,162,
  153, 125,182,237,
  204,  84,127,207,
  255,  19, 40,114};

CRGBPalette16 myPal = fairygarden_gp;

Servo Servo;

SoftwareSerial softwareSerial(3, 4);

const int wirePin = 4; 
const int endPin = 5;

DFRobotDFPlayerMini player;

unsigned long currentMillis;


unsigned long servoPreviousMillis = 0;
unsigned long tasterMillis = 0;
unsigned long millisLied = 0;

const unsigned long servoPeriod = 50;
const unsigned long servoPeriod2 = 75;
const unsigned long tasterPeriod = 100;
const unsigned long anzeigePeriod = 1000;
const unsigned long wartezeit = 5000;
const unsigned long Leuchten1 = 20000;
const unsigned long Leuchten2 = 25000;
const unsigned long Ablaufzeit = 60000;
const unsigned long millislied1warte = 16000;
const unsigned long millislied2warte = 32000;
const unsigned long millislied1 = 1000;
const unsigned long millislied2 = 1000;
const unsigned long interval = 50; 
const unsigned long interval2 = 50;
const unsigned long interval3 = 600;
const unsigned long intervalnext = 16000;
const unsigned long intervalnext2 = 33000;
const unsigned long displayTime = 50;


void setup() {

  Servo.attach(servopin);
  Servo.write(servopos);

  tft.begin();           
  tft.setRotation(1);     
  tft.fillScreen(GC9A01A_BLACK); 

  pinMode(tasterpin, INPUT_PULLUP);
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);

  softwareSerial.begin(9600);
  Serial.begin(115200);

  if (!player.begin(softwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true){
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }

Serial.println(F("DFPlayer Mini online."));
player.volume(3);  //Lautstärke auf Maximum (15)  

}

void loop() {

currentMillis = millis();
static unsigned long previousMillis = 0;

Tasterstatus = digitalRead(tasterpin);

switch(Instanz) {

  case 0:

  if(Tasterstatus == LOW) {
  Instanz = 1;
  tft.fillScreen(0x0000); 
  } else {
    Tasterwarten();
  }
  break;
  
  case 1:
  
  if(currentMillis - previousMillis >= Ablaufzeit) {
    Instanz = 0;
    previousMillis = currentMillis;
  
  } else {
  
  //Servomotor();
  //LEDRing();
  //Liedabspielen();
  Display();
  }
break;
}
  FastLED.show();
}



void Display() {
  
  switch(Anzeige) {

    case 0:

    static unsigned long displayanzeige = 0;

    //Displayhintergrund();

    tft.setFont(&FreeSerif9pt7b);
    tft.setCursor(70, 110);
    tft.setTextColor(random(0x0000, 0xF8FF));
    tft.setTextSize(2); 
    tft.print("Happy");
    tft.setCursor(5, 155);
    tft.setTextColor(random(0x0000, 0xF8FF));
    tft.setTextSize(2); 
    tft.print("Valentine's Day"); 
    tft.setFont(&FreeMonoBoldOblique12pt7b);
    tft.setCursor(63, 220);
    tft.setTextColor(GC9A01A_YELLOW);
    tft.setTextSize(2); 
    tft.print("Name");

    if (currentMillis - displayanzeige >= intervalnext) {
    
    tft.fillScreen(0x0000);
    Anzeige = 1;
    }
    break;

    case 1:

    if (currentMillis - displayanzeige >= intervalnext2) {
    displayanzeige = currentMillis;
    tft.fillScreen(0x0000);
    Anzeige = 0;
    
  } else {
    
    if (currentMillis - displayanzeige >= interval2) {

    drawHeart(tft.width()/2, tft.height()/2 - 20, GC9A01A_MAGENTA);

    if (currentMillis - displayanzeige >= interval3) {
    tft.fillScreen(0x0000); 
  }
  }
  }
  break;
}
}
.
.
.
.
.
void drawHeart(int x0, int y0, uint16_t color) {
    int size = 50; // Size of the heart

   // Calculate the vertices of the two triangles that form the bottom of the heart
   int x1 = x0 - size + 5;
   int y1 = y0 - 10;
   int x2 = x0 + size - 5;
   int y2 = y0 - 10;
   int x3 = x0;
   int y3 = y0 + size;

   // Draw two triangles to form the bottom of the heart
   tft.fillTriangle(x1, y1, x3, y3, x0, y0 - size/2, color);
   tft.fillTriangle(x0, y0 - size/2, x3, y3, x2, y2, color);

   // Draw two half-circles at the top of the heart
   tft.fillCircle(x0 - size/2, y0 - size/2, size/2, color);
   tft.fillCircle(x0 + size/2, y0 - size/2, size/2, color);
}


void Tasterwarten(){

static unsigned long anzeigezeit = 0;

if(currentMillis - anzeigezeit >= anzeigePeriod) {
  anzeigezeit = currentMillis;
  
  tft.fillScreen(0x0000); 
  tft.setCursor(50, 50); 
  tft.setFont(&FreeSerif9pt7b);
  tft.setTextColor(GC9A01A_WHITE); 
  tft.setTextSize(2); 
  tft.print("Press me!"); 
  tft.fillRect(107, 110, 26, 100, GC9A01A_WHITE);
  tft.fillTriangle(90,185,150,185,120,245, GC9A01A_WHITE);
  }

  FastLED.setBrightness(50);
  fill_solid(leds, NUM_LEDS, CRGB(48, 173, 10));


}


void Displayhintergrund() {

    static unsigned long displayanzeige1 = 0;

    if (currentMillis - displayanzeige1 >= interval) {
    displayanzeige1 = currentMillis;

    
    int x = random(SCREEN_WIDTH);
    int y = random(SCREEN_HEIGHT);
    int x2 = random(SCREEN_WIDTH);
    int y2 = random(SCREEN_HEIGHT);
    int rectSize = random(3, 7); 
    int rectSize2 = random(3, 7); 

    
    tft.fillRect(x, y, rectSize, rectSize, GC9A01A_WHITE);
    tft.fillRect(x2, y2, rectSize2, rectSize2, GC9A01A_WHITE);

    
    static unsigned long displayEndTime = currentMillis + displayTime;

    
    while (currentMillis < displayEndTime) {
    currentMillis = displayEndTime;
    }
    
    tft.fillRect(x, y, rectSize, rectSize, GC9A01A_BLACK);
    tft.fillRect(x2, y2, rectSize2, rectSize2, GC9A01A_BLACK);
  }

}

Die Funktionen Servomotor(), LEDRing() und Liedabspielen() habe ich mal weg gelassen, aber die Struktur ist die Selbe wie bei Display() (also switch-case Ablauf einschließlich currentMillis). Ich möchte lediglich, dass nach dem Intervall von einer Minute wieder alles vorne beginnt, wenn der Taster erneut gedrückt wird.

Nebenbei könnt ihr mir vielleicht Tipps geben, wo man sich mit Arduino-Programmierung, für Hobbyanwendungen, schlau machen kann, einschließlich die Benutzung elektronischen Bauteilen in Arduino-Projekten. Momentan wurschtle ich mich nur so lala durch.

Da gibt es 2 Möglichkeiten.

Entweder man strukturiert den Code entsprechend das er auf den Taster reagiert
oder
man macht die nicht so schöne Lösung.

Die geht so:

Eine Globale Variable deklarieren als Boolean . z.b. taste_getippt = false ;

Dann setzt du die Varible wenn der Taster gedrückt wurde auf TRUE.
Nun kannst du ÜBERALL im Code eine Abfrage machen z.b. so.

if (Taster_getippt == true) {
  taster_gedruckt = false;
  // mach was
}

Ist nicht schön aber funktioniert. Ähnliches mache ich z.b. wenn etwas via Timer/IRQ ausgelöst wird und der Code darauf reagieren muss.

Gruß

Pucki

Such hier im Forum nach Nacht Wechter wen das verstehst bau weiter

Hallo,

Die Arduino Referenz in der HIlfe geht eigentlich ja immer, und für Einsteiger finde ich das ganz gut
https://www.arduinoforum.de/referenz.php

Deine ganze Hardware habe ich nicht, daher mal was mit LEDs. Es soll nur das Grundprinzip zeigen:

Programm mit Schrittkette und Millis
#include <FastLED.h>
#define NUM_LEDS  16
#define LED_PIN   6
CRGB leds[NUM_LEDS];

const byte tasterpin = 2;
unsigned long currentMillis;

void setup()
{
  pinMode(tasterpin, INPUT_PULLUP);
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.show();
}

void loop()
{
  const unsigned long Ablaufzeit = 60000;
  currentMillis = millis();
  static unsigned long previousMillis = 0;
  bool Tasterstatus = digitalRead(tasterpin);
  static byte schritt = 0;

  switch (schritt)
  {
    case 0:
      if (Tasterstatus == LOW)
      {
        previousMillis = currentMillis;
        schritt = 1;
      }
      break;

    case 1:
      if (ledAnimation(0, 255))
      {
        schritt = 2;
      }
      break;

    case 2:
      if (ledAnimation(127, 255))
      {
        schritt = 3;
      }
      break;

    case 3:
      if (ledAnimation(0, 0))
      {
        schritt = 4;
      }
      break;

    case 4:
      if (currentMillis - previousMillis >= Ablaufzeit)
      {
        schritt = 0;
      }
      break;
  }
}

bool ledAnimation(byte farbe, byte hell)
{
  bool ergebnis = false;
  const unsigned long BLINKZEIT = 100;
  static unsigned long vorher = 0;
  static byte pos = 0;
  if (currentMillis - vorher >= BLINKZEIT)
  {
    vorher = currentMillis;
    leds[pos] = CHSV(farbe, 255, hell);
    FastLED.show();
    if (++pos >= NUM_LEDS)
    {
      ergebnis = true;
      pos = 0;
    }
  }
  return ergebnis;
}

Nach Tastendruck läuft eine Animation ab. Ist die Funktion fertig, kommt sie mit true zurück, sonst mit false. So kann man in der Schrittkette verharren, bis es weitergeht. Das kann man mit allen Deinen Funktionen so machen.

Hilft Dir das zum Verständnis?

2 Likes

Schaut vielversprechend aus. Muss es mal ausprobieren.

Meine Funktionen, die ich erstellt habe, laufen alle zur selben Zeit parallel ab, also nicht nacheinander. Ich muss es so ausführen, dass, nach der 1-minütigen Ablaufzeit, quasi ein Reset stattfindet. Muss noch einmal die Nachtwächter-Erklärung genauer unter die Lupe nehmen.

Aber vielen Dank für die Unterstützung!!!

Wie würde denn die schöne Lösung aussehen :thinking::grin:?

Ach so, dann gefällt Dir eventuell diese Variante besser:

Programm mit Schrittkette und Millis
#include <FastLED.h>
#define NUM_LEDS  16
#define LED_PIN   19 //6  <- wegen ESP32
CRGB leds[NUM_LEDS];

const byte tasterpin = 2;
unsigned long currentMillis;

void setup()
{
  pinMode(tasterpin, INPUT_PULLUP);
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
  FastLED.show();
}

void loop()
{
  const unsigned long Ablaufzeit = 60000;
  currentMillis = millis();
  static unsigned long previousMillis = 0;
  static bool fertigA = false, fertigB = false;
  bool Tasterstatus = digitalRead(tasterpin);
  static byte schritt = 0;

  switch (schritt)
  {
    case 0:
      if (Tasterstatus == LOW)
      {
        previousMillis = currentMillis;
        schritt = 1;
      }
      break;

    case 1:
      if (!fertigA) fertigA = ledAnimationA();
      if (!fertigB) fertigB = ledAnimationB();
      if ( fertigA && fertigB )
      {
        fertigA = false;
        fertigB = false;
        schritt = 2;
      }
      break;

    case 2:
      if (currentMillis - previousMillis >= Ablaufzeit)
      {
        for (byte j = 0; j < NUM_LEDS; j++)
        {
          leds[j] = CHSV(0, 0, 0);
        }
        FastLED.show();
        schritt = 0;
      }
      break;
  }
}

bool ledAnimationA()
{
  bool ergebnis = false;
  const unsigned long BLINKZEIT = 777;
  static unsigned long vorher = 0;
  static byte pos = 0;
  if (currentMillis - vorher >= BLINKZEIT)
  {
    vorher = currentMillis;
    leds[pos] = CHSV(0, 255, 255);
    FastLED.show();
    if (++pos >= NUM_LEDS / 2)
    {
      ergebnis = true;
      pos = 0;
    }
  }
  return ergebnis;
}

bool ledAnimationB()
{
  bool ergebnis = false;
  const unsigned long BLINKZEIT = 333;
  static unsigned long vorher = 0;
  static byte pos = NUM_LEDS / 2;
  if (currentMillis - vorher >= BLINKZEIT)
  {
    vorher = currentMillis;
    leds[pos] = CHSV(127, 255, 255);
    FastLED.show();
    if (++pos >= NUM_LEDS)
    {
      ergebnis = true;
      pos = NUM_LEDS / 2;
    }
  }
  return ergebnis;
}

@agmue Danke für die Hilfe.

Aktuell klappt es nur nicht, wie ich es möchte und ich weiß nicht wo mein Fehler ist. Ich habe es so umgeschrieben wie du @agmue es vorgeschlagen hast. Aber optisch ist es so momentan, dass wohl currentMillis schon beim einschalten hochgezählt wird. Aber die strikten Zeit-Intervalle interhalb meiner Funktion werden nicht eingehalten.

Hier nochmals meine umgeschriebene Version:

#include <Servo.h>
#include <FastLED.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>

#include <Fonts/FreeMonoBoldOblique12pt7b.h>
#include <Fonts/FreeSerif9pt7b.h>
#include <Fonts/Org_01.h>

#define NUM_LEDS  16
#define LED_PIN   6
#define TFT_DC 9
#define TFT_CS 10
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define COLOR_ORDER GRB
 
Adafruit_GC9A01A tft (TFT_CS, TFT_DC);

CRGB leds[NUM_LEDS];

uint8_t paletteIndex = 0;

int servopin = 7;
int tasterpin = 2;

int servotakt = 1;
int servopos = 90;


int Stufe;
int Sequence;
int Lied;


DEFINE_GRADIENT_PALETTE( fairygarden_gp ) {
    0,  55, 19,103,
   51,  95, 32,133,
  101, 167, 44,162,
  153, 125,182,237,
  204,  84,127,207,
  255,  19, 40,114};

CRGBPalette16 myPal = fairygarden_gp;

Servo Servo;

SoftwareSerial softwareSerial(3, 4);

const int wirePin = 4; 
const int endPin = 5;

DFRobotDFPlayerMini player;

unsigned long currentMillis;


unsigned long servoPreviousMillis = 0;
unsigned long tasterMillis = 0;
unsigned long millisLied = 0;

const unsigned long servoPeriod = 50;
const unsigned long servoPeriod2 = 75;
const unsigned long tasterPeriod = 100;
const unsigned long wartezeit = 5000;
const unsigned long Leuchten1 = 20000;
const unsigned long Leuchten2 = 25000;
const unsigned long millislied1warte = 16000;
const unsigned long millislied2warte = 32000;
const unsigned long millislied1 = 1000;
const unsigned long millislied2 = 1000;
const unsigned long interval = 50; 
const unsigned long displayTime = 50;


void setup() {

  Servo.attach(servopin);
  Servo.write(servopos);

  tft.begin();           
  tft.setRotation(1);     
  tft.fillScreen(GC9A01A_BLACK); 

  pinMode(tasterpin, INPUT_PULLUP);
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);

  softwareSerial.begin(9600);
  Serial.begin(115200);

  if (!player.begin(softwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true){
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }

Serial.println(F("DFPlayer Mini online."));
player.volume(3);  //Lautstärke auf Maximum (15)  

}

void loop() {

currentMillis = millis();
static unsigned long previousMillis = 0;
const unsigned long Ablaufzeit = 18000;
static bool Fertig = false;
static byte Instanz = 0;
bool Tasterstatus = digitalRead(tasterpin);

switch(Instanz) {

  case 0:

  if(Tasterstatus == LOW) {
  previousMillis = currentMillis;
  Instanz = 1;
  tft.fillScreen(0x0000); 
  } else {
    Tasterwarten();
  }
  break;
  
  case 1:
  
  if (!Fertig) Fertig = Display();
  
  //Servomotor();
  //LEDRing();
  //Liedabspielen();

  if (Fertig)
      {
        Fertig = false;
        Instanz = 2;
      }
  
  break;

  case 2:

  if(currentMillis - previousMillis >= Ablaufzeit) {
    Instanz = 0;
}
  //FastLED.show();
}
}



bool Display() {

  bool Back = false;
  static unsigned long displayanzeige = 0;
  const unsigned long intervalnext = 5000;
  const unsigned long intervalnext2 = 15000;
  const unsigned long interval2 = 50;
  const unsigned long interval3 = 600;
  static byte Anzeige = 0;
  
  switch(Anzeige) {

    case 0:

    //Displayhintergrund();

    tft.setFont(&FreeSerif9pt7b);
    tft.setCursor(70, 110);
    tft.setTextColor(random(0x0000, 0xF8FF));
    tft.setTextSize(2); 
    tft.print("Happy");
    tft.setCursor(5, 155);
    tft.setTextColor(random(0x0000, 0xF8FF));
    tft.setTextSize(2); 
    tft.print("Valentine's Day"); 
    tft.setFont(&FreeMonoBoldOblique12pt7b);
    tft.setCursor(63, 220);
    tft.setTextColor(GC9A01A_YELLOW);
    tft.setTextSize(2); 
    tft.print("Name");

    if (currentMillis - displayanzeige >= intervalnext) {
    tft.fillScreen(0x0000);
    Anzeige = 1;
    }
    break;

    case 1:

    if (currentMillis - displayanzeige >= intervalnext2) {
    displayanzeige = currentMillis;
    tft.fillScreen(0x0000);
    Back = true;
    Anzeige = 0;
    
  } else {
    
    if (currentMillis - displayanzeige >= interval2) {
   
    drawHeart(tft.width()/2, tft.height()/2 - 20, GC9A01A_MAGENTA);

    if (currentMillis - displayanzeige >= interval3) {
  
    tft.fillScreen(0x0000); 
  }
  }
  }
  break;
}
return Back;
}
/*

void Servomotor() {

  switch(Stufe) {

  case 0:
  
  servoPreviousMillis = currentMillis;
  servopos += servotakt;
  Servo.write(servopos);
  if (servopos >= 180) {
  Stufe = 1;
  }
  
  break;

  case 1:

  if (currentMillis - servoPreviousMillis >= wartezeit) {
  servoPreviousMillis = currentMillis;
  Stufe = 2;
  }
  break;

  case 2:

  if (currentMillis - servoPreviousMillis >= servoPeriod2) {
  servoPreviousMillis = currentMillis;
  servopos -= servotakt;
  Servo.write(servopos);

  if(servopos <= 90) {

  Stufe = 0;
  }
  }
  break;
}
}

void LEDRing() {

switch(Sequence){

case 0:

static unsigned long LEDMillis1 = 0;

FastLED.setBrightness(50);
fill_solid(leds, NUM_LEDS, CRGB(48, 173, 10));
 
  if (currentMillis - LEDMillis1 >= Leuchten1) {
  Sequence = 1;
  LEDMillis1 = currentMillis;
}
break;

case 1:

  static unsigned long LEDMillis2 = 0;

  if(currentMillis - LEDMillis2 >= Leuchten2) {
  Sequence = 0;
  LEDMillis2 = currentMillis;
} else {

  FastLED.setBrightness(40);
  fill_palette(leds, NUM_LEDS, paletteIndex, 255 / NUM_LEDS, myPal, 255, LINEARBLEND);
  
  EVERY_N_MILLISECONDS(2){
  paletteIndex++;
  }
}
break;
}
}

void Liedabspielen() {

switch(Lied) {

case 0:

if(currentMillis - millisLied >= millislied1) {
  millisLied = currentMillis;
  player.play(1);
  Lied = 1;
  }
  break;

case 1:

if(currentMillis - millisLied >= millislied1warte) {
  millisLied = currentMillis;
  Lied = 2;
 }
 break;

case 2:

if(currentMillis - millisLied >= millislied2) {
  millisLied = currentMillis;
  player.play(2);
  Lied = 3;
  }
  break;

case 3:

if(currentMillis - millisLied >= millislied2warte) {
  millisLied = currentMillis;
  Lied = 0;
 }
 break;
 
}
}

*/
void drawHeart(int x0, int y0, uint16_t color) {
    int size = 50; // Size of the heart

   // Calculate the vertices of the two triangles that form the bottom of the heart
   int x1 = x0 - size + 5;
   int y1 = y0 - 10;
   int x2 = x0 + size - 5;
   int y2 = y0 - 10;
   int x3 = x0;
   int y3 = y0 + size;

   // Draw two triangles to form the bottom of the heart
   tft.fillTriangle(x1, y1, x3, y3, x0, y0 - size/2, color);
   tft.fillTriangle(x0, y0 - size/2, x3, y3, x2, y2, color);

   // Draw two half-circles at the top of the heart
   tft.fillCircle(x0 - size/2, y0 - size/2, size/2, color);
   tft.fillCircle(x0 + size/2, y0 - size/2, size/2, color);
}


void Tasterwarten(){

static unsigned long anzeigezeit = 0;
const unsigned long anzeigePeriod = 1000;

if(currentMillis - anzeigezeit >= anzeigePeriod) {
  anzeigezeit = currentMillis;
  
  tft.fillScreen(0x0000); 
  tft.setCursor(50, 50); 
  tft.setFont(&FreeSerif9pt7b);
  tft.setTextColor(GC9A01A_WHITE); 
  tft.setTextSize(2); 
  tft.print("Press me!"); 
  tft.fillRect(107, 110, 26, 100, GC9A01A_WHITE);
  tft.fillTriangle(90,185,150,185,120,245, GC9A01A_WHITE);
  }

  FastLED.setBrightness(50);
  fill_solid(leds, NUM_LEDS, CRGB(48, 173, 10));


}

/*
void Displayhintergrund() {

    static unsigned long displayanzeige1 = 0;

    if (currentMillis - displayanzeige1 >= interval) {
    displayanzeige1 = currentMillis;

    
    int x = random(SCREEN_WIDTH);
    int y = random(SCREEN_HEIGHT);
    int x2 = random(SCREEN_WIDTH);
    int y2 = random(SCREEN_HEIGHT);
    int rectSize = random(3, 7); 
    int rectSize2 = random(3, 7); 

    
    tft.fillRect(x, y, rectSize, rectSize, GC9A01A_WHITE);
    tft.fillRect(x2, y2, rectSize2, rectSize2, GC9A01A_WHITE);

    
    static unsigned long displayEndTime = currentMillis + displayTime;

    
    while (currentMillis < displayEndTime) {
    currentMillis = displayEndTime;
    }
    
    tft.fillRect(x, y, rectSize, rectSize, GC9A01A_BLACK);
    tft.fillRect(x2, y2, rectSize2, rectSize2, GC9A01A_BLACK);
  }

}*/

Die anderen 3 Funktionen müssen erstmal nicht beachtet werden. Solang die eine Funktion nicht funktioniert, kann ich es mit den anderen auch knicken.

Werft mal einen Blick drüber und schreibt mir, wenn ihr den Fehler findet und was ich verbessern müsste (abgesehen von meinem Code-Chaos :sweat_smile:).

Oder klappt vielleicht meine switch-case-Ausführung innerhalb meiner Funktion nicht und soll es lieber in einzelne Funktionen packen :thinking: :thinking: :thinking:?

Natürlich. Das ist seine Aufgabe.

Gruß Tommy

Schau dir mal Display an:

#include <Servo.h>
#include <FastLED.h>
#include <SoftwareSerial.h>
#include <DFRobotDFPlayerMini.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_GC9A01A.h>

#include <Fonts/FreeMonoBoldOblique12pt7b.h>
#include <Fonts/FreeSerif9pt7b.h>
#include <Fonts/Org_01.h>

#define NUM_LEDS  16
#define LED_PIN   6
#define TFT_DC 9
#define TFT_CS 10
#define SCREEN_WIDTH 320
#define SCREEN_HEIGHT 240
#define COLOR_ORDER GRB

Adafruit_GC9A01A tft (TFT_CS, TFT_DC);

CRGB leds[NUM_LEDS];

uint8_t paletteIndex = 0;

int servopin = 7;
int tasterpin = 2;

int servotakt = 1;
int servopos = 90;


int Stufe;
int Sequence;
int Lied;


DEFINE_GRADIENT_PALETTE( fairygarden_gp ) {
  0,  55, 19, 103,
  51,  95, 32, 133,
  101, 167, 44, 162,
  153, 125, 182, 237,
  204,  84, 127, 207,
  255,  19, 40, 114
};

CRGBPalette16 myPal = fairygarden_gp;

Servo Servo;

SoftwareSerial softwareSerial(3, 4);

const int wirePin = 4;
const int endPin = 5;

DFRobotDFPlayerMini player;

unsigned long currentMillis;


unsigned long servoPreviousMillis = 0;
unsigned long tasterMillis = 0;
unsigned long millisLied = 0;

const unsigned long servoPeriod = 50;
const unsigned long servoPeriod2 = 75;
const unsigned long tasterPeriod = 100;
const unsigned long wartezeit = 5000;
const unsigned long Leuchten1 = 20000;
const unsigned long Leuchten2 = 25000;
const unsigned long millislied1warte = 16000;
const unsigned long millislied2warte = 32000;
const unsigned long millislied1 = 1000;
const unsigned long millislied2 = 1000;
const unsigned long interval = 50;
const unsigned long displayTime = 50;


void setup() {

  Servo.attach(servopin);
  Servo.write(servopos);

  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(GC9A01A_BLACK);

  pinMode(tasterpin, INPUT_PULLUP);
  FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);

  softwareSerial.begin(9600);
  Serial.begin(115200);

  if (!player.begin(softwareSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while (true) {
      delay(0); // Code to compatible with ESP8266 watch dog.
    }
  }

  Serial.println(F("DFPlayer Mini online."));
  player.volume(3);  //Lautstärke auf Maximum (15)

}

void loop() {
  currentMillis = millis();
  static unsigned long previousMillis;
  const unsigned long Ablaufzeit = 18000;
  static bool Fertig = false;
  static byte Instanz = 0;
  bool Tasterstatus = digitalRead(tasterpin);

  switch (Instanz) {
    case 0:
      if (Tasterstatus == LOW) {
        previousMillis = currentMillis;
        Instanz = 1;
        tft.fillScreen(0x0000);
      } else {
        Tasterwarten();
      }
      break;
    case 1:
      if (!Fertig)
        Fertig = Display();
      else {
        Fertig = false;
        Instanz = 2;
      }
      break;
    case 2:
      if (currentMillis - previousMillis >= Ablaufzeit) {
        Instanz = 0;
      }
  }
}

bool Display() {
  bool Back = false;
  static unsigned long displayanzeige = 0;
  static unsigned long displayanzeige1 = 0;
  const unsigned long intervalnext = 5000;
  const unsigned long intervalnext2 = 15000;
  const unsigned long interval2 = 50;
  const unsigned long interval3 = 600;
  static byte Anzeige = 0;

  switch (Anzeige) {
    case 0:
      displayanzeige = currentMillis;
      displayanzeige1 = currentMillis;
      tft.setFont(&FreeSerif9pt7b);
      tft.setCursor(70, 110);
      tft.setTextColor(random(0x0000, 0xF8FF));
      tft.setTextSize(2);
      tft.print("Happy");
      tft.setCursor(5, 155);
      tft.setTextColor(random(0x0000, 0xF8FF));
      tft.setTextSize(2);
      tft.print("Valentine's Day");
      tft.setFont(&FreeMonoBoldOblique12pt7b);
      tft.setCursor(63, 220);
      tft.setTextColor(GC9A01A_YELLOW);
      tft.setTextSize(2);
      tft.print("Lisa");
      Anzeige = 1;
      break;
    case 1:
      if (currentMillis - displayanzeige >= intervalnext) {
        tft.fillScreen(0x0000);
        displayanzeige = currentMillis;
        Anzeige = 2;
      }
      break;
    case 2:
      if (currentMillis - displayanzeige >= interval2) {
        displayanzeige = currentMillis;
        Anzeige = 3;
        drawHeart(tft.width() / 2, tft.height() / 2 - 20, GC9A01A_MAGENTA);
      }
      break;
    case 3:
      if (currentMillis - displayanzeige >= interval3) {
        tft.fillScreen(0x0000);
        displayanzeige = currentMillis;
        Anzeige = 2;
      }
      break;
  }

  if (currentMillis - displayanzeige1 >= intervalnext2) {
    displayanzeige = currentMillis;
    tft.fillScreen(0x0000);
    Back = true;
    Anzeige = 0;
  }
  return Back;
}

void drawHeart(int x0, int y0, uint16_t color) {
  int size = 50; // Size of the heart

  // Calculate the vertices of the two triangles that form the bottom of the heart
  int x1 = x0 - size + 5;
  int y1 = y0 - 10;
  int x2 = x0 + size - 5;
  int y2 = y0 - 10;
  int x3 = x0;
  int y3 = y0 + size;

  // Draw two triangles to form the bottom of the heart
  tft.fillTriangle(x1, y1, x3, y3, x0, y0 - size / 2, color);
  tft.fillTriangle(x0, y0 - size / 2, x3, y3, x2, y2, color);

  // Draw two half-circles at the top of the heart
  tft.fillCircle(x0 - size / 2, y0 - size / 2, size / 2, color);
  tft.fillCircle(x0 + size / 2, y0 - size / 2, size / 2, color);
}

void Tasterwarten() {
  static unsigned long anzeigezeit = 0;
  const unsigned long anzeigePeriod = 1000;

  if (currentMillis - anzeigezeit >= anzeigePeriod) {
    anzeigezeit = currentMillis;

    tft.fillScreen(0x0000);
    tft.setCursor(50, 50);
    tft.setFont(&FreeSerif9pt7b);
    tft.setTextColor(GC9A01A_WHITE);
    tft.setTextSize(2);
    tft.print("Press me!");
    tft.fillRect(107, 110, 26, 100, GC9A01A_WHITE);
    tft.fillTriangle(90, 185, 150, 185, 120, 245, GC9A01A_WHITE);
  }

  FastLED.setBrightness(50);
  fill_solid(leds, NUM_LEDS, CRGB(48, 173, 10));
}
1 Like