If - Vergleich

Gast #6047571
Hallo,
Ich baue mir grade eine Schaltuhr nur leider funktioniert der Vergleich 
nicht richtig.

Der vergleich funktioniert so lange das die Bis Ausschalt Stunde und Bis 
Ausschalt Minute immer grösser sind als Ab Ausschalt Stunde und Ab 
Ausschalt Minute.

Das geht
15:25 - 18:55

Das geht nicht
15:25 - 01:15


Vielleicht könnte mir da einer weiter helfen was hier falsch mache.



1
//Ab Ausschalt Stunde
2
switch_buffer[0]
3
//Ab Ausschalt Minute
4
switch_buffer[1]
5
//Bis Ausschalt Stunde
6
switch_buffer[2]
7
//Bis Ausschalt Minute
8
switch_buffer[3]


1
if((RTC_TimeStructure.RTC_Hours > switch_buffer[0] ||           (RTC_TimeStructure.RTC_Hours == switch_buffer[0] &&   RTC_TimeStructure.RTC_Minutes >= switch_buffer[1] )) &&
2
(RTC_TimeStructure.RTC_Hours < switch_buffer[2] || (RTC_TimeStructure.RTC_Hours == switch_buffer[2] && RTC_TimeStructure.RTC_Minutes <= switch_buffer[3] )))         
3
{
Gast
Bernd schrieb:
> Der vergleich funktioniert so lange das die Bis Ausschalt Stunde und Bis
> Ausschalt Minute immer grösser sind als Ab Ausschalt Stunde und Ab
> Ausschalt Minute.

Wenn dein Programm auch so aussieht, sehe ich schwary.

Du kannst auch einfach die Stunden mit 100 erweitern und die Minuten 
dazuzählen (wenn du die Stunden mit 60 multiplizierst, bekommst du 
Sekunden heraus..).
Dann einfach zwei Werte vergleichen.

Bernd schrieb:
> Das geht nicht
> 15:25 - 01:15

Dafür brauchst du eine weitere Stelle ("Tag").
Gast
Bernd schrieb:
> Das geht nicht
> 15:25 - 01:15

Was auch immer da "gehen" sollte ...

In einem Fahrplan würdest du an der Stelle einen Verweis auf eine 
Fußnote "Ankunft am nächsten Tag" finden.

Füge zur "Bis Zeit" 24h hinzu, vielleicht geht es dann.
Gast
Bernd schrieb:
> Vielleicht könnte mir da einer weiter helfen was hier falsch mache.

Tja, so ist das eben mit Dingen, die zeitzyklisch geschehen sollen.

Im Grunde mußt du Buch führen über Ereignisse, die zu vorgebbaren Zeiten 
geschehen sollen.
Dazu brauchst du erstmal ne Systemuhr. Wenn diese die Mitternacht 
erreicht, also von 23.59 Uhr auf 00.00 Uhr, dann mußt du bei allen 
deinen Ereignis-Merkern das Flag "ist abgehakt" löschen und dann deine 
Liste durchsehen.

Etwa so im Prinzip:
1
 item = record
2
         sollzeit: longint;
3
         event: dein EventTyp;
4
         erledigt: boolean;
5
        end;
6

7
DeineTafel: array[1 bis sonstwo] of item:
8

9
// So und nun dein Uhr-Interrupt:
10
uhr_handler:
11
    uhrzeit:= uhrzeit + 1 Minute
12
    if uhrzeit > 23.59 Uhr
13
    then begin
14
           uhrzeit:= 00.00 Uhr
15
           for i:= 1 to sonstwo do
16
           DeineTafel[i].erledigt:= false;
17
         end
18

19
// und nun deine Zeitschaltuhr:
20
 for i:= 1 to sonstwo do
21
 begin
22
   if DeineTafel[i].sollzeit <= uhrzeit
23
      and
24
      DeineTafel[i].erledigt = false
25
      then begin
26
             DeineTafel[i].erledigt:= true
27
             Wirf_In_Queue(DeineTafel[i].event)
28
           end
29
 end;
30
uhr_handler_ende;

so einfach geht sowas (eigentlich...). Ich hab hier mal angenommen, daß 
dieser Uhr-Handler alle Minute einmal gestartet wird. Und was du mit den 
Events in der als vorhanden angenommenen Event-Queue machst, ist deine 
Sache.

W.S.
Gast
Du hast nun das Problem, dass man auch bei Indizes für ringbuffer hat.

1) lege fest, was passieren soll, wenn aus == ein (ist dann 24h aus oder 
ein?

2) unterscheide aus > ein (einfach, wie bisher)else (dann an bis 
Mitternacht und ggf. ab Mitternacht).

Je nach Antwort 1 wird aus dem > ein >=.

Alternative für den Else Zweig: vertausche die Aktion:


On = Zeit>=an && Zeit<aus;
Wenn an>aus dann On=!On
Peter D. schrieb:
> In der Regel prüfen Schaltuhren nur auf Gleichheit. Bei der
> Einschaltzeit wird eingeschaltet, bei der Ausschaltzeit aus. Dazwischen
> passiert nichts.
>
> Schmeiß also die >, < einfach raus.

Prima - noch einfacher :-) (stimmt, die > < Abfragen sind sinnlos und 
man kann sich die Umrechnung in Minuten sparen)
Gast
W.S. schrieb:
> Bernd schrieb:
>> Vielleicht könnte mir da einer weiter helfen was hier falsch mache.
>
> Tja, so ist das eben mit Dingen, die zeitzyklisch geschehen sollen.

Richtig spannend wird das bei der Umstellung von Sommer- auf Winterzeit, 
wenn es die Stunde von 02:00 bis 02:59 zwei mal gibt ;-)
Beitrag #6047645 wurde von einem Moderator gelöscht.
Gast
Peter D. schrieb:
> In der Regel prüfen Schaltuhren nur auf Gleichheit. Bei der
> Einschaltzeit wird eingeschaltet, bei der Ausschaltzeit aus. Dazwischen
> passiert nichts.

Das geht aber nur, wenn die rtcc nicht separat batterieversorgt ist. Und 
weder schalt- noch Uhrzeit sich ändern.
Gast
Hugo H. schrieb:
> Er hat das Problem, dass man mit "Stunden und Minuten"-Vergleichen
> entweder ein Riesen-Konstrukt aufbau

 Naja, das Problem hätte er genauso mit Minuten gehabt. Es wäre ihm da 
nur eher aufgefallen. So braucht er halt 3 Vergleiche statt einem. Bzw 
in Summe 9 statt 3, spart dafür 3 Umrechnungen in Minuten. Bei dem 
Codefragment (switch_buffer) macht es allerdings wenig Sinn, darüber zu 
diskutieren.
Gast
sid schrieb:
> oooder
>
> man packt einfach alles in eine unix timestamp
> und hat die nächsten paar Jahre Ruhe :D
>
> von 1574397863 bis 1574469863 .. done

War auch mein erster Gedanke. time_t daraus machen. Dann hat man eine 
'handliche' Integer Zahl und braucht nur einen Vergleich. Man kann auch 
Zeiten addieren, die Zeiträume vergleichen etc.
PittyJ schrieb:
> War auch mein erster Gedanke. time_t daraus machen. Dann hat man eine
> 'handliche' Integer Zahl und braucht nur einen Vergleich.

Will man täglich schalten, muß man vor dem Vergleich noch Modulo 86400 
rechnen. Ein < oder > kann man dann aber auch nicht feststellen, nur ein 
==.
Gast
Ich hab das jetzt mal bis 24:00Uhr versucht umzusetzen, funktionieren 
tut das nicht


Ausgeschaltet werden soll von:
15:22 - 02:30
1
//Ab Ausschalt Stunde
2
switch_buffer[0]
3
//Ab Ausschalt Minute
4
switch_buffer[1]
5
//Bis Ausschalt Stunde
6
switch_buffer[2]
7
//Bis Ausschalt Minute
8
switch_buffer[3]



1
 if (RTC_TimeStructure.RTC_Hours >= 0)
2
  {
3
  if ((RTC_TimeStructure.RTC_Hours > switch_buffer[0] || 
4
         (RTC_TimeStructure.RTC_Hours == switch_buffer[0] && 
5
          RTC_TimeStructure.RTC_Minutes >= switch_buffer[1] )) &&
6
         (RTC_TimeStructure.RTC_Hours < switch_buffer[2] ||     
7
         (RTC_TimeStructure.RTC_Hours == switch_buffer[2] && 
8
          RTC_TimeStructure.RTC_Minutes <= switch_buffer[3] )))       
9
     {
10

11
     }
12
  }
13
 else if ((RTC_TimeStructure.RTC_Hours > switch_buffer[0] || 
14
         (RTC_TimeStructure.RTC_Hours == switch_buffer[0] && 
15
          RTC_TimeStructure.RTC_Minutes >= switch_buffer[1] )) &&
16
         (RTC_TimeStructure.RTC_Hours < switch_buffer[2] ||     
17
         (RTC_TimeStructure.RTC_Hours == switch_buffer[2] && 
18
          RTC_TimeStructure.RTC_Minutes <= switch_buffer[3] )))         
19
{
20

21
}
Bernd schrieb:
> Ich hab das jetzt mal bis 24:00Uhr versucht umzusetzen, funktionieren
> tut das nicht
>
> Ausgeschaltet werden soll von:
> 15:22 - 02:30
> //Ab Ausschalt Stunde
> switch_buffer[0]
> //Ab Ausschalt Minute
> switch_buffer[1]
> //Bis Ausschalt Stunde
> switch_buffer[2]
> //Bis Ausschalt Minute
> switch_buffer[3]
1
if (RTC_TimeStructure.RTC_Hours   == switch_buffer[0] &&
2
    RTC_TimeStructure.RTC_Minutes == switch_buffer[1]    )
3
  {
4
    ... Ausschalten
5
  }
6

7
if (RTC_TimeStructure.RTC_Hours   == switch_buffer[2] &&
8
    RTC_TimeStructure.RTC_Minutes == switch_buffer[3]   )
9
  {
10
    ... Einschalten
11
  }

Mindestens 1 mal pro Minute prüfen ... frei nach PeDa

Wobei dann in der "wieder Einschaltzeit" eher 02:31 stehen sollte.
Gast
Peter D. schrieb:
>
> Du hast ja auch die >, < drin gelassen.
> Was stört Dich an der einfachen Variante, nur auf Gleichheit zu testen?

Ich würde gerne das in den Ausschalt Zeitraum nicht wieder eingeschaltet 
werden soll.
Ausgeschaltet werden soll von:
15:22 - 02:30

Das in den IF-Vergleich zu schreiben das bekomm ich nicht umgesetzt.



So wie von Hugo vorgeschlagen auf Gleichheit zu testen funktioniert, 
aber danach kann ich ja wieder einschalten.
Bernd schrieb:
> Peter D. schrieb:
>>
>> Du hast ja auch die >, < drin gelassen.
>> Was stört Dich an der einfachen Variante, nur auf Gleichheit zu testen?
>
> Ich würde gerne das in den Ausschalt Zeitraum nicht wieder eingeschaltet
> werden soll.
> Ausgeschaltet werden soll von:
> 15:22 - 02:30
>
> Das in den IF-Vergleich zu schreiben das bekomm ich nicht umgesetzt.
>

Es soll eher um 15:22 ausgeschaltet werden und um 02:30 (nächster Tag) 
wieder eingeschaltet werden. Das sind separate Aktionen mit einfacher 
Identität als Bedingung.
So machen das auch "echte" elektronische Schaltuhren, allerdings nicht 
die mechanischen, die tatsächlich zwischen 15:33 und 02:30 den Schalter 
auf "aus" halten. Die elektronischen würden, hätte man das nach 15:21 
aktiviert, erst am Folgetag wie gewünscht funktionieren.
Sowas wird viel einfacher, wenn man modulo verwendet. Einfach alles mod 
24*60 rechnen, und start zum Nullpunkt machen, dann kann man schauen, ob 
mehr Zeit vergangen ist, als das Interval lang ist.
1
// For numbers 0 to 1440 (=24*60), 16 bits would have been enough, but I've used 32 here for the people who are going to forget to increase it later when they add seconds, or upgread to yearly intervals, or do similar things. 
2
uint_least32_t now   = (  now_h*60 +   now_m) %(24*60);
3
uint_least32_t start = (start_h*60 + start_m) %(24*60);
4
uint_least32_t end   = (  end_h*60 +   end_m) %(24*60);
5

6
// check if now is in interval [start, end), with now, start and end being in (mod 24*60)
7
// 24*60 was added to prevent underflows, uint_least32_t has a moduli for underflows which is not a multiple of 24*60, which would otherwise lead to wrong results in that case.
8
bool is_in_range = (uint_least32_t)(24*60 + now - start) %(24*60) < (uint_least32_t)(24*60 + end - start) %(24*60);

PS: Der Code reagiert so, wie das was Carl D. als typisch für 
mechanische Schaltuhren bezeichnet.
Ich finde das Auswerten in Minuten auch am übersichtlichsten.
1
uint8_t  state;
2
uint16_t minutes_off;
3
uint16_t minutes_on;
4
uint16_t minutes_now;
5

6
minutes_off = switch_buffer[0] * 60 + switch_buffer[1];
7
minutes_on  = switch_buffer[2] * 60 + switch_buffer[3];
8
minutes_now = RTC_TimeStructure.RTC_Hours * 60 + RTC_TimeStructure.RTC_Minutes;
9

10
if (minutes_off < minutes_on) // on over midnight
11
  state = (minutes_now >= minutes_on || minutes_now < minutes_off);
12
else
13
  state = (minutes_now >= minutes_on && minutes_now < minutes_off);
14

15
// state == 1: ON
16
// state == 0: OFF

Vorteil von Auswertung mit >= und < ist, dass man die Uhr (das Programm) 
auch innerhalb eines Intervals starten kann und der Ausgang hat sofort 
den korrekten Schaltzustand.
Bei "==" muss man unter Umständen warten bis entweder Ein- oder 
Ausschaltpunkt erreicht wird, damit der Ausgang mit Sicherheit den 
korrekten Zustand hat.
Z.B. die ZUD 132 von meiner Gasheizung schaltet nur bei Gleichheit um. 
Je Ausgang sind bis zu 8 Ein-und Ausschaltzeiten programmierbar, die mit 
Wochentagen verknüpft werden können.
Hat man die Uhrzeit oder Schaltzeiten geändert, kann man manuell 
zwischen ein und aus umschalten.
Schaltuhren mit Bereichstest sind mir nicht bekannt.
Bernd schrieb:
> So wie von Hugo vorgeschlagen auf Gleichheit zu testen funktioniert,
> aber danach kann ich ja wieder einschalten.

In der Regel ist es erwünscht, daß man die Uhr überstimmen kann und sei 
es nur zu Testzwecken. Z.B. wenn der Schornsteinfeger die Abgasprüfungen 
macht.
Peter D. schrieb:
> In der Regel ist es erwünscht, daß man die Uhr überstimmen kann und sei
> es nur zu Testzwecken.

Ja, also Ein/Aus/Auto, sollte schon zur Verfügung stehen.

Hugo H. schrieb:
> Bernd schrieb:
>> So wie von Hugo vorgeschlagen auf Gleichheit zu testen funktioniert,
>> aber danach kann ich ja wieder einschalten.
>
> Ich denke, das Programm soll das machen - was erzählst Du denn von "aber
> danach kann ich ja wieder einschalten" ?

Da geht dann auch mit "Ein/Aus/Auto", den gewünschten Zustand 
herzustellen und sofort wieder auf Auto zu stellen. Dann vergisst man 
das nicht und merkt es evtl. erst, wenn's bereits zu spät ist.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 6 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.