Basic, Verzögerungsschleifen bzw Timer

Es gibt 38 Antworten in diesem Thema, welches 4.633 mal aufgerufen wurde. Der letzte Beitrag (16. Juni 2022 um 10:20) ist von Hoogo.

  • Ich möchte (ja,ja... noch so vieles...:/ )

    zur Classic-Computing wahrscheinlich, möglicherweise....

    Also, es geht um Diddl ´s C64SPS Modul, respektive der Programmierung

    in Basic 2.0. Wie programmiert man ANSTÄNDIG einen Timer der, sagen wir,

    alle Sekunde die nächste Aktion ausführt? Ich meine eben NICHT sinnlose

    Warteschleigen mit For/Next sondern ob es einen Befehl gibt, einen Timer abzufragen?

    Ähnlich wie in "C" ( vom Arduino her)

    Zitat

    if (currentMillis - previousMillis >= interval) {

    .....

    .....

    previousMillis = currentMillis;}

    Nächste Frage:

    Muss ein Basic 2.0 Programm nach der letzten Zeile wieder ein "GOTO"

    zur Anfangszeile haben, damit es endlos abläuft? Oder quillt dann irgend ein Stack über?

    (Wahrscheinlich denke ich zu kompliziert / komfortabel)

    Grüße

    Stefan

  • Da gibt es 2 Möglichkeiten, die auch im Turbomode von (SuperCPU, U64, TC64 etc.) funktionieren:

    1. Jiffy Clock über die Adressen $a0 - $a2 (#160 - #162)

    2. CIA Timer, den man aber erst einmal, am besten bei Programmstart, initialisiert, z.B. mit der aktuellen Tageszeit.

    Vorstellung Raveolution BBS -> Bitte melde dich an, um diesen Link zu sehen.
    Raveolution BBS -> raveolution.hopto.org:64128
    Raveolution Gopher Hole -> gopher://raveolution.hopto.org:70

  • Also, es geht um Diddl ´s C64SPS Modul, respektive der Programmierung

    in Basic 2.0. Wie programmiert man ANSTÄNDIG einen Timer der, sagen wir,

    alle Sekunde die nächste Aktion ausführt? Ich meine eben NICHT sinnlose

    Warteschleigen mit For/Next sondern ob es einen Befehl gibt, einen Timer abzufragen?

    Mit Interrupts in BASIC wirst du nicht viel Freude haben. Bleibt das Pollen der Echtzeituhr, um zu erkennen, ob die Zeitdauer T abgelaufen ist.

    Muss ein Basic 2.0 Programm nach der letzten Zeile wieder ein "GOTO"

    zur Anfangszeile haben, damit es endlos abläuft? Oder quillt dann irgend ein Stack über?

    Du kannst es auch mit "RUN" erneut starten, das macht ein implizites "CLR" und der Variablenbereich ist aufgeräumt.

    Der Stack läuft wegen des GOTOs nicht über, bei diesem wird (im Gegensatz zu GOSUB) ja keine Rücksprungadresse auf den Stack gelegt (weil es ja gar keine solche gibt). Vielleicht meinst du die "Garbage Collection" - die würdest du mit dem "RUN" nach meinem Verständnis verhindern.

  • Ja, in Basic V2 hat man quasi nur die Systemvariable TI für "getimte" Sachen:

    Bitte melde dich an, um diesen Link zu sehen.

    Je nachdem was man so anstellt, kann der Timer aber auch mal abweichen.

    Da Basic linear abläuft, muss man ja irgendwann mal irgendwohin zurückspringen, sonst kommt ein schnödes READY. :)

  • 1 Sek. Pause:

    Code
    10 t=ti+60
    20 if ti<t goto 20
    30 print"action @ "ti$
    40 goto 10

    1 Sek. Intervall:

    Code
    10 if ti<t goto 10
    20 t=ti+60
    30 print"action @ "ti$
    40 goto 10
  • Danke Jungs,

    Danke atomcode.

    Ist ja irgendwie ähnlich wie beim Arduino.

    ' ti ' läuft automatisch los, sobald der C64

    eingeschaltet wird?

    Stefan

  • Den TI kann man auch mit PEEK() abfragen.


    Ich könnte natürlich auch noch Zusatzbefehle rein bauen, wenn da Bedarf ist.

    Bitte melde dich an, um diesen Link zu sehen. --- Bitte melde dich an, um diesen Link zu sehen. --- Bitte melde dich an, um diesen Link zu sehen.

  • Und was, außer undurchsichti9gem Spaghetti-Code, bringt das für einen Vorteil?

    Hat eindeutig mehr Doppelpunkte :bgdev :weg:

    Bitte melde dich an, um diesen Link zu sehen.

    Bitte melde dich an, um diesen Link zu sehen.

  • Und was, außer undurchsichti9gem Spaghetti-Code, bringt das für einen Vorteil?

    Es kommt ohne GOTO aus und passt in eine Zeile und ist damit eigentlich sehr kompakt und übersichtlich.

    Spagetti-Code? Was genau verstehst du darunter? Solche Einzeiler?

  • Und was, außer undurchsichti9gem Spaghetti-Code, bringt das für einen Vorteil?

    Dann kann er gleich ...


    FOR I = 1 TO 1000:NEXT I


    ... für eine Sekunde Verzögerung schreiben.

    Verglichen damit ist der BIF-Unfall dann aber schon besser, einfach weil er an TI gekoppelt ist. Man kann das natürlich auch leserlich schreiben...

    Yes, I'm the guy responsible for the Bitte melde dich an, um diesen Link zu sehen. cross assembler. And some Bitte melde dich an, um diesen Link zu sehen..

  • Und das sollte auch, dank ti, jenseits von 1MHz funktionieren, was eine "normale" FOR NEXT Schleife nicht kann.

    Vorstellung Raveolution BBS -> Bitte melde dich an, um diesen Link zu sehen.
    Raveolution BBS -> raveolution.hopto.org:64128
    Raveolution Gopher Hole -> gopher://raveolution.hopto.org:70

  • Kurz vor Mitternacht kann es aber auch passieren, daß die Warteschleife hängt weil TI den vorgegebenen Wert nie erreicht:

    Code
    10 TI$="235959"
    15 A=TI+120
    20 IF TI<A THEN 20 : REM ** 2 Sekunden warten. Oder?

    Ich ziehe darum die nachfolgende Variante vor, auch wenn sie in diesem Fall die Schleife vorzeitig beendet:

    Code
    10 TI$="235959"
    15 A=TI
    20 IFABS(TI-A)<120THEN20 : REM ** 2 Sekunden warten. Manchmal nicht ganz so lang.
  • ich seh da ein paar ganz praktische gründe für BIF 's ansatz gegenüber kinzi 's ansatz.

    Mal abgesehen das 100 einfach deutlich der falsche wert ist.

    Ich hab mal folgendes getestet, sowohl in vice als auch auf echter hardware:

    also in zählschleife einmal eine und einmal 10 sekunden warten und in zeitpunkt-abwarte-schleife einmal eine einmal 10 sekunden warten.
    Ergebnisse:

    Vice:

    1.4

    14.7

    1

    10

    echte hardware:

    1.38333333

    14.6833333

    1.01666667

    10.0166667

    vice c128 im 64 modus

    2.1

    21.7833333

    1

    10


    hier könnte man das eigentlich schon als fertig betrachten.

    klar, man kann die 1000 auf ca 720 optimieren um näher an eine/10 sekunden zu kommen, aber das ist ja noch nicht mal linear und viorallen nicht auf jedem system gleich.

    jetzt hantier ich ja recht viel mit MOSpeed rum.

    da sehen die zahlen dann komplett unbrauchbar aus:


    vice

    0

    0

    1

    10.0166667

    echte hardware

    0

    0

    1

    10.016667

  • Kurz vor Mitternacht kann es aber auch passieren, daß die Warteschleife hängt weil TI den vorgegebenen Wert nie erreicht:

    Vorrausgesetzt jemand hat tatsächlich die Uhr gestellt. Anderenfalls versagt die TI-Variante erst nach 24-Std Einschaltzeit.

    Und dann auch nur, wenn der Tageswechsel genau in die Verzögerungsschleife fällt. Also wenn die Schleife ständig verwendet wird, dann sollte man das schon abfangen.

  • Also wenn die Schleife ständig verwendet wird, dann sollte man das schon abfangen.

    Der Grund, warum man generell die Zeitdifferenz ermitteln und nicht auf das Überschreiten einer vorgegebenen Zeitmarke prüfen sollte, zeigt sich ganz besonders, wenn der genutzte Timerwert eine kurze Periode hat (z.B. das Jiffy-Low-Byte!) und die Modulo- oder 2-Komplement-Arithmetik der CPU hier einem noch "mithilft":

    Bei einem 8-Bit-Timer und z.B. Ausgangszeitpunkt T0=120, Wartezeit=10 ergibt 2-Komplement-Arithmetik den "Zielzeitpunkt" T1=-126. Da (bei vorzeichenbehafteter Arithmetik) T0>T1 ist, wird die Schleife hier unerwarteterweise sofort beendet. Gleiches passiert bei nicht-Vorzeichen-behafteteter Arithmetik und T0=250, ebenfalls Wartezeit=10. Gibt T1=4 und wiederum ist T0 direkt schon größer als T1.

    Rechnet man stattdessen die Differenz aus und vergleicht diese mit der Zeitdauer, dann funktioniert das auch dann mit der korrekten Wartezeit, wenn in Modulo-Arithmetik zwischendrin ein Wrap-Around des Zeitgebers stattfindet! In Maschinencode für das Jiffy-Low-Byte sieht das dann so aus:

    Code
     LDA $A2 ; Jiffy-Low-Byte ...
     STA zp ; ... sichern.
    .loop
     SEC
     LDA $A2
     SBC zp
     CMP #xx ; xx = Wartezeit
     BCC loop

    Das funktioniert sogar noch mit xx=$FF. Selbstredend sollte der obige Code mit Binär-Arithmetik laufen (... also vorher mal sicher CLD ausgeführt worden sein ...).

    Dummerweise reicht es in BASIC nicht aus, die Differenz zu bilden, da die Fließkommazahlen eben keine Modulo-Arithmetik haben. "TI-A" wird beim Wraparound von TI dann negativ, aber betragsmäßig ein sehr großer Wert und ABS() sorgt dann dafür, daß diese Schleife beendet wird (vorzeitig zwar, aber wenigstens!).

    Wenn ich also die Wahl habe zwischen einer Schleife bzw. Programm, welches unter simplen, nachvollziehbaren Umständen einfach hängenbleiben kann oder in diesem Fall vielleicht mal nicht ganz so lang wartet, dann ziehe ich letztere Option eindeutig vor.

  • Jetzt macht ihr mich aber etwas wuschig... :)

    Im BBS Code von C*BASE und wahrscheinlich anderen System auch wird eine Pause mit der TI Variable wie folgt gelöst (Beispiel):

    Code
    b=160:gosub _jiffywait
    
    ;----> Waitloop with Jiffy Clock
    _jiffywait:         a=ti
    _jiffywtloop:       if (ti-a)<b then goto _jiffywtloop
                        return

    So ähnlich läuft das in ML auch in Punter und X-Modem. Haben wir da ein jetzt ein potentielles Problem ?

    Vielleicht kann ich dank dieses Threats hier ein paar ungelöste Bugs entfernen :)

    Vorstellung Raveolution BBS -> Bitte melde dich an, um diesen Link zu sehen.
    Raveolution BBS -> raveolution.hopto.org:64128
    Raveolution Gopher Hole -> gopher://raveolution.hopto.org:70