Übergang bei 59min +1 auf 1Std und 0 min

Hallo zusammen

Für mein Schaltuhrprojekt möchte ich einen Wert ,der mit einem Incrementalgeber verändert wird, auf einem LCD ausgeben und zwar in der Form von Minuten und Stunden.
Hierzu muß ich ab dem Wert 59 dann den Minutenwert wieder auf 00 setzen und den Stundenwert dann um 1 erhöhen.
Ebenso wenn der Minutenwert von 00 auf 59 dann sinkt-> Stundenwert um 1 reduzieren.
Leider finde ich nicht raus wie ich das anstellen kann. Weiß vieleicht jemand wie man sowas umsetzt.

Vielen Dank Rudi

minuten ++;
if (minuten >59)
{ minuten = 0; 
  stunden ++;}

minuten --;
if (minuten < 0 && stunden >0)
{ minuten = 59 ; 
   stunden --;}
else
{ minuten = 0;}

Grüße Uwe

Wow das geht ja einfach.
Werde es heute abend umsetzen.

Vielen dank Uwe

Hallo Uwe

ich habe den Sketch ausprobiert. die Hochschaltung funktioniert. Doch werden die Minuten nicht auf 0 gesetzt.
Das währe die Befehlszeile { minuten = 0;

Ich habe zur Sicherheit mal den kompletten Sketch eingestellt:

// Schaltuhr für Elektroheizung
//
// I assume you know how to connect the DS1302 and LCD.
// DS1302:  RST pin    -> Arduino Digital 10
//          DAT pin   -> Arduino Digital 11
//          CLK pin  -> Arduino Digital 12
//          VCC über eine Diode an +5V da sich die Batterei sonst eventuell entladen kann
// LCD:     DB7       -> Arduino Digital 7
//          DB6       -> Arduino Digital 6
//          DB5       -> Arduino Digital 5
//          DB4       -> Arduino Digital 4
//          E         -> Arduino Digital 9
//          RS        -> Arduino Digital 8

#include <LiquidCrystal.h>
#include <DS1302.h>

int AusgangLadung = 13;
float Ladezeit;
int ZeitLadeende;
int minuten;
int Aktuell;
Time t;
int encoderPin1 = 2;
int encoderPin2 = 3;

int stunden;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;
// Den DS1302 initialisieren
DS1302 rtc(10, 11, 12);

// Das LCD initialisieren
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

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

  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //der Pullupwiderstand wird aktiviert
  digitalWrite(encoderPin2, HIGH); //der Pullupwiderstand wird aktiviert

  //bei negativer oder positiver Flanke wird der Interrupt aktiviert
  //interrupt 0 an (pin 2), interrupt 1 an (pin 3) 
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);


  rtc.halt(false);  // setzt die Uhr in den run-Modus
  rtc.writeProtect(false);  // Hebt den Schreibschutz auf

  // Einstellen auf ein LCD mit 16x2 Zeichen
  lcd.begin(16, 4);

  // hier wird die Zeit gesetzt ( Achtung wenn das Einstellen erfolgt ist dann auskommentieren und nochmals übertragen )
  ////////rtc.setTime(21, 05, 0);
}
void loop()
{
  // Uhrzeit anzeigen
  lcd.setCursor (0, 0);
  lcd.print("Uhrzeit");
  lcd.setCursor(8, 0);
  lcd.print(rtc.getTimeStr());


  t = rtc.getTime();

  Serial.print(t.date, DEC); // tag
  Serial.print(".");
  Serial.print(t.mon,DEC);  // monat
  Serial.print(".");
  Serial.print(t.year, DEC);  //jahr
  Serial.print("  ");
  Serial.print(t.dow, DEC);  //wochentag mo=1, di=2 ...

  Serial.println("  ");

  Serial.print(t.hour, DEC); //stunde
  Serial.print(":");
  Serial.print(t.min,DEC);  // minute
  Serial.print(":");
  Serial.print(t.sec, DEC);  //sekunde
  Serial.print("  ");

  Serial.println(encoderValue);
  lcd.setCursor (0, 1);
  lcd.print ("Ladedauer");
  minuten = (encoderValue /4*10); //Umrechnung der Inkrementwerte in Schritte zu 10 für die Minuten Schrittwerte
  lcd.setCursor (10, 1);
  lcd.println (minuten);
  delay(10); //just here to slow down the output, and show it will work  even during a delay







lcd.setCursor (2, 2);
lcd.print ("Stunden");
lcd.println (stunden);
}

void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if((sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) && minuten < 600) encoderValue ++; // Ladezeiten über 600 min nicht möglich
  if((sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000) && minuten > 0) encoderValue --;   // Ladezeiten unter 0 min nicht möglich
    
    if (minuten >50)
{ minuten = 0;
stunden ++;}                                                                 

if (minuten < 0 && stunden >0)
{ minuten = 50 ; 
  stunden --;}
else
{ minuten = 0;}                                                      
                                                                     
  lastEncoded = encoded; //store this value for next time

  // 1s Warten bis Programm weitergeführt wird
  delay (100);
}

Kannst Du mir helfen ?

Vielen Dank Rudi

if((sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011) && minuten < 600) encoderValue ++; // Ladezeiten über 600 min nicht möglich
....

if (minuten >50)
{ minuten = 0;
stunden ++;}

if (minuten < 0 && stunden >0)
{ minuten = 50 ;
stunden --;}
else
{ minuten = 0;}

Wieso kontrollierst Du in der if Anweisung ob Minuten kleiner als 600 sind ?
Haben bei Dir die Stunden 50 Minuten?
Grüße Uwe

hi,

ich versteh' diesen teil nicht:

minuten --;                     //minuten minus 1
if (minuten < 0 && stunden >0)   //wenn minuten kleiner 0 dann minuten = 59
{ minuten = 59 ; 
   stunden --;}
else
{ minuten = 0;}               //wenn minuten größer oder gleich 0                                     
                                     //dann minuten = 0 WARUM??

oder willst Du damit minuten auf 0 setzen wenn stunden schon 0 ist? dann stimmt aber die if else abfrage nicht, weil er das nur dann machen darf, wenn beide bedingungen in der if-abfrage nicht zutreffen. er geht aber auch dann ins else, wenn nur eine der beiden falsch ist.

gruß stefan

Das ist um einen Unterlauf zu unterbinden und damit nicht negative Zeit zu erhalten sondern auf 0 zu bleiben.
Grüße Uwe

Vordergründig scheint der "&&" Operator in folgendem Vergleich das Problem zu sein.

if (minuten < 0 && stunden >0)

Tatsächlich ist aber der ganze Ansatz schräg. Besser wäre es nur mit einer Einheit (üblicherweise Sekunden) zu rechnen und nur die Ausgabe auf Stunden / Minuten / Sekunden umzurechnen.

D.h.

Minuten = Sekunden / 60;
Stunden = Minuten / 60;

AusgabeStunden = Stunden;
AusgabeMinuten = Minuten - Stunden * 60;
AusgabeSekunden = Sekunden - Minuten * 60;

// Alternativ
AusgabeMinuten = Minuten % 60;
AusgabeSekunden = Sekunden % 60;

Rauf und runter geht es dann so:

Sekunden += 60; // 1 Minute mehr
Sekunden += 600; // 10 Minuten mehr
Sekunden += 3600; // 1 Stunde mehr
Sekunden = Sekunden > 60? Sekunden - 60: 0;  // 1 Minute weniger
Sekunden = Sekunden > 600? Sekunden - 600: 0;  // 10 Minuten weniger
Sekunden = Sekunden > 3600? Sekunden - 3600: 0;  // 1 Stunde weniger

Verzweigungen mit "if" Statements halte ich für sowas unangebracht weil sie semantisch etwas anderes ausdrücken als ein Ausdruck mit "?". Außerdem finde ich "?" lesbarer, aber das könnte Geschmackssache sein :wink:

hi,

dann ist da aber ein fehler:

if (minuten < 0 && stunden >0) in den if zweig geht er, wenn BEIDE bedingungen zutreffen, in allen anderen fällen setzt er minuten auf 0. ins else geht er, wenn nicht BEIDE bedingungen zutreffen. also wenn minuten 15 ist, setzt er sie auch auf 0.

gruß stefan

Nachtrag: ich sehe gerade, dass nach oben nicht mehr als 600 Minuten erlaubt sind, also:

Sekunden = Sekunden < 360000 - 60? Sekunden + 60: 360000; // 1 Minute mehr
Sekunden = Sekunden < 360000 - 600? Sekunden + 600: 360000; // 10 Minuten mehr
Sekunden = Sekunden < 360000 - 3600? Sekunden + 3600: 360000; // 1 Stunde mehr

Und noch ein Nachtrag: für alle die den "?" Operator nicht mögen:

Statt

Sekunden = Sekunden < 360000 - 60? Sekunden + 60: 360000;

Kann man auch

Sekunden = min(Sekunden + 60, 36000);

schreiben.

Und statt

Sekunden = Sekunden > 60? Sekunden - 60: 0;  // 1 Minute weniger

geht auch

Sekunden = max(Sekunden - 60, 0);

Das finde ich besser weil es die Semantik deutlicher beschreibt. Allerding muss man dann auf jeden Fall mit vorzeichenbehafteten Zahlen rechnen.

Eisebaer:
hi,

dann ist da aber ein fehler:

if (minuten < 0 && stunden >0) in den if zweig geht er, wenn BEIDE bedingungen zutreffen, in allen anderen fällen setzt er minuten auf 0. ins else geht er, wenn nicht BEIDE bedingungen zutreffen. also wenn minuten 15 ist, setzt er sie auch auf 0.

gruß stefan

Da hast Du recht.
also laut meinem Vorschlag ist es so dann richtig:

minuten --;                     //minuten minus 1
if (minuten < 0)    //wenn minuten kleiner 0 dann minuten = 59
if (stunden >0)
{ minuten = 59 ; 
   stunden --;}
else
{ minuten = 0;}

Natürlich ist der Ansatz von Udo auch nicht falsch einfach die Variable in Sekunden/minuten lassen und nur zur Anzeige in Sekunden Minuten und Stunden umrechnen.

Rudi01 bitte verzeih mir meinen Fehler.

Grüße Uwe

Wow das sind ja eine ganze Menge an Hilfen .
Vielen Dank Allen.
Die Begrenzung auf 600 min kommt daher dass ich die Schaltzeit nicht mehr als 10 Stunden einstellbar möchte.
Die komischen 50 anstatt 59 beim Übertrag auf die Stunden kommen weil ich die Minuten bei jedem Schritt um 10 ändern will damitt die Einstellung der Zeit schneller geht und die Auflösung reicht vollkommen.
Nochmals Allen vielen Dank demnächst werde ich`s umsetzen.

Rudi

ok, 50 oder 59 ist in diesem Fall gleichwertig. Aber bitte schreib dennoch 59 weil wenn Du später doch nicht 10 Min Schritte haben willst sondern 5 Min Schritte hast Du einen Fehler den Du suchen mußt weil Du es bis dahin vergessen hast.

Grüße Uwe

Hallo

im Moment probiere ich gerade die Programierung.
Es gibt immernoch das Problem dass beim Übergang von von 60 auf 61 Minuten die Stunden zwar um 1 erhöht werden die Minuten aber nicht auf 0 gesetzt werden .
Die Änderung der Stunden geschieht auch erst beim Übergang von 60 auf 61 Minuten
Wenn die Minuten über 60 sind werden die Stunden bei jeder Minutenerhöhung auch um 1 erhöht.
Wenn die Minuten über 60 sind werden die Stunden bei jedr Minutenreduzierung auch um 1 erhöht
Unter 60 Minuten ändern sich die Stunden nicht
Erst ab -1 Minuten werden die Stunden pro Minutenrduzierung um 1 reduziert.

Ligt es vieleicht an der Befehlszeile: minuten = 0;

Vorerst mal Vielen Dank Rudi

Bitte Deinen aktuellen Sketch
Danke Uwe

Hallo Uwe

hier der gesamte Sketch

// Schaltuhr für Elektroheizung
//
// I assume you know how to connect the DS1302 and LCD.
// DS1302:  RST pin    -> Arduino Digital 10
//          DAT pin   -> Arduino Digital 11
//          CLK pin  -> Arduino Digital 12
//          VCC über eine Diode an +5V da sich die Batterei sonst eventuell entladen kann
// LCD:     DB7       -> Arduino Digital 7
//          DB6       -> Arduino Digital 6
//          DB5       -> Arduino Digital 5
//          DB4       -> Arduino Digital 4
//          E         -> Arduino Digital 9
//          RS        -> Arduino Digital 8

#include <LiquidCrystal.h>
#include <DS1302.h>


int AusgangLadung = 13;
float Ladezeit;
int ZeitLadeende;
int minuten;
int Aktuell;
Time t;
int encoderPin1 = 2;
int encoderPin2 = 3;

int stunden;

volatile int lastEncoded = 0;
volatile long encoderValue = 0;

long lastencoderValue = 0;

int lastMSB = 0;
int lastLSB = 0;
// Den DS1302 initialisieren
DS1302 rtc(10, 11, 12);

// Das LCD initialisieren
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

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

  pinMode(encoderPin1, INPUT);
  pinMode(encoderPin2, INPUT);

  digitalWrite(encoderPin1, HIGH); //der Pullupwiderstand wird aktiviert
  digitalWrite(encoderPin2, HIGH); //der Pullupwiderstand wird aktiviert

  //bei negativer oder positiver Flanke wird der Interrupt aktiviert
  //interrupt 0 an (pin 2), interrupt 1 an (pin 3) 
  attachInterrupt(0, updateEncoder, CHANGE);
  attachInterrupt(1, updateEncoder, CHANGE);


  rtc.halt(false);  // setzt die Uhr in den run-Modus
  rtc.writeProtect(false);  // Hebt den Schreibschutz auf

  // Einstellen auf ein LCD mit 16x2 Zeichen
  lcd.begin(16, 4);

  // hier wird die Zeit gesetzt ( Achtung wenn das Einstellen erfolgt ist dann auskommentieren und nochmals übertragen )
  ////////rtc.setTime(21, 05, 0);
}
void loop()
{
  // Uhrzeit anzeigen
  lcd.setCursor (0, 0);
  lcd.print("Uhrzeit");
  lcd.setCursor(8, 0);
  lcd.print(rtc.getTimeStr());


  t = rtc.getTime();

  Serial.print(t.date, DEC); // tag
  Serial.print(".");
  Serial.print(t.mon,DEC);  // monat
  Serial.print(".");
  Serial.print(t.year, DEC);  //jahr
  Serial.print("  ");
  Serial.print(t.dow, DEC);  //wochentag mo=1, di=2 ...

  Serial.println("  ");

  Serial.print(t.hour, DEC); //stunde
  Serial.print(":");
  Serial.print(t.min,DEC);  // minute
  Serial.print(":");
  Serial.print(t.sec, DEC);  //sekunde
  Serial.print("  ");

  Serial.println(encoderValue);
  lcd.setCursor (0, 1);
  lcd.print ("Minuten");
  minuten = (encoderValue /4); //Umrechnung der Inkrementwerte in Schritte zu 10 für die Minuten Schrittwerte
  lcd.setCursor (10, 1);
  lcd.println (minuten);
  delay(10); //just here to slow down the output, and show it will work  even during a delay







lcd.setCursor (4, 2);
lcd.print ("Stunden");
lcd.setCursor (12, 2);
lcd.println (stunden);
}

void updateEncoder(){
  int MSB = digitalRead(encoderPin1); //MSB = most significant bit
  int LSB = digitalRead(encoderPin2); //LSB = least significant bit

  int encoded = (MSB << 1) |LSB; //converting the 2 pin value to single number
  int sum  = (lastEncoded << 2) | encoded; //adding it to the previous encoded value

  if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)  encoderValue ++; 
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)  encoderValue --; 
    
    if (minuten >59)
{ minuten = 0;
stunden ++;}                                                                 

if (minuten < 0)
if (stunden >0)
{ minuten = 59 ; 
  stunden --;}
else
{ minuten = 0;}                                                      
                                                                     
  lastEncoded = encoded; //store this value for next time

  // 1s Warten bis Programm weitergeführt wird
  delay (100);
}

Hallo

ich bins wieder.
wenn ich die Zeile : minuten = 0;
durch : encoderValue = 0;
ersetze funktioniert es einigermasen . Der Stundenwert wird um 4 erhöht.
Das ligt wahrscheinlich daran dass der Inkrementalgeber immer pro Raste 4 Signale liefert . desshalb muss ich die "" encoderValue " Konstante auch durch 4 teilen um eine Minutenerhöhung um 1 zu erreichen.

An was könnte es ligen dass die Rücksetzen der Minuten auf 0 nicht gelingt?

Vieleicht funktioniert es nicht so richtig weil Du die Umrechnung encoderValue zu Minuten in Zeile 99 außerhalb der interruptroutine machst

minuten = (encoderValue /4); //Umrechnung der Inkrementwerte in Schritte zu 10 für die Minuten Schrittwerte

Die In/Decrementierung in Zeile 123 ff aber innerhalb der Interruproutine.

 if(sum == 0b1101 || sum == 0b0100 || sum == 0b0010 || sum == 0b1011)  encoderValue ++; 
  if(sum == 0b1110 || sum == 0b0111 || sum == 0b0001 || sum == 0b1000)  encoderValue --; 
    
    if (minuten >59)
{ minuten = 0;
stunden ++;}                                                                 

if (minuten < 0)
if (stunden >0)
{ minuten = 59 ; 
  stunden --;}
else
{ minuten = 0;}

Den update der Zeit mußt Du aber zwischen encoderValue ++; bzw encoderValue --; und der Kontrolle des Über/unterlauflaufs der Minuten in der Interruptroutine machen.

Welchen Encoder hast Du eigentlich daß Du ihn so kompliziert lesen mußt?
Wenn es ein normaler 2 Phasen Encoder ist dann reicht ein Interrupteingang auf eine der Phasen des Encoders (nehmen wir mal encoderPin2 und die Auslösung des Interrupts entweder RISING oder FALLING) und in der Interruptroutine eine Kontrolle ob die 2. Phase H oder L ist, um die Richtung zu bestimmen. Entsprechend Inkrementierst oder decrementierst Du die Minuten:

setup()
{...
attachInterrupt(0, updateEncoder, RISING);
...}

updateEncoder()
{
if (digitalRead(encoderPin2)) {minuten ++;}
else {minuten--;}

if (minuten >59)
{ minuten = 0;
stunden ++;}                                                                 

if (minuten < 0)
if (stunden >0)
{ minuten = 59 ; 
  stunden --;}
else
{ minuten = 0;} 
}

Grüße Uwe

Hi Uwe

gerade bin ich am Testen Deines Sketch-Vorschlages.
Doch die Delaration der Variablen "updateEncoder" mittels "int updateEncoder"
führt zu Fehlermeldungen:

In function 'void setup()':
9: error: invalid conversion from 'int' to 'void ()()'
9: error: initializing argument 2 of 'void attachInterrupt(uint8_t, void (
)(), int)'
At global scope:
12: error: ISO C++ forbids declaration of 'updateEncoder' with no type
In function 'int updateEncoder()':

Mein Sketch:

int minuten;
int stunden;
int updateEncoder;
int encoderPin2;


void setup()
{
 
attachInterrupt(0, updateEncoder, RISING);
}

updateEncoder()
{
if (digitalRead(encoderPin2)) {minuten ++;}
else {minuten--;}

if (minuten >59)
{ minuten = 0;
stunden ++;}                                                                 

if (minuten < 0)
if (stunden >0)
{ minuten = 59 ; 
  stunden --;}
else
{ minuten = 0;} 
}

Kannst Du mir sagen wie ich die Varablen richtig deklariere.

Eine Frage habe ich noch . Du gibst als Hilfe die Zeilennummer an und ich hab schon mehrmals beobachtet dass Sketche mit Zeilennummern versehen sind .
Lässt sich das vieleicht in der IDE einstellen ( trotz langen suchen habe ich leider nichts gefunden ) .

Danke Rudi