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
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
Ich bin etwas irritiert. Wenn Du soweit gekommen bist, scheiterst Du am Einbinden einer Variable?
Vielen Vielen Dank :-) Ich werd es mal testen und hofen das es geht.
Wird nicht wirklich erfolgreich sein:
1 | Dim ..., Stunde As Byte |
2 | ...Stunde = -1 Then Goto Countdown_stop |
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.
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.
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
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.
Hallo, beomt noch ein Then bei If Sekunde = 59 Then rein Aber Problem bleibt natürlich
>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
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
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.
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
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
@ 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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.