Forum: Mikrocontroller und Digitale Elektronik If - Vergleich


von Bernd (Gast)


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
{

von Jim M. (turboj)


Lesenswert?

Das Intervall zerlegen in

15:25-24:00 und
00:00-01:15

macht Dir die Vergleiche viel einfacher.

von STK500-Besitzer (Gast)


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").

von Wolfgang (Gast)


Lesenswert?

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.

von Hugo H. (hugohurtig1)


Lesenswert?

Beitrag "Zeitvergleich zweier "Uhrzeiten""

zeigt das Prinzip.

Beide Uhrzeiten umrechnen in Minuten. Wenn BIS < AKT oder AKT < BIS 
weiter laufen lassen. Wenn BIS == AKT -> Ziel erreicht.

Setzt natürlich voraus, dass Du in Intervallen < 1 Minute vergleichst.

: Bearbeitet durch User
von W.S. (Gast)


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.

von A. S. (Gast)


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

von Hugo H. (hugohurtig1)


Lesenswert?

W.S. schrieb:
> Im Grunde mußt du Buch führen über Ereignisse, die zu vorgebbaren Zeiten
> geschehen sollen.

Nicht nötig.

von Hugo H. (hugohurtig1)


Lesenswert?

A. S. schrieb:
> Du hast nun das Problem, dass man auch bei Indizes für ringbuffer hat.

Er hat das Problem, dass man mit "Stunden und Minuten"-Vergleichen 
entweder ein Riesen-Konstrukt aufbaut oder einfach nur mit Minuten 
rechnet. Das letztere ist sinnvoll.

von Peter D. (peda)


Lesenswert?

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.

von Hugo H. (hugohurtig1)


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.
>
> Schmeiß also die >, < einfach raus.

Prima - noch einfacher :-) (stimmt, die > < Abfragen sind sinnlos und 
man kann sich die Umrechnung in Minuten sparen)

: Bearbeitet durch User
von Wolfgang (Gast)


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 vom Autor gelöscht.
von A. S. (Gast)


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.

von A. S. (Gast)


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.

von sid (Gast)


Lesenswert?

oooder

man packt einfach alles in eine unix timestamp
und hat die nächsten paar Jahre Ruhe :D

von 1574397863 bis 1574469863 .. done

von PittyJ (Gast)


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.

von Peter D. (peda)


Lesenswert?

A. S. schrieb:
> Das geht aber nur, wenn die rtcc nicht separat batterieversorgt ist. Und
> weder schalt- noch Uhrzeit sich ändern.

Du kannst auch den MC puffern, der AVR zieht <1µA im Power-Down. Die RTC 
weckt ihn dann kurz für den Vergleich auf.
Wenn der MC nicht gepuffert wird, geht es aber auch so:
Beitrag "Re: Zeitvergleich zweier "Uhrzeiten""

von Peter D. (peda)


Lesenswert?

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 
==.

von Bernd (Gast)


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
}

von Hugo H. (hugohurtig1)


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.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Bernd schrieb:
> funktionieren
> tut das nicht

Du hast ja auch die >, < drin gelassen.
Was stört Dich an der einfachen Variante, nur auf Gleichheit zu testen?

von Bernd (Gast)


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.

von Carl D. (jcw2)


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.

: Bearbeitet durch User
von Daniel A. (daniel-a)


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.

von Joe F. (easylife)


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.

: Bearbeitet durch User
von Peter D. (peda)


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.

von Hugo H. (hugohurtig1)


Lesenswert?

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" ?

von Peter D. (peda)


Lesenswert?

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.

von Teo D. (teoderix)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.