If - Vergleich

Gast #6047571
Lesenswert?

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 #6047582
Lesenswert?

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 #6047621
Lesenswert?

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 #6047626
Lesenswert?

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
Gast #6047643
Lesenswert?

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 #6047713
Lesenswert?

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 #6047726
Lesenswert?

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 #6047971
Lesenswert?

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.
Gast #6050460
Lesenswert?

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
}
#6050489
Lesenswert?

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 #6050805
Lesenswert?

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.
#6050828
Lesenswert?

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.
#6050896
Lesenswert?

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.
#6050957
Lesenswert?

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.
#6051001
Lesenswert?

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.
#6051074
Lesenswert?

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

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren