Forum: Mikrocontroller und Digitale Elektronik Variable das ereignis diese Minute schon ausgeführt wurde


von Kai B. (tekasiko)


Angehängte Dateien:

Lesenswert?

Hallo Alle zusammen,

habe den Bascom Code angehängt.

Folgendes Problem habe ich zu lösen, komm aber nicht drauf wie.

Ich habe einen Timer, der eine Zeit aus einem I2C EEprom Liest, und von
diese Zeit rückwärts zählt.

Dies geschiet in eine "Do" "Loop" funktion.

Funktioniert so auch Prima.

Nun möchte ich nach jeder Minute die aktuellen Wert für die Minte aus
dem EEprom lesen und anschliesen um 1 reduzieren.

Genau so verhält es sich für die Stunde.

Die dafür benötigten Subroutinen usw. habe ich ja auch, diese
Funktionieren auch.

Das Problem ist nun, da die Zeit geloopt wird, habe ich Lese eeprom und
schreibe eeprom eben im Do-Loop teil, um immer wieder abzufragen ob
gewisses ereignis "If sekunde = 59" bzw. "If minute = 59 and Sekunde =
59" abzufragen

Wenn dies eintritt sollte er eine minute bzw eine Stunde Abziehen

Das Problem ist, das dieser Stand sekunde = 59 ja immer 1 Sekunde
andauert und da es im Loop ist, wird diese Aktion ja ca. 100 mal
ausgeführt. somit Spielt alles verückt.

Wie kann ich es machen, das er "Lese und Schreibe eeprom bei sek. = 59
und "sek. und min. = 59 nur einmal ausführt bis diese Ereignisse nochmal
eintreten???

Jetzt benötige ich eine Variable, die dem Program sagt das diese 
Ereignis diese Minute schon ausgeführt wurde

Wie kann ich diese einbinden?
 Für eure Hilfe bin ich euch sehr dankbar.

lG Kai

von Karl H. (kbuchegg)


Lesenswert?

1
   IF irgendeine_Bedingung_bei_dir_eben_die_Zeit THEN
2
     
3
     IF DO_ACTION = 0 THEN     ' Aktion schon gemacht ?
4
5
       DO_ACTION = 1           ' Nein, Aktion machen, aber merken, dass
6
                               ' die Aktion jetzt durchgeführt wurde
7
                               ' wenn die Zeitbedingung danach wieder wahr
8
                               ' ergibt, wird dadurch die Aktion nicht mehr
9
                               ' ausgeführt
10
11
                               ' und jetzt die bewusste Altion
12
       mache was auch immer es zu machen gibt
13
14
     ENDIF
15
16
   ELSE                        ' Zeitbedingung war nicht wahr
17
     DO_ACTION = 0             ' dafür sorgen, dass die Aktion beim nächsten
18
                               ' Übereinstimmung der Zeitbedinung wieder gemacht
19
                               ' wird
20
   ENDIF

DO_ACTION ist die Variable, die das steuert. Du musst sie dann auch noch 
am Anfang definieren. So wie alle Variablen

von HappyHacker (Gast)


Lesenswert?

Ich bin etwas irritiert. Wenn Du soweit gekommen bist, scheiterst Du am 
Einbinden einer Variable?

von Kai B. (tekasiko)


Lesenswert?

Vielen Vielen Dank :-)

Ich werd es mal testen und hofen das es geht.

von MWS (Gast)


Lesenswert?

Wird nicht wirklich erfolgreich sein:
1
Dim ..., Stunde As Byte
2
...Stunde = -1 Then Goto Countdown_stop

von Karl H. (kbuchegg)


Lesenswert?

Kai Burghart schrieb:
> Vielen Vielen Dank :-)
>
> Ich werd es mal testen und hofen das es geht.

Das hoffe ich mal für dich.
In einen Spaghetticode bei dem laufend hin und hergesprungen wird, ist 
es nun mal schwer im nachhinein noch Designfehler auszubügeln, ohne das 
alles auseinanderfällt.

von Kai B. (tekasiko)


Lesenswert?

Hallo MWS,

diese Funktion mit if Stunde = -1 funktioniert aber,

Ich weis das es logischerweise ein Integer sein sollte, weis aber nicht 
warum ich mit dem Byre auch ins minus gehen kann??

Aber es funktioniert.

von Achim M. (minifloat)


Lesenswert?

Kai Burghart schrieb:
> logischerweise ein Integer

Wieviel Bit ist die int-Variable breit?
Außerdem kann ein Byte auch den Wert "-1" enthalten, wenn man die 255 
nach Zweierkomplement interpretiert. mfg mf

von Kai B. (tekasiko)


Lesenswert?

Hallo nochmal,

ich bekomme es einfach nicht hin.

@ Happy Hacker,

ja stimmt schon, habs schon wirklich weit geschaft, aber ich bin 
absoluter newby und der Code der oben ist, hat mich ungefähr schon ein 
halbes Jahr die nächte geraubt.

Wemm ich dan so kurz vorm Ziel für dich wohl sehr einfache aufgabe habe, 
ist das sehr ärgerlich.

Aber ich bin schon auf einem sehr guten Weg denke ich und hab schon 
soviel hier gelernt dafür bin ich euch allen sehr dankbar.


Also zurück zu meinem Problem:

Hier der Ausschnitt aus meinem Programm:

Timer1 = Timervorgabe
Dim Do_action As Byte

Do

Portb.4 = 1


If Sekunde = 59 And Minute = 59 And Stunde = -1 Then Goto Countdown_stop
If Sekunde = 59


If Do_action = 0 Then

   Do_action = 1

Goto Abzug_m

 End If

   Else
     Do_action = 0


   End If


'If Minute = 59 And Sekunde = 59 Then Goto Abzug_s

Loop
Wait 1
Timer_irq:
   Timer1 = Timervorgabe
   Sekunde = Sekunde - 1
   If Sekunde = -1 Then
      Sekunde = 59
      Minute = Minute - 1
      If Minute = -1 Then
         Minute = 59
         Stunde = Stunde - 1

      End If
   End If

Cls


Was mach ich falsch?

Selbes problem, alles spielt verückt weil er sich nicht merkt dass ich 
diese minute schon abgezogen habe.

von Kai B. (tekasiko)


Lesenswert?

Hallo,

beomt noch ein Then bei

If Sekunde = 59 Then

rein

Aber Problem bleibt natürlich

von Peter D. (pdiener) Benutzerseite


Lesenswert?

>Was mach ich falsch?

Es gibt da grundsätzlich drei verschiedene Arten von Fehlern:
Die Fehler erster Art sind die, die tatsachlich direkt dazu führen, dass 
das Programm im Moment nicht funktioniert:

- Subroutinen müssen als solche gekennzeichnet sein (return)
  siehe "Abzug_s:" usw.
- Subroutinen werden mit "gosub" aufgerufen, nicht mit goto
  siehe "If Sekunde = 59 Then Goto Abzug_m"
- Datentypen werden falsch verwendet
  siehe Minute As Byte
  If Minute = -1 Then
- Aufruf von Subroutinen aus Interrupt und Hauptprogramm (reentrant?)
  siehe LCD

Und dann gibt es noch die Fehler zweiter Art. Diese sind zwar für die 
Programmausführung irrelevant, führen jedoch dazu, dass sich niemand 
genauer mit dem Code auseinandersetzen möchte, weil er nahezu 
unverständlich ist in der gewählten Formatierung. Somit führen Fehler 
zweiter Art dazu, dass das Programm auch in naher Zukunft noch nicht 
funktioniert:

- Warum gibt es Read_eeprom und Write_eeprom mehrfach?
  alle machen exakt das Gleiche, nur die lokalen Vaiablen heißen anders.
  Datenrückgabe für Read_eeprom wäre per FUNCTION eleganter.
- Code ist erheblich falsch eingerückt.
- Unnötige Mengen an Leerzeilen an Stellen, wo sie nicht benötigt
  werden, dafür an Stellen keine, wo sie wirklich für mehr Übersicht
  helfen würden
  siehe EEPROM_xxx und mainloop
- Willkürliche Groß- und Kleinschreibung.
- Variablen- und Funktionsbenennung gemischt deutsch-englisch
- Fehlender Kommentar an wichtigen Stellen
  z.B. Timerinitialisierung: Warum welcher Prescaler, welcher mode,
  welche Reloadwerte, wie oft wird der Interrupt ausgeführt usw.

Fehler zweiter Art sind auch das, was Karl Heinz Buchegger meint mit:
>In einen Spaghetticode [...]

Schließlich gibt es noch die Fehler dritter Art. Das sind die, die 
(falls das Gerät mal funktioniert) dann irgendwann zum Ausfall führen. 
Dazu gehört auf jeden Fall:

- Das EEPROM wird 61 mal pro Stunde geschrieben, nach ca. 100000
  Schreibzyklen ist es defekt.


Am besten geht man so vor:

Als erstes die Fehler zweiter Art beheben, die frustrieren einen nämlich 
selbst, weil man so andere Fehler gar nicht erkennt.
Code in funktionale Gruppen teilen, Funktionsblöcke am Anfang 
kommentieren. Was macht der Block, warum macht man das so? 
Variablendeklarationen in einen eigenen Block, jede Variable 
kommentieren und den möglichen Wertebereich angeben. Und schließlich 
alles mit einem Kommentar versehen, was nicht sofort verständlich 
erscheint. Das Programm gut strukturieren, goto nach Möglichkeit 
vermeiden und gosub verwenden. Code immer richtig einrücken, auch wenn 
es nur Tests sind.

Dann alle Fehler erster Art beheben, die man unmittelbar erkennen kann.
Anschließend nochmal den ganzen Code hier posten.

Die restlichen Fehler erster Art beheben und so dafür sorgen, dass das 
Programm macht, was es soll.

Dann diskutieren, wie man den Fehler dritter Art vermeidet.


Grüße,

Peter

von oldmax (Gast)


Lesenswert?

Hi
Schön, wie ihr ihm sagt, welche Fehler er macht. Er ist ein "Neuling" 
mit Ehrgeiz, also denk ich mal, ich werd es etwas ergänzen.
Programmieren heißt: Eine Aufgabe in viele klein Teile zu zerlegen und 
diese dann wie in einer Liste abzuarbeiten. Daher besteht in der Regel 
ein Programm aus einer Schleife. Die Liste wird immer wieder durchlaufen 
und die Anweisungen bearbeitet. Das ist in allen Programmiersprachen 
gleich.
Nun gibt es aber Aufgaben, die immer wieder einen gleichen Aufbau haben. 
Daraus werden Unterprogramme geschrieben, die, damit es funktioniert, 
die Rücksprungadresse brauchen
etwa so
Loop
 x:    ....
 x+1:  Aufruf machwas   Rücksprung x+1
 x+1:  ....
 x+1:  ....
 x+1:  Aufruf machwas   Rücksprung x+1
 x+1:  ...
 x+1:  Ssprung nach Loop

Ok, diese Struktur wird dir wohl bekannt sein. Wichtig ist, das ein 
Programm erkennen muß, wann ein Rücksprung an verschiedene Adressen 
erfolgt, und wo diese Info dazu steht. Mit Gosub wird die nächste 
Adresse für den Befehlszeiger auf den Stack gepackt und mit Return 
wieder in den Befehlszeiger zurückgeschrieben. Verwendest du ein Goto, 
gibt es keine Rücksprungaresse und der Befehlszeiger macht immer munter 
an der falschen Stelle weiter, da er ja bei jedem Laden eines Befehles 
erhöht wird. Vergißt du das Return nach einem Gosub, landest du auch im 
Wald, genau wie bei einem Return ohne Gosub, denn dann wird der 
Befehlszeiger mit einem undefinierten Wert geladen und die 
Anweisungsliste an irgend einer Stelle bearbeitet.
Das sind mal grob so die Funktion eines Programmes. Damit es für den 
Programmierer etas leichter wird, seinen Code zu lesen, gibt es die 
Möglichkeit, texte etwas einzurücken. Eine Vorschrift dazu gibt es zwar 
nicht, aber i.R. ist es so, das ein Block um 2 Leerzeichen eingerückt 
wird. Dadurch erkennt man ganz gut die Schachtelung ohne wahnsinnig weit 
nach links zu geraten...
z.B.
Loop:                ; Programmbegin, nicht eingerückt
  ...                ; Anweisungen, eingerückt
  For x=1 to 10
    ....             ; 1. Schleife eingerückt
    If x = n
       ....         ; If- Block, eingerückt
       Gosub Machwas_A
    end If           : Block ende
    Gosub Machwas_B
  End For            ; Block ende
End Loop             ; ende Programmschleife

Machwas_A
  ...
Return

Machwas_B
  ....
Return

Dieses Listing ist jenseits von Programmiersprache, aber es zeigt eine 
Struktur.  Vielleicht hilft dir diese Ansicht etwas. Nun zum thema, 
einen Schritt von einer Variablen , einem Flag abhängig zu machen.
Angenommen, du hast einen Interrupt, der dir ein Flag setzt. Also, jede 
Minute durchläust du aufgrund eines Interrupts eine kleine Routine:
Int_Serv_Rout_Min:
   Flag=1
RETI                       Interrupt-Rücksprung !

Diese Routine wird NICHT aus der Programmschleife aufgerufen, sondern 
von einem Interrupt. (Timer/ IO, was auch immer...)
In deiner Progrmmschleife muß dann folgender Code aufgerufen werden, um 
das Ereignis zu erfassen:
Loop   ....
   If Flag=1 then
      Mach_Dein_Ding      Irgendwelche Bearbeitungsschritte aufgrund des 
Ereignisses
      Flag=0                    Das Flag quittieren, d. H. auf 0 setzen
   End If
   ....
Ich glaub, so wird deutlich, das,  nur wenn das Flag 1 ist, diese 
Bearbeitung durchgeführt wird und mit dem "resetten" des Flags diese 
Bearbeitung quittiert wird. Erst nach enem weiteren Interrupt wird die 
Variable wieder auf 1 gesetzt und der Job erneut durchgeführt. Ist die 
Aufgabe umfangreich macht es Sinn. ein Unterprogramm zu schreiben und 
diesen Job dort abzulegen. Dies spart keinesfalls Programmierzeilen, 
erhöht aber die Lesbarkeit.
Bearbeite_Flag:
    Mach_Dein_Ding      Irgendwelche Bearbeitungsschritte aufgrund des 
Ereignisses
    Flag=0                    Das Flag quittieren, d. H. auf 0 setzen
Return                        Kein Return für Interrupt, da der Aufruf 
aus der Programmschleife erfolgt !

Loop
   ....
  If Flag=1 then Gosub Bearbeite_Flag
  ......
End Loop
So, das sollte erst mal genug sein.
Gruß oldmax

von Purzel H. (hacky)


Lesenswert?

Mit Programmieren sollte man sich auf einem PC vertraut machen, nicht 
auf einem Controller. Dies, weil die Debugmoeglichkeiten ganz was 
anderes auf einem PC sind. Einen Controller sollte man erst anfassen, 
wenn man das Programmieren auf einem PC beherscht.

von Kai B. (tekasiko)


Angehängte Dateien:

Lesenswert?

Hallo Peter,

vielen Dank für deine Mühe,

habe jetzt alles soweit geändert und habe dein Tipps befolgt.

Ich muss sagen du hast mir unheimlich viel geholfen und somit 
funktioniert es auch.

Dafür vielen vielen Dank.

Der dank geht auch an alle anderen in diesem Forum ohne die ich mein 
projekt niemals zu Ende gebracht hätte.


Nun zu dem Problem mit dem EEprom,

das verwendete EEprom hat 1.000.000 schreibzyklen,

das sind bei 24 Std. dauereinsatz bei einem Schreibzyklus / Minute ca. 2 
Jahre bis es sich verabschiedet.


Es handelt sich dabei um eine Chipkarte. Datenblatt ist im Anhang.

Natürlich gibt es da Tricks die man anwenden kann um immer andere 
Adressen anzusprechen, aber dafür reicht mein wissen bei weitem nicht 
aus.

Ich bin euch aber sehr dankbar für tips wie ich diese Problem in den 
Griff bekomme.

Lg Kai

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Es kommt auf die Anwendung an, wie man das Problem vermeiden kann.

So wie ich das verstehe, ist das eine Art Guthabenkarte für ein Spiel 
oder Ähnliches.

Man könnte es so machen:

1. Karte vor Spielbeginn reinstecken, damit Guthaben gelesen wird
2. Karte als ungültig markieren (z.B. Checkbyte verstellen)
3. Karte entfernen

4. Spielen, Guthaben wird im µC runtergezählt

5. Nach Spielende Karte reinstecken
6. Restguthaben auf die Karte schreiben
7. Karte entfernen

3. und 5. kann man auch weglassen.

Wichtig ist nur, dass dem Gerät das Spielende bekannt ist.

Alternativ gibt es die Kartensockel auch mit Schalter. Man kann das 
Guthaben dann zurückschreiben, sobald jemand versucht, die Karte zu 
entfernen.

Grüße,

Peter

von Kai B. (tekasiko)


Lesenswert?

@ oldmax,

Vielen dank für deine Hilfe, du hast mir damit soviel informationen 
gegeben, die ich bestimmt mit stundenlanger suche im Internet verbracht 
hätte.

Ich bin dir unheimlich dankbar und überlege mir ob ich mein Program 
anhand der neuen Informationen von dir neu schreiben werde.

Das ist ein Beitrag genau so wie ich ihn mir gewünscht habe.

Durch leute wie dich kann ich noch so unendlich viel lernen.

Vielen Vielen Dank dafür. :-)


@ Peter,

Dankeschön.

Ich werd mir das mal anschauen und beide Möglichkeiten in betracht 
ziehen.

Werde es euch wissenlassen wenn ich mich entschieden habe und wie ich es 
gelöst habe.

Spätestens aber wenn ich mal wieder vor irgendwelchen Problemen stehe.

:-)

Danke an alle.

von oldmax (Gast)


Lesenswert?

Hi
Du brauchst dich nicht bei mir bedanken, fast alle Antworten zielten auf 
das selbe Problem. Nur vergessen wir Programmierer leicht, das es noch 
"normal" denkende Menschen gibt, für die ein Schritt eben ein Schritt 
und nicht eine Ablauffolge von Muskelbewegungen ist.....
Gruß oldmax

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.