Uhrzeit / Datum durch "switch case" zeitlich anzeigen

Hallo

Mein Name ist Ronny und dies ist der erste Beitrag in diesem hilfreichen Forum :slight_smile:
Durch dieses bin ich auf den Tip mit der switch case Funktion von michael_x gestoßen.

Darauf hin gleich diese einfache Ausgabe der Zeit und des Datums integriert in der Hoffnung abwechselnd aller 5 Sekunden durch die Schritte zu schalten. Jedoch wird nur aller 5 Sekunden ein Digit von 6 vorhanden angezeigt. Der Serial.print Kommentar funktioniert problemlos alleinig im seriellen Monitor. Wo liegt hier der Hund begraben?

MfG Ronny

#include "SevSeg.h"
#include <DS3231.h>
DS3231  rtc(SDA, SCL); //A4,A5
Time  t;
SevSeg Display;

int Schritt;
unsigned long Dauer; 
unsigned long previousMillis;
unsigned long datum = 0;
unsigned long zeit = 0;

void setup() {  
  //Serial.begin(9600);  
  rtc.begin();
  byte numDigits = 6;  
  byte digitPins[] = {5, 4, 3, 2, 0, 1}; // [8 8] [8 8] [8 8]
  byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13}; // A,B,C,D,E,F,G,Dp
  bool resistorsOnSegments = true; // false = resistors are on digit pins
  byte hardwareConfig = COMMON_CATHODE;
  bool updateWithDelays = false; // Default 'false' is Recommended
  bool leadingZeros = true; // Use 'true' if you'd like to keep the leading zeros
  bool disableDecPoint = false; // Use 'true' if your decimal point doesn't exist or isn't connected. Then, you only need to specify 7 segmentPins[]
  
  Display.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros, disableDecPoint);
  Display.setBrightness(100);
  }

void loop () 
{    
   unsigned long currentMillis = millis();
   if (  currentMillis  - previousMillis > Dauer )  
   {
      Schritt++;  // nächster Schritt
      switch (Schritt) 
           {
                case 1:
                    //Serial.println("modus 1"); 
                    t = rtc.getTime(); 
                    zeit = (t.hour * 100 + t.min) * 100L + t.sec;  
                    Display.setNumber(zeit);
                    Display.refreshDisplay();           
                    Dauer = 5000; // sec warten

                    break;
      
                case 2:
                    //Serial.println("modus 2");
                    t = rtc.getTime(); 
                    datum = (((t.date * 100 + t.mon) * 100L) + t.year) - 2000;
                    Display.setNumber(datum);
                    Display.refreshDisplay(); 
                    Dauer = 5000; // sec warten

                    break;

              // ....  Beliebig weitere Schritte definieren

                   default:
                   Schritt = 0;
                   Dauer = 1;     // Schrittfolge wieder von vorn
           }
          previousMillis = currentMillis; // "Delay" neu starten
   }

   // hier evtl. Tasterabfragen, um die Schrittfolge zu ändern oder Wartezeiten abzubrechen o.ä.

}

Das refresh() muss andauernd passieren.

Ungetestet:

#include "SevSeg.h"
#include <DS3231.h>
DS3231  rtc(SDA, SCL); //A4,A5
Time  t;
SevSeg Display;

int Schritt=1;
unsigned long Dauer = 5000;
unsigned long previousMillis;
unsigned long datum = 0;
unsigned long zeit = 0;

void setup()
{
  //Serial.begin(9600);
  rtc.begin();
  byte numDigits = 6;
  byte digitPins[] = {5, 4, 3, 2, 0, 1}; // [8 8] [8 8] [8 8]
  byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13}; // A,B,C,D,E,F,G,Dp
  bool resistorsOnSegments = true; // false = resistors are on digit pins
  byte hardwareConfig = COMMON_CATHODE;
  bool updateWithDelays = false; // Default 'false' is Recommended
  bool leadingZeros = true; // Use 'true' if you'd like to keep the leading zeros
  bool disableDecPoint = false; // Use 'true' if your decimal point doesn't exist or isn't connected. Then, you only need to specify 7 segmentPins[]
  Display.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros, disableDecPoint);
  Display.setBrightness(100);
}

void loop ()
{
  Display.refreshDisplay();
  unsigned long currentMillis = millis();
  if (  currentMillis  - previousMillis > Dauer )
  {
    t = rtc.getTime();
    switch (Schritt)
    {
      case 1:
        //Serial.println("modus 1");
        zeit = (t.hour * 100 + t.min) * 100L + t.sec;
        Display.setNumber(zeit);
        Schritt = 2;
        break;
      case 2:
        //Serial.println("modus 2");
        datum = (((t.date * 100 + t.mon) * 100L) + t.year) - 2000;
        Display.setNumber(datum);
        Schritt = 1;
        break;
      // ....  Beliebig weitere Schritte definieren
      default:
        Schritt = 1;
        break;
    }
    previousMillis = currentMillis; // "Delay" neu starten
  }
  // hier evtl. Tasterabfragen, um die Schrittfolge zu ändern oder Wartezeiten abzubrechen o.ä.
}

Formal korrekt und auch besser ist für Dauer einen Startwert zu definieren.
Grüße Uwe

Danke für die schnelle Antwort. Funktioniert fast perfekt, jedoch bleiben die Sekunden
eben für die "Dauer" im case 1 wie eingefroren.

Geh ich Recht der Annahme das er nur 1x den jeweiligen "case" ausführt und eben wartet um in den nächsten zu springen?

MfG Ronny

Im Normalfall führt Switch nur ein Case aus. Dafür sorgt das break; Du kommst aber jeden Loop Durchlauf wieder in den Switch, womit ein neuer Case ausgeführt werden kann. Die Bedingungen, den Switch zu erreichen, müssen natürlich erfüllt sein.


void loop ()
{
  Display.refreshDisplay();
  unsigned long currentMillis = millis();
  t = rtc.getTime();
  if (  currentMillis  - previousMillis > Dauer )
  {
    schritt++;
    previousMillis = currentMillis; // "Delay" neu starten
  }
  switch (Schritt)
  {
    case 1:
      //Serial.println("modus 1");
      zeit = (t.hour * 100 + t.min) * 100L + t.sec;
      Display.setNumber(zeit);
      break;
    case 2:
      //Serial.println("modus 2");
      datum = (((t.date * 100 + t.mon) * 100L) + t.year) - 2000;
      Display.setNumber(datum);
      break;
    // ....  Beliebig weitere Schritte definieren
    default:
      Schritt = 1;
      break;
  }
  // hier evtl. Tasterabfragen, um die Schrittfolge zu ändern oder Wartezeiten abzubrechen o.ä.
}

@my_xy_projekt: Wer zu spät kommt ...

Weil Du am switch/case nicht mehr während fünf Sekunden vorbeikommst. Wenn Du Inkrementieren und Zeitabfrage trennst, funktioniert es. Getestet mit Mega2560 und OLED:

#include <U8g2lib.h>
#include <Wire.h>
U8G2_SSD1306_128X64_NONAME_F_HW_I2C oled(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

//#include "SevSeg.h"
#include <DS3231.h>
DS3231  rtc(SDA, SCL); //A4,A5
Time  t;
//SevSeg Display;

uint8_t Schritt = 0;
unsigned long Dauer = 5000;
unsigned long schrittMillis = 0;
unsigned long datum = 0;
unsigned long zeit = 0;

void setup() {
  oled.begin();
  oled.setFont(u8g2_font_6x12_tr);
  
  //Serial.begin(9600);
  rtc.begin();
  //byte numDigits = 6;
  //byte digitPins[] = {5, 4, 3, 2, 0, 1}; // [8 8] [8 8] [8 8]
  //byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13}; // A,B,C,D,E,F,G,Dp
  //bool resistorsOnSegments = true; // false = resistors are on digit pins
  //byte hardwareConfig = COMMON_CATHODE;
  //bool updateWithDelays = false; // Default 'false' is Recommended
  //bool leadingZeros = true; // Use 'true' if you'd like to keep the leading zeros
  //bool disableDecPoint = false; // Use 'true' if your decimal point doesn't exist or isn't connected. Then, you only need to specify 7 segmentPins[]

  //Display.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments, updateWithDelays, leadingZeros, disableDecPoint);
  //Display.setBrightness(100);
}

void loop ()
{
  char buf[20] = {'\0'};

  unsigned long currentMillis = millis();
  static unsigned long leseMillis = 0;
  const unsigned long leseIntervall = 100;
  
  if (  currentMillis  - schrittMillis >= Dauer )
  {
    schrittMillis = currentMillis; // "Delay" neu starten
    Schritt++;  // nächster Schritt
  }

  if (  currentMillis  - leseMillis >= leseIntervall )
  {
    leseMillis = currentMillis; // "Delay" neu starten
    switch (Schritt)
    {
      case 0:
        //Serial.println("modus 1");
        t = rtc.getTime();
        zeit = (t.hour * 100 + t.min) * 100L + t.sec;
        snprintf( buf, sizeof(buf), "%2d:%2d", t.hour, t.min );
        oled.clearBuffer();          // clear the internal memory
        oled.drawStr(0, 10, buf);    // write something to the internal memory
        oled.sendBuffer();           // transfer internal memory to the display

        //Display.setNumber(zeit);
        //Display.refreshDisplay();
        break;

      case 1:
        //Serial.println("modus 2");
        t = rtc.getTime();
        delay(100);
        datum = (((t.date * 100 + t.mon) * 100L) + t.year) - 2000;
        snprintf( buf, sizeof(buf), "%2d.%2d.%2d", t.date, t.mon, t.year );
        oled.clearBuffer();          // clear the internal memory
        oled.drawStr(0, 10, buf);    // write something to the internal memory
        oled.sendBuffer();           // transfer internal memory to the display
        //Display.setNumber(datum);
        //Display.refreshDisplay();
        break;

      // ....  Beliebig weitere Schritte definieren

      default:
        Schritt = 0;
    }
  }
}

Guten Abend

Vielen Dank für die tolle Hilfe, es funktioniert wie gewünscht mit Pausenzeit.

Natürlich folgt schon darauf eine nächste Frage in der ich einzelne Digits definieren kann. Ich möchte das die 8bits aus den Variablen (digit2 / 3) nur mit der Zahl von 0-9 gebildet
werden. Beispiel wenn "6" als "0b01111101" erscheint. Welche Herangehensweise
müsste ich verfolgen?

MfG Ronny

void loop(){

       int digit2 = 0; //Zehner Stelle 0-9 Temperaturwert 
       int digit3 = 0; //Einer Stelle 0-9 Temperaturwert 
                    
        uint8_t segs[6] = {0b00000000, 
                           0b00000000, 
                           digit2, 
                           digit3, 
                           0b01100011,  //*
                           0b00111001}; //C für Celsius, Segmentfolge: dP, g, f, e, d, c, b, a
                                                      
        Display.setSegments(segs);
        Display.refreshDisplay(); 
}

Ich weiß nicht, ob ich Dein Anliegen richtig verstanden habe, aber ich würde vorschlagen:

variable & 0xf;

Wenn Du nur die unteren 4 Bits willst.

Gruß Tommy

mit irgendwelchen Teilsketchen ist das rumgerate.
so wird das nicht klappen, denn in deiner Temperatur hast du einen Dezimalwert, in deinem seg Array wirst du die Segmente brauchen.
Du müsstest von deine Zehnerstelle (die du einfach mit Wert / 10 ermitteln könntest) dann noch von dem Wert 0 ..9 die jeweiligen Segmente bestimmen.

Schau in den Beispieln der Library nach, aber ich würde in digit2 und digit 3 mit setNumber schreiben, und nur das Gradzeichen (und Celsisius) mit setSegments.

Hallo

Ja ok das ist ein Auszug aus der sevseg Library. An für sich funktioniert mit setNumber bisher alles wie gewünscht (Uhrzeit/Datum als 6 stellige Zahl abzubilden). Nun war der Plan den Temperatur Zehner/Einer eben auf 2 einzelne Digits mit setSegments zu verteilen. Da werde ich um ein definiertes Array zu je 8bit für die 0-9 Darstellung nicht herum kommen. Probiert setNumber und setSegments
zu kombinieren habe ich noch nicht.

MfG Ronny

noch mal von vorne:

setSegments schreibt eine bitmap an jede Stelle so das einzelne Segmente aufleuchten
Wenn du deine Temperatur in Einzelstellen zerteilst wird z.B. aus 42 Grad 4 für die Zehnerstelle.
4 ist in ASCII das Zeichen 52 oder binär 0b00110100.
00110100 ist aber nicht das was du im Array segs brauchen kannst.
Theoretisch brauchst du irgend einen Binärcode mit vier 1. Sonst wird das nie eine 4 auf deiner Segmentanzeige.

warum nicht?

Lies die Doku von deiner Library:
https://github.com/DeanIsMe/SevSeg

Es gibt auch ein

// Set the segments for a single digit. Set digit 3 to 0x63. 
sevseg.setSegmentsDigit(3, 0x63);

also machs dir einfach und schreibe die Zahlen als Zahl und setze die Sonderzeichen mit der Funktion für einzelne Digits.

Nabend,
der Tip zu kombinieren klappt bestens. Damit wird es korrekt angezeigt:

case 3:
                  temp = (rtc.getTemp()*1000)-4500;  //Temp erzeugen, verschieben u bissel Offset            
                  Display.setNumber(temp, 3);  //Temp als 88.8 darstellen
                  Display.setSegmentsDigit(4, 0b01100011);      //* Zeichen                                      
                  Display.setSegmentsDigit(5, 0b00111001);     //C wie Celsius       
                  Dauer = 3000; // sec warten
                  break;    

Ja der Plan war, wie Du oben schön beschrieben hast durch die einzelne Zehnerstelle zB.
"4" dieses Bitmuster { 0,1,1,0,0,1,1,0 }, // 4 aus dem unteren Array, an eben die entsprechende Digit Stelle zu kopieren.

int num_array[10][8] = {  { 0,0,1,1,1,1,1,1 },    // 0
                          { 0,0,0,0,0,1,1,0 },    // 1
                          { 0,1,0,1,1,0,1,1 },    // 2
                          { 0,1,0,0,1,1,1,1 },    // 3
                          { 0,1,1,0,0,1,1,0 },    // 4
                          { 0,1,1,0,1,1,0,1 },    // 5
                          { 0,1,1,1,1,1,0,1 },    // 6
                          { 0,0,0,0,0,1,1,1 },    // 7
                          { 0,1,1,1,1,1,1,1 },    // 8
                          { 0,1,1,0,1,1,1,1 }};   // 9

Danke für die Hilfe, MfG Ronny