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.
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);
}
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.
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.
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
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.
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.
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.
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.
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;
// 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);
}
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:
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 ) .