DCF Uhr / Rheinturmuhr (ähnlich)! -Zahlen zerlegen-

Hallo,

Ich habe folgendes vor. Ich möchte eine "analoge" Uhr mit DCF und LCD-Display bauen. Die Ansteuerung mit DCF und LCD läuft soweit.

Jetzt möchte ich die DCF-Zeitangaben wie z.B. Stunden, Minuten, Sekunden auf einem LED Band mit 39 LEDS darstellen. Es wäre so ähnlich wie die Rheinturmuhr allerdings mit einem Unterschied. Es soll immer nur eine LED im entsprechendem Zeitbereich leuchten. Letztendlich wird es eine Wortuhr, die einzelnen Wort-Zahlen sollen von der entsprechenden LED beleuchtet werden.

Beispiel: 16:23:46

Auf der fertigen Uhr soll später zu lesen sein: [Sechs] [Zehn] [Uhr] [Drei] [und] [Zwanzig] [und] [Sechs] [und] [vierzig] [Sekunden]

Die LEDS sind dann nach diesem Grund Schema aufzubauen.

Stunden-Einer - Stunden-Zehner - Minuten-Einer - Minuten-Zehner - Sek-Einer Sek-Zehner

Die Werte für Stunden, Minuten, Sekunden werden mir ja von der time.h-Funktion übergeben.

(hour() , (minute(), (second(),

Wie kann ich aber die einzelnen Werte in Zehner und Einer Stellen trennen damit ich mit den einzelnen Werten dann die entprechenden LED´s ansteuern kann?

Also: 16 müsste in 1 und 6 aufgeteilt werden.

Ich möchte keine endlosen "if then " Schleifen schreiben müssen, es müsste auch einfacher gehen. Beispiel, sinngemäss

if hour=16 then Ausgang StundenZehner-Eins high , StundenEiner-Sehs high,

Das müsste ich dann für jede Stunden, Minuten, Sekundenangabe machen. Es wären 141 If- Schritte.

https://de.wikipedia.org/wiki/Division_mit_Rest#Modulo

Division durch 10 für die Zehner-Stelle. Modulo 10 für die Einer-Stelle.

16 müsste in 1 und 6 aufgeteilt werden.

In c geht das so

int h = 16;
int hz = h/10; // Zehner
int he = h%10; // Einer

Eigentlich passt hier byte sogar besser als int

Für Dein Problem musst Du das gar nicht trennen. Speichere einfach die gewünschten Bitmuster in einem Array und nimm die Stunden / Minuten jeweils als Index.

Hallo, RheinUhr Gruß und Spaß Andreas

Hallo,

Danke für die schnelle Hilfe. Mit "Modulo" habe ich noch nichts gemacht. Ich denke das int oder byte das richtige wäre. Welche Funktion hat denn das Prozentzeichen?

Die Seite von H.-J. Berndt kenne ich, da weis ich aber nicht wie ich die DCF Zeit rein bekomme, ausserdem leuchten die LEDs als Band auf, ich will ja das nur eine leuchtet, sonst macht es mit dem beleuchtetm Text ja keinen Sinn.

Modulo bedeutet der Rest einer Division. 16 % 10 = 6

Hallo,

Ich stehe vor einem Rätsel.

Testweise habe ich diesen Programmpunkt eingefügt (Auszug). Dabei sollen 9 LEDS nacheinander aufleuchten,
entsprechend der Sekunden.

for (int i = 1; i<10; i++)
   {
     
   
if (second()%10==i)
   digitalWrite(30+i,HIGH);
   else
   digitalWrite(30+i,LOW);

Diese Funktion soll die LED´s an Pin 30 bis 39 aufleuchten lassen.
Das geht auch soweit allerdings leuchtet die LED nur bis PIN 37 richtig auf. Auf Pin 38 bis 39
leuchtet die kaum (Pin Spannung 1,7V) bis gar nicht.

Wenn ich jedoch die Pins direkt anspreche (Blink-Sketch Pin 38 / 39 ) leuchten diese so auf wie
sie sollen.
Woran kann es liegen, das die kaum bis gar nicht leuchten ??

Später habe ich es vor mit einer Art Matrix zu realisieren.
Dabei sollen z.B. die Pins 40-45 die Masse und die Pins 30-38 die Zahlen-LED´s (1-9) darstellen.
Prinzip für die Sekunden:

PIN 45 LOW (Sekunden-Einer)
PIN30-38 nacheinander auf leuchten lassen (es leuchtet immer nur eine LED(Sek1-9), Sketch oben)
PIN 45 HIGH

dann:
PIN 46 LOW (Sekunden-Zehner)
PIN30-38 nacheinander auf leuchten lassen (es leuchtet immer nur eine LED(Sek10-50), Sketch oben)
PIN 46 HIGH

Ob es auch so läuft, weis ich nicht. Ich habe aber die Befürchtung das später die LED-Ansteuerung zu lange
dauert so das die DCF-Auswertung nicht mehr funktioniert.

Hast du die Pin auch im Setup als Augang "pinMode(Led_x, OUTPUT)" definiert?

Ja habe ich,

for (int i = 0; i<6; i++)
   {
     pinMode(Massepins[i],OUTPUT);
   }
for (int i = 0; i<10; i++)
   {
     pinMode(Zahlenpins[i],OUTPUT);
   }

Das komische ist das die LEDs an 38,39 im Blink-Sketch (zum testen), leuchten. nur im eigentlichem Programm nicht wirklich (1,7V) wobei die Pins 30-37 volle Spannung raus geben.

Das kann ich aktuell nicht nachvollziehen. Einmal zählst du bis 6, einmal bis 8.

Setze die zum Test mal fest auf Output.

Die 5 "Masse" Pins werden in der Schleife auf Output gesetzt und die "Zahlenpins" (1-9) ebenfalls.

Bei festem Output funktioniert es ja.

Ein Fehler habe ich; der letzte Pin der aktiv sein darf ist PIN 38, das wäre also LED 9. Pin 39 ist also falsch, ich habe mich mit dem zählen vertan.

Bajazzo: Die 5 "Masse" Pins werden in der Schleife auf Output gesetzt und die "Zahlenpins" (1-9) ebenfalls.

Bei festem Output funktioniert es ja.

Ein Fehler habe ich; der letzte Pin der aktiv sein darf ist PIN 38, das wäre also LED 9. Pin 39 ist also falsch, ich habe mich mit dem zählen vertan.

Na prima, dann ist das ja gelöst. ;)

Eine Led erscheint auch weniger hell zu leuchten, wenn sie nur ganz kurz angeschaltet wird.

Ohne deinen Kode ganz zu sehen, kann ich sonst nicht viel sagen.

Also gut… Nur der Code ist ungekürzt und noch mit einigen auskommentierten Funktionen.
Das Programm ansich funktioniert so einigermassen. Wie “Whandall” schon sagte leuchten die LED´s sehr
schwach, werden also nur einmal kurz “angesteuert”. Aber sobald ich ein delay einfüge kommt die DCF Dekodierung durcheinander, bzw läuft gar nicht.
Sollte es nicht anders gehen muss ich es mal mit einem Matrix IC 7219 probieren.

Als Board benutze ich Mega 2560.

Hier der noch unübersichtliche :wink: Code

// DCF Uhr mit LCD 16x1 und LED Punktanzeige

#include <LiquidCrystal.h>
#include <Wire.h>
#include <DCF77.h>
#include <Time.h>


#define DCF_PIN 2               // DCF-Signal Input-Pin
#define DCF_INTERRUPT 0         // Interrupt number associated with pin


   int flankUp = 0;             //
   int flankDown = 0;           //
   int PreviousflankUp;         //
   bool Up = false;             //
   
   const int Zahlenpins[] ={30,31,32,33,34,35,36,37,38};  // LED-Pins für Zahlen (Beispiel)
   const int Massepins[] = {40,41,42,43,44,45};           // Masse - Pins
   
   
  
 
time_t time;
DCF77 DCF = DCF77(DCF_PIN,DCF_INTERRUPT);
LiquidCrystal lcd(12, 13, 11, 7, 8, 9, 10);  // RS, RW, E, D4, D5, D6, D7

byte AntenneSig[8] =  // Antennen- Symbol mit Signal
{
B01110,
B10001,
B10101,
B01110,
B00100,
B00100,
B01110,
B11111};

byte Antenne[8] =  // Antennen- Symbol ohne Signal
{
B00000,
B00000,
B00100,
B00100,
B00100,
B00100,
B01110,
B11111};



void setup() {
Wire.begin();

lcd.createChar(1,AntenneSig);
lcd.createChar(2,Antenne);

lcd.begin(8,2);
DCF.Start();

 //  LED-pins alle als OUTPUT deklarieren   

 for (int i = 0; i<9; i++)
   {
     pinMode(Zahlenpins[i],OUTPUT);
   }
 // ---------------------------------
 
 // Massepins als OUTPUT deklarieren
 for (int i = 0; i<6; i++)
   {
     pinMode(Massepins[i],OUTPUT);
   }
 //------------------------------------
 
 


   pinMode(DCF_PIN, INPUT);   
     

}


void loop() {




time_t DCFtime = DCF.getTime();  // Check if new DCF77 time is available
if (DCFtime!=0)
{
setTime(DCFtime);
}





// Ausgabe

//  lcd.clear();
lcd.setCursor(0,0);
if(hour() < 10)
lcd.print("0");
lcd.print(hour());
lcd.print(":");
if(minute() < 10)
lcd.print("0");
lcd.print(minute());
lcd.print(":");
if(second() < 10)
lcd.print("0");
lcd.print(second());

      // lcd.setCursor(0,1);          // Test  Zehner / Einer stelle heraus filtern
      // lcd.print (hour()%10) ;    // Test

lcd.setCursor (8,0);
lcd.print("   ");

lcd.setCursor(1,1);
if(day() < 10)
lcd.print("0");
lcd.print(day());
lcd.print(".");
if(month() < 10)
lcd.print("0");
lcd.print(month());
// lcd.print("");
 //lcd.print(year());


//  LED´s für Sekunde aufleuchten lassen  

/* if (second()%10 ==1)
    digitalWrite(A0, HIGH);
    else
    digitalWrite(A0, LOW);
  
if (second()%10 ==2)
    digitalWrite(23, HIGH);
    else
    digitalWrite(23, LOW);

if (second()%10 ==3)
    digitalWrite(22, HIGH);
    else
    digitalWrite(22, LOW); 

if (second()%10 ==4)
    digitalWrite(19, HIGH);
    else
    digitalWrite(19, LOW);    
  
*/

/*

digitalWrite(45,LOW);  // Pin für Sek Einer auf Masse legen


for (int i = 0; i<10; i++)
   {
     
   
if (second()%10==i)
   digitalWrite(30+i,HIGH);
   else
   digitalWrite(30+i,LOW);
*/   
   
      
   
/* if (second()%10==2)
   digitalWrite(31,HIGH);
   else
   digitalWrite(31,LOW); 
 
if (second()%10==3)
   digitalWrite(32,HIGH);
   else
   digitalWrite(32,LOW);  
  
if (second()%10==4)
   digitalWrite(33,HIGH);
   else
   digitalWrite(33,LOW); 
 
if (second()%10==5)
   digitalWrite(34,HIGH);
   else
   digitalWrite(34,LOW);   
   
*/   
     
   
  




  int sensorValue = digitalRead(DCF_PIN);
   if (sensorValue) {
   if (!Up) {
        flankUp=millis();
        Up = true;
        
        lcd.setCursor(7,1);
        // lcd.print("*");
        lcd.write(1);  //Antennensymbol mit Signal
        
        
     
      }
    } else {
      if (Up) {
        flankDown=millis();
        
        lcd.setCursor(7,1);
        // lcd.print(" ");
        lcd.write(2);  // Antennensymbol ohne Signal
        
        
     //   lcd.setCursor(0,2);
     //   lcd.print("Cycle: ");
     //   lcd.setCursor(8,2);
     //   lcd.print("     ");
     //   lcd.setCursor(7,2);              
     //   lcd.print(flankUp-PreviousflankUp); 
     //   lcd.setCursor(12,2);
     //   lcd.print("ms");
        
        
     //   lcd.setCursor(0,3);
     //   lcd.print("Pulse : ");
     //   lcd.setCursor(7,3);
     //    lcd.print("      ");
     //   lcd.setCursor(7,3);
     //    lcd.print(flankDown - flankUp-20); // "-20" bedeutet -20 ms Zeitkoreektur ; variabel 
     //    lcd.setCursor(12,3);
     //   lcd.print("ms");
        
        PreviousflankUp = flankUp;
        Up = false;
//	digitalWrite(BLINKPIN, LOW);
      }              
    }
  
  digitalWrite(45,LOW);  // Pin für Sek Einer auf Masse legen


for (int i = 0; i<10; i++)

   {
      
if (second()%10==i+1)
   
   digitalWrite(30+i,HIGH);
   
   
   else
   digitalWrite(30+i,LOW);
   
   
   
    }
    

 digitalWrite(45,HIGH);  // Pin für Sek Einer auf +5v legen
 
 
 //-----------------------------------------------------------
 
 digitalWrite(44,LOW); // Pin für Sek Zehner auf Masse
 
 for (int i = 0; i<6; i++)

   {
      
if (second()/10==i+1)  // Sekunden Zehner

    
   digitalWrite(30+i,HIGH);
   else
   digitalWrite(30+i,LOW);
   }

digitalWrite(44,HIGH);

//-----------------------------------------------------------

 digitalWrite(43,LOW); // Pin für Min Einer auf Masse
 
 for (int i = 0; i<10; i++)

   {
      
if (minute()%10==i+1)  // Minuten Einer

    
   digitalWrite(30+i,HIGH);
   else
   digitalWrite(30+i,LOW);
   }

digitalWrite(43,HIGH);

//---------------------------------------------------------

 digitalWrite(42,LOW); // Pin für Min Zehner auf Masse
 
 for (int i = 0; i<6; i++)

   {
      
if (second()/10==i+1)  // Sekunden Zehner

    
   digitalWrite(30+i,HIGH);
   else
   digitalWrite(30+i,LOW);
   }

digitalWrite(42,HIGH);

//-----------------------------------------------------

digitalWrite(41,LOW); // Pin für Stunden Einer auf Masse
 
 for (int i = 0; i<10; i++)

   {
      
if (hour()%10==i+1)  // Stunden Einer

    
   digitalWrite(30+i,HIGH);
   else
   digitalWrite(30+i,LOW);
   }

digitalWrite(41,HIGH);

//----------------------------------------------------

digitalWrite(40,LOW); // Pin für Stunden Zehner auf Masse
 
 for (int i = 0; i<3; i++)

   {
      
if (hour()/10==i+1)  // Stunden Zehner

    
   digitalWrite(30+i,HIGH);
   else
   digitalWrite(30+i,LOW);
   }

digitalWrite(40,HIGH);

//--------------------------------------------------
 

}

Ich habe den Kode nur mal kurz überflogen.

Die Zeit die einzelne LEDs an sind, hängt von ihrer Nummer und der Gesamtanzahl LEDs dieser Stelle ab, je höher die Nummer, je kürzer der Anteil (der wieder von der Anzahl von LEDs für diese Stelle abhängt).

Du würdest mit einer anderen Methodik besser fahren.

Meine Empfehlung wäre:

Anzeigen einer Stelle wird zu einem Zustand.

Jeder Zustand dauert eine gleich lange Zeitscheibe.

Die Zustände werden dauernd durchlaufen.

Edit: die Ausgabe auf das LCD sollte auch zeitlich moderiert werden, also z.B. nur 1x die Sekunde erfolgen.

  lcd.createChar(1, AntenneSig);
  lcd.createChar(2, Antenne);

  lcd.begin(8, 2);

Sauberer wäre das begin vor dem create aufzurufen.

Hast du wirklich ein zweizeiliges Display mit 8 Zeichen? Das hat dann ja fast mehr Pins als Zeichen. ;)

  pinMode(DCF_PIN, INPUT);

Das ist die Grundeinstellung und zudem sollte man das auch dem DCF Objekt überlassen. (Das bekommt den Pin ja schon im Konstruktor)

Ich habe ein 16-stelliges LCD dran, es wird aber aber wie 2x8 behandelt.

Ich wollte ja mit dem jetzigem Programm Pins sparen, es werden jetzt für die LED Ansteuerung nur 15 Pins benötigt, 6 x für "Masse", die nacheinander durchgeschaltet wird und 9x für LED-Signal.

Die Andere Methode wäre eine feste Masse und 39 Pins für LED-Signal.

Das Muxen ist schon in Ordnung, die for's und die LCD Ausgabe sollten aber nicht der zeitbestimmende Faktor sein. ;)

Die Pins bezogen sich auf dein LCD.

Ich habe allen meinen LCD's so ein preiswertes I2C Backpack verpasst, neue würde ich nur noch mit dem Ding dran kaufen.

Wirklich testen kann ich das hier nicht, dazu müsste ich mir erst so eine Matrix bauen.

Schau mal wie dir der Ansatz gefällt:

// DCF Uhr mit LCD 16x1 und LED Punktanzeige

#include <LiquidCrystal.h>
#include <Wire.h>
#include <DCF77.h>
#include <Time.h>

const byte  dcfPin = 2;               // DCF-Signal Input-Pin

unsigned long flankUp;
unsigned long flankDown;
unsigned long PreviousflankUp;
bool Up = false;

const byte Zahlenpins[] = {30, 31, 32, 33, 34, 35, 36, 37, 38}; // LED-Pins für Zahlen (Beispiel)
const byte Massepins[] = {40, 41, 42, 43, 44, 45};      // Masse - Pins

time_t time;
DCF77 DCF = DCF77(dcfPin, digitalPinToInterrupt(dcfPin));
LiquidCrystal lcd(12, 13, 11, 7, 8, 9, 10);  // RS, RW, E, D4, D5, D6, D7

byte AntenneSig[8] =  // Antennen- Symbol mit Signal
{
  B01110,
  B10001,
  B10101,
  B01110,
  B00100,
  B00100,
  B01110,
  B11111
};

byte Antenne[8] =  // Antennen- Symbol ohne Signal
{
  B00000,
  B00000,
  B00100,
  B00100,
  B00100,
  B00100,
  B01110,
  B11111
};

unsigned long lastLcdPrint;
unsigned long lastMuxChange;
unsigned long topLoop;

const byte lcdUpdateInterval = 500;
const byte muxTimeSlice = 50;
byte currMux;

void setup() {
  Wire.begin();
  DCF.Start();

  lcd.begin(8, 2);
  lcd.createChar(1, AntenneSig);
  lcd.createChar(2, Antenne);

  //pinMode(dcfPin, INPUT);

  //  LED-pins
  for (int i = 0; i < 9; i++) {
    pinMode(Zahlenpins[i], OUTPUT);
  }

  // Massepins
  for (int i = 0; i < 6; i++) {
    pinMode(Massepins[i], OUTPUT);
  }
}

void p2DecimalPlus(byte val, byte behind = 8) {
  if (val < 10) {
    lcd.print(F("0"));
  }
  lcd.print(val);
  if (behind != 8) {
    lcd.print(behind);
  }
}

void loop() {
  topLoop = millis();

  time_t DCFtime = DCF.getTime();  // Check if new DCF77 time is available
  if (DCFtime != 0)  {
    setTime(DCFtime);
  }
  // Ausgabe
  if (topLoop - lastLcdPrint >= lcdUpdateInterval) {
    lastLcdPrint = topLoop;
    //  lcd.clear();
    lcd.setCursor(0, 0);
    p2DecimalPlus(hour(), ':');
    p2DecimalPlus(minute(), ':');
    p2DecimalPlus(second());

    lcd.setCursor (8, 0);
    lcd.print("   ");

    lcd.setCursor(1, 1);
    p2DecimalPlus(day(), '.');
    p2DecimalPlus(month());

    bool sensorValue = digitalRead(dcfPin);
    byte dispChar = 1;  //Antennensymbol mit Signal
    if (sensorValue) {
      if (!Up) {
        flankUp = topLoop;
        Up = true;
      }
    } else {
      if (Up) {
        flankDown = topLoop;
        dispChar = 2;  // Antennensymbol ohne Signal
        PreviousflankUp = flankUp;
        Up = false;
      }
    }
    lcd.setCursor(7, 1);
    lcd.write(dispChar);
  }

  if (topLoop - lastMuxChange >= muxTimeSlice) {
    lastMuxChange = topLoop;
    if (++currMux >= 6) {
      currMux = 0;
    }
    byte ledIndex;
    switch (currMux) {
      case 0: ledIndex = second() % 10; break;
      case 1: ledIndex = second() / 10; break;
      case 2: ledIndex = minute() % 10; break;
      case 3: ledIndex = minute() / 10; break;
      case 4: ledIndex = hour() % 10; break;
      case 5: ledIndex = hour() / 10; break;
    }
    for (byte idx = 0; idx < 6; idx++) {
      digitalWrite(45 - idx, currMux != idx); // Pin für die Stelle auf Masse legen
    }
    for (byte idx = 0; idx < 9; idx++) {
      digitalWrite(30 + idx, ledIndex == idx); // Pin für die LED auf 5V legen
    }
  }
}