|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
psygate
Anmeldungsdatum: 05.04.2005 Beiträge: 304 Wohnort: Wien und der Computer
|
Verfasst am: 05.04.2005, 18:48 Titel: Timer |
|
|
Also, ich hab leider im Monster FAQ usw nix dazu gefunden....
Ich möcht ein Zeit besierendes Programm schreiben, mit der zeitfunktion. Ich müsst milli, sekunden und minuten stoppen können, um es zu beenden. kann mir einer helfen, eine art stoppuhr zu bauen? |
|
Nach oben |
|
|
jb
Anmeldungsdatum: 14.01.2005 Beiträge: 2010
|
Verfasst am: 05.04.2005, 20:22 Titel: |
|
|
Ganz so einfach ist das nicht.
Der Befehl TIMER hat eine geringere Auflösung als 1ms, ich glaube so etwa 56ms.
Da müsste man schon auf die TIMER-Register zugreifen.
Tip: Frag mal Skilltronic!!
Für Minuten und Sekunden geht das hier aber:
Code: |
DO
IF t$ <> TIME$ THEN
Sekunden = Sekunden + 1
IF Sekunden > 59 THEN Sekunden = 0: Minuten = Minuten + 1
t$ = TIME$
END IF
LOOP UNTIL INKEY$ = CHR$(27)
PRINT " Das PRogramm lief "; Minuten; " Minuten und "; Sekunden; " Sekunden."
|
Dazu wird der Befehl TIME$ verwendet, der die Systemzeit zurückliefert.
Wenn dieser sich von der Variable t$ unterscheidet, muss also eine
Sekunde vergangen sein, da TIME$ sich auch jede Sekunde ändert.
Das ganze läuft in einer Schleife, die durch ESCAPE beendet wird.
jb |
|
Nach oben |
|
|
psygate
Anmeldungsdatum: 05.04.2005 Beiträge: 304 Wohnort: Wien und der Computer
|
Verfasst am: 06.04.2005, 10:46 Titel: Hm.... |
|
|
Die schleife hätte ich auch noch schreiben können, aber danke.
Das mit den 0,56 sec ist bei mir das probelm.
wenn ich z.B
Code: |
CLS
PRINT "Test"
a = TIMER+0.56
DO
LOOP UNTIL a => TIMER
c = TIMER
PRINT "GESTOPPT um ";c;" Sekunden nach Mitternacht."
CLS
|
schreibe, dann stoppt das Programm nie! Kann er das LOOP nicht schnell genug ausführen, also in 0.56 sec oder was ist da sonst los?!
Was ist da das Problem?? Er stoppt nämlich NIE!
HILFE...
---------------------------------------
psy, der Anfänger
Zuletzt bearbeitet von psygate am 06.04.2005, 10:50, insgesamt einmal bearbeitet |
|
Nach oben |
|
|
Skilltronic
Anmeldungsdatum: 10.09.2004 Beiträge: 1148 Wohnort: Köln
|
Verfasst am: 06.04.2005, 11:30 Titel: Re: Hm.... |
|
|
Hallo
1. Also ich habe deinen Programmschnippsel jetzt 10 mal oder so laufen lassen und das Programm hat jedesmal von selbst gestoppt. Ist eigentlich auch logisch, dass es das tut. Nur warum du direkt nach einer Anzeige gleich ein CLS nachschiebst, ist mir schleierhaft. Bist du sicher, dass du jbs Beispiel auch hättest schreiben können?
2. 56ms sind 0,056 Sekunden nicht 0,56 und die reichen eigentlich immer, um ein paar Programmzeilen abzuarbeiten.
3. Was genau hast du eigentlich vor? Soll eine Wartezeit von bestimmter Dauer gebildet werden und wie genau brauchst du es denn. Die Angabe "milli, sekunden und minuten" ist etwas ungenau. Meinst du 500ms oder eine?
4. Sieh dir das mal an: http://forum.qbasic.at/viewtopic.php?t=555
oder das: http://forum.qbasic.at/viewtopic.php?t=58
Gruss
Skilltronic _________________ Elektronik und QB? www.skilltronics.de ! |
|
Nach oben |
|
|
psygate
Anmeldungsdatum: 05.04.2005 Beiträge: 304 Wohnort: Wien und der Computer
|
Verfasst am: 06.04.2005, 11:41 Titel: Re: Hm.... |
|
|
THX! Wenn das jetzt geht! Konnte es nicht testen, weil ich in der Schule sitze...
1. Wenn das geht, dann vielen Dank!
Ja, jb Code hätte ich gerade noch mti eminen Kenntnissen entwerfen können
Zitat: |
2. 56ms sind 0,056 Sekunden nicht 0,56 und die reichen eigentlich immer, um ein paar Programmzeilen abzuarbeiten.
|
Sh***!!! dann hab' ich die flasche bezeichnung verwendet... Das erklärt, warum alle Stoppungen falsch gelaufen sind...
Zitat: |
3. Was genau hast du eigentlich vor? Soll eine Wartezeit von bestimmter Dauer gebildet werden und wie genau brauchst du es denn. Die Angabe "milli, sekunden und minuten" ist etwas ungenau. Meinst du 500ms oder eine?
|
Ja, es sollte gerade eine kleine Verzögerung beim Zeichnen der Elemente geben. (Am Ti-Voyage 200 war das einfacher, durch den langsamen Prozessor, und die Verzögerung des Interpreters.... Bei einem Ghz geht das viel zu schnell, viel zu schnell für meinen geschmack natürlich... )
Ganz großen THX an dich Silk
PS: Ich möchte SUB unter allen Umständen vermeiden, die machen mein Prog unnötig komplizierter und größer... |
|
Nach oben |
|
|
psygate
Anmeldungsdatum: 05.04.2005 Beiträge: 304 Wohnort: Wien und der Computer
|
Verfasst am: 06.04.2005, 14:14 Titel: Neue Frage; |
|
|
Neu frage an die QBasic genies hier:
Könnte ich einen Code wie den hier ca. einrichten, wenn ja, WIE?
Code: |
c = 0
time = TIMER
DO
c = c + 1
LOOP UNTIL time + 1 = TIMER
Print "Es können "; c ;" Schleifen in einer Sekunde ausgeführt werden."
|
Jetzt kommts, und darüber hab ich kange nachgedacht, aber kein ergebnis gefunden.... Habs auch schon mit verschiedenen Codes am TI-Voyage versucht (ähnlich wie QBasic).
Ich möchte mit so einer Schleife messen, wie viele von diesen Schleifen der Computer in einer Sekunde schafft. Danach möchte ich gerne damit die Zeit messen, also ca. so:
Code: |
c = 0
1 / c = sec
Print "jede Schleife dauert ca. ";sec;" Sekunden."
Print "Also ca."; ???;" Milli, Mikrosekunden."
DO
c = c + 1
LOOP UNTIL c = 400
|
Also, kann mir da jemand ein bisschen helfen? Mich wenigstens auf den weg bringen? |
|
Nach oben |
|
|
code
Anmeldungsdatum: 19.01.2005 Beiträge: 154
|
Verfasst am: 06.04.2005, 14:18 Titel: |
|
|
also bei deinem ersten code muss es soviel ich weiß Code: | LOOP UNTIL TIMER = time + 1 |
heißen.
ich bin mir aber nicht ganz sicher. |
|
Nach oben |
|
|
psygate
Anmeldungsdatum: 05.04.2005 Beiträge: 304 Wohnort: Wien und der Computer
|
Verfasst am: 06.04.2005, 14:22 Titel: |
|
|
Ich hoff' doch stark, dass das agle ist?! ansonsten bin ich |
|
Nach oben |
|
|
Skilltronic
Anmeldungsdatum: 10.09.2004 Beiträge: 1148 Wohnort: Köln
|
Verfasst am: 06.04.2005, 15:00 Titel: |
|
|
Hallo
Du schreibst:
LOOP UNTIL time + 1 = TIMER
Wenn du eine Sekunde durch 56ms teilst, siehst du schon, dass da kein runder Wert herauskommt. Aufgund dessen ist der Stand des TIMER nie genau um 1 grösser, als ein anderer. Du musst in diesem Fall immer mit > oder < arbeiten.
Wenn du Warteschleifen benutzen willst, um definierte Pausen zu erzeugen, dann sollte die Schleife beim Messen der Zeit genauso aussehen, wie später im Programm auch und da willst du ja keine TIMER-Abfrage mehr machen.
Hier mein Ansatz:
Code: | CLS
DO
c = 0
d = 10000000
ta = TIMER
DO
c = c + 1
LOOP WHILE c < d
tb = TIMER
t = tb - ta
PRINT "Zeit fuer eine Schleife:"; 10 ^ 6 * t / d; "µs"
PRINT "Schleifen fuer eine Sekunde:"; FIX(1 / t * d)
LOOP WHILE INKEY$ = "" |
Ich habe d extra gross gewählt, um den Fehler durch die Auflösung von TIMER so gering wie möglich zu halten, dashalb dauert der Messvorgang (bei mir) ein paar Sekunden. Wenn du das Programm später unter Windows laufen lässt, ist es mit der millisekundengenauen Zeitmessung sowieso vorbei, unter DOS sind wenige µs möglich.
Gruss
Skilltronic _________________ Elektronik und QB? www.skilltronics.de ! |
|
Nach oben |
|
|
jb
Anmeldungsdatum: 14.01.2005 Beiträge: 2010
|
Verfasst am: 06.04.2005, 15:35 Titel: |
|
|
Zu deinem Programm:
Das
Code: |
LOOP UNTIL time + 1 = TIMER
|
würde ich zu
Code: |
LOOP UNTIL TIMER >= time + 1
|
umändern, unter Umständen kannst du bei deiner Variante nämlich
bis in die Ewigkeit warten.
jb |
|
Nach oben |
|
|
psygate
Anmeldungsdatum: 05.04.2005 Beiträge: 304 Wohnort: Wien und der Computer
|
Verfasst am: 06.04.2005, 17:10 Titel: |
|
|
*lölz* Danke, hab mich schon gewundert
EDIT:
War wieder mal voreilig.... das kommt davon wenn man nciht liest! Danke Silktronnic
Ich versuch das mal....
sagt mal, wie kommt man ins dos, ohne disketten laufwerk? |
|
Nach oben |
|
|
Thomas Antoni
Anmeldungsdatum: 12.10.2004 Beiträge: 220 Wohnort: Erlangen
|
Verfasst am: 06.04.2005, 19:57 Titel: Zu dem Thema habe ich mir für die QB-MonsterFAQ vorgemerkt.. |
|
|
Zu den beiden Themen "Wartezeiten" und "Stoppuhr" habe ich mir für die QB-MonsterFAQ Folgendes vorgemerkt.
---------------------------------------------------------------------------------
Frage deutsch
~~~~~~~~~~~~~~~~
Wie erzeuge ich Wartezeiten unter 1 sec?
(( Ergänzung des bestehenden FAQ-Eintrags))
Antwort
~~~~~~~~~~~~~~~~
[ von Thomas Antoni, 1.2004 - 12.3.2005 ]
QBasic-Anfänger verwenden für die Bildung von Wartezeiten gerne den SLEEP-
Befehl. Mit "SLEEP n" kann man Programmablauf für eine ganze Anzahl von n
Sekunden anhalten. SLEEP 3 fügt z.B. eine Pause von 3 sec ein. Als kleinste
Pausenzeit kannst Du 1 sec erreichen, indem Du "SLEEP 1" verwendest.
Wie kann man nun aber genauere und kleinere Wartezeiten als mit SLEEP erzeugen?
Dazu verwendet man die TIMER-Funktion. TIMER liefert den aktuellen Stand der
Systemuhr zurück und zeigt die Anzahl der seit Mitternacht vergangenen Sekunden
an. TIMER hat eine Auflösung von 18,2 "Takten" pro sec. D.h. TIMER wird alle
0,055 sec (= 55 ms) um den Wert 0,055 erhöht. Wartezeiten unter 0,055 sec sind
daher mit TIMER nicht realisierbar.
Der Timer liefert Gleitpunktwerte vom Typ SINGLE zwischen 0.000 und 86400.000
sec (24 x 3600 = 86400; entspricht den in 24 Stunden von 00:00:00h ... 23:59:59h
verstrichenen Sekunden). Bei der Realisierung von Wartezeiten, Stoppuhren und
Countdown-Timern ist der Rücksprung des TIMERs vom Maximalwert 86400.000 auf
0.000 um Mitternacht zu berücksichtigen (genauer gesagt, von 86399.444 auf Null,
denn statt der 86400.000 wird um Mitternacht ja die Null zurückgeliefert).
Das folgende Progrämmchen zeigt, wie Du Wartezeiten mit TIMER realisieren
kannst.
Code: |
'***************************************************************
' TIMER.BAS = Erzeugung von Wartezeiten
' =========
' Der Anwender gibt eine Wartezeit in sec ein.
' Anschliessend wird die TIMER-Funktion
' verwendet, um den Programmablauf fuer diese
' Zeit anzuhalten. Wenn die Zeit abgelaufen
' ist, ertoent ein Piepston.
'
' (c) Thomas Antoni, 12.11.2003
'****************************************************************
CLS
PRINT "Gib eine Wartezeit in [sec] ein; ";
PRINT "Nachkommastellen erlaubt....t = ";
INPUT t!
starttime! = TIMER 'Startzeit merken
'
DO
PRINT TIMER - starttime! 'abgelaufene Zeit anzeigen
LOOP UNTIL TIMER > starttime! + t! 'Warteschleife
'
PRINT "Wartezeit ist abgelaufen"
BEEP
END
|
*** Die Problematik des Timer-Überlaufs um Mitternacht
Um Mitternacht springt der System-TIMER von 86399.944 auf 0 zurück. Dadurch
kommt es bei normalen Timer-Routinen, wie sie gemeinhin verwendet werden zu
Problemen (z.B. auch beim obenstehenden Programm TIMER.BAS).
Der TIMER hat z.B. 5 sec. vor Mitternacht einen Wert von 86395. Will man jetzt
eine Wartezeit von 10 sec einfügen, wartet das Programm solange, bis der um 10
erhöhte Wert von 86405 erreicht wird. Dieser Wert wird aber nie erreicht, wegen
des Rücksprungs von 86399.944 auf 0 . Daher wartet das Programm ewig und drei
Tage und das Programm hängt sich genau um Mitternacht in einer Dauerschleife
auf.
Mein folgendes Programm TIMER24.BAS umschifft dieses Problem und erzeugt
"saubere" Wartezeiten von bis zu 24h:
Code: |
'***************************************************************************
' TIMER24.BAS = erzeugt Wartezeiten, die auch um Mitternacht funktionieren
' ===========
' Dieses Q(uick)Basic-Programm erzeugt Wartezeiten mit einer
' zeitlichen Aufloesung von 0,056 sec, die auch um Mitternacht herum
' funktionieren. Das Programm verwendet den System-TIMER, der die ab
' Mitternacht verstrichenen Sekunden zaehlt und alle 0.055556 sec erhoeht
' wird. Der Anwender gibt eine Wartezeit in sec ein. Das Programm
' berechnet hieraus und aus dem momentanen Stand des System-TIMERs den
' in der Zukunft liegenden TIMER-Stand nach Ablauf der Wartezeit. Dabei
' wird auch der Ruecksprung ("Rollover") des TIMERs um Mitternacht von
' 86399.944 auf 0 beruecksichtigt. Wenn die Wartezeit abgelaufen ist,
' erfolgt eine entspechende Anzeige und es ertoent ein Piepston.
'
' (c) Thomas Antoni, 12.3.2005
'**************************************************************************
DECLARE SUB Pause24 (Wartezeit!)
DO
CLS
PRINT "Gib eine Wartezeit in [sec] ein ";
PRINT "(Dezimalpunkt erlaubt)"
INPUT "t = ", t!
IF t! = 0 THEN END 'Programm beenden wenn "0" eingegeben
CALL Pause24(t!)
PRINT "Wartezeit ist abgelaufen"
BEEP
PRINT
PRINT "Wiederholen...[beliebige Taste] Beenden...[Esc]"
DO: Taste$ = INKEY$: LOOP WHILE Taste$ = ""'Warten auf Tastenbetaetigung
IF Taste$ = CHR$(27) THEN END
LOOP
'
SUB Pause24 (Wartezeit!)
'******************************************************************
' Pause24 = Q(uick)Basic-Subroutine zur Erzeugung von Pausen von
' ======= max. 24h , die auch um Mitternacht herum funktionieren
'******************************************************************
'
'---- Start und Endezeit ermitteln
Startzeit! = TIMER
Endezeit! = Startzeit! + Wartezeit!
'
'---- Warteschleife, wenn kein Ueberlauf erfolgt
IF Endezeit! <= 86399.94 THEN
DO: LOOP WHILE TIMER < Endezeit!
'
'---- Warteschleife wenn Ueberlauf des Timers
'---- um Mitternacht von 86399.94 auf 0 erfolgt
ELSE
DO
LOOP WHILE (TIMER >= Startzeit!) OR (TIMER < (Endezeit! - 86400))
END IF
'
END SUB
|
-------------------------------------------------------------------------------------
Frage
~~~~~~~~~
Wie programmiere ich eine Stoppuhr?
Und wie kann ich dabei das Rücksetzen des TIMERs um Mitternacht umgehen?
Antwort 1
~~~~~~~~~
[ von Thomas Antoni, 6.4.2005 ]
Für eine eine einfache Stoppuhr, die nur eine Auflösung von ganzen Sekunden zu
haben braucht, kann man den Befehl TIME$ verwenden, der die Uhrzeit im Format
hh:mm:ss als String zurückliefert (hh=Stunden, mm=Minuten, ss=Sekunden). Wenn sich
der Wert von TIME$ geändert hat, muss eine Sekunde vergangen sein, da TIME$ sich
nur jede Sekunde ändert.
Das folgende Programm zeigt, wie man mit dem TIME$-Befehl eine Stoppuhr
programmiert :
Code: |
'******************************************************************
' STOPUHR1.BAS = Einfache Stoppuhr mit Sekunden- und Minutenanzeige
' ============
' Dieses Q(uick)Basic-Programm benutzt die Systemfunktion TIME$ zur
' Realisierung einer Stoppuhr, die die vergangenen Minuten und
' Sekunden anzeigt
'
' (c) jb und Thomas Antoni, 6.4.2005
'******************************************************************
'
'******** Vorbesetzungen und Anzeige der Bedienhinweise ***********
CLS
PRINT " Stoppuhr"
PRINT " ========"
LOCATE 7
PRINT " [S]=Start/Stopp...[R]=Reset...[Esc]=Beenden"
TimeAlt$ = ""
Min% = 0
Sek% = 0
Uhrlaeuft% = 0 'Uhr ist angehalten
'
'******** Tasten abfragen *****************************************
DO
Taste$ = INKEY$
'
SELECT CASE Taste$
CASE "s", "S" 'Start/Stopp betaetigt
IF Uhrlaeuft% = 0 THEN Uhrlaeuft% = 1 ELSE Uhrlaeuft% = 0
CASE "r", "R" 'Ruecksetzen betaetigt
Min% = 0: Sek% = 0 'Stoppuhr auf 0 setzen ...
Uhrlaeuft% = 0 '... und anhalten
CASE CHR$(27) 'Programm beenden bei Esc-Taste
END
END SELECT
'
'******** Zeit weiterzaehlen wenn eine Sec vergangen **************
IF Uhrlaeuft% = 0 THEN
TimeAlt$ = TIME$
ELSE
IF TimeAlt$ <> TIME$ THEN '1 Sek vergangen?
Sek% = Sek% + 1
IF Sek% > 59 THEN Sek% = 0: Min% = Min% + 1
TimeAlt$ = TIME$
END IF
END IF
'
'******** Zeit anzeigen *******************************************
LOCATE 4, 2: PRINT Min%; ":"; Sek%;
LOCATE , 10: PRINT "Minuten"
LOOP
|
Scheinbar noch einfacher als mit TIME$ kannst Du eine Stoppuhr mit dem TIMER-
Befehl ermitteln, der die seit Mitternacht verstrichenen Sekunden mit einer
Auflösung von 56 ms ( = 0,056 sec) als SINGLE-Gleitpunktwert zurückliefert.
Mit TIMER kannst Du also im Gegensatz zu TIME$ auch Nachkommastellen der
Sekunden darstellen. Eine größere Anzeige-Auflösung als 0,1 sec ist aber wenig
sinnvoll, weil die Hunderter-Stelle ja jeweils um den Wert 5 oder 6 springt.
Zur Realisierung einer Stoppuhr musst Du Dir einfach beim Starten den momentanen
TIMER-Wert als Startwert abspeichern und dann in einer Dauerschleife jeweils die
Differenz TIMER - Startwert anzeigen.
Das entsprechende Programm würde dann etwa so aussehen:
Code: |
'******************************************************************
' STOPUHR2.BAS = Einfache Stoppuhr mit min, sec u. 1/10 sec Anzeige
' ============
' Dieses Q(uick)Basic-Programm benutzt den System-TIMEr zur
' Realisierung einer Stoppuhr, die die vergangenen Minuten und
' Sekunden sowie die 1/10 Sekunden anzeigt.
' Das Nullsetzen des TIMERS um Mitternacht wird nicht
' beruecksichtigt. Daher zeigt das Programm falsche Zeiten an, wenn
' man es um Mitternacht herum benutzt.
'
' (c) Thomas Antoni, 6.4.2005
'******************************************************************
'
'******** Vorbesetzungen und Anzeige der Bedienhinweise ***********
CLS
PRINT " Stoppuhr"
PRINT " ========"
LOCATE 7
PRINT " [S]=Start/Stopp...[R]=Reset...[Esc]=Beenden"
Sekunden! = 0
StartZeit! = TIMER
Min% = 0
Sek% = 0
Uhrlaeuft% = 0 'Uhr ist angehalten
'
'******** Tasten abfragen *****************************************
DO
Taste$ = INKEY$
'
SELECT CASE Taste$
CASE "s", "S" 'Start/Stopp betaetigt
StartZeit! = TIMER - Sekunden!
IF Uhrlaeuft% = 0 THEN Uhrlaeuft% = 1 ELSE Uhrlaeuft% = 0
CASE "r", "R" 'Ruecksetzen betaetigt
Sekunden! = 0 'Stoppuhr auf 0 setzen ...
Uhrlaeuft% = 0 '... und anhalten
CASE CHR$(27) 'Programm beenden bei Esc-Taste
END
END SELECT
'
'******** Zeit ermitteln und anzeigen *****************************
IF Uhrlaeuft% = 1 THEN
Sekunden! = TIMER - StartZeit!
END IF
LOCATE 4, 2
PRINT USING "#####.#"; Sekunden!; 'Sec mit 1 Nachkommastelle anz.
PRINT " sec"
LOOP
|
Der Timer liefert Gleitpunktwerte vom Typ SINGLE zwischen 0.000 und 86400.000
sec (24 x 3600 = 86400; entspricht den in 24 Stunden von 00:00:00h ... 23:59:59h
verstrichenen Sekunden). Bei der Realisierung von Wartezeiten, Stoppuhren und
Countdown-Timern ist der Rücksprung des TIMERs vom Maximalwert 86400.000 auf
0.000 um Mitternacht zu berücksichtigen (genauer gesagt, von 86399.444 auf Null,
denn statt der 86400.000 wird um Mitternacht ja die Null zurückgeliefert). Wenn
man das nicht tut, wird eine um Mitternacht herum gestoppte Zeit völlig falsch
mit großen negativen Zeitwerten angezeigt.
Das obige Programm STOPUHR.BAS hat also 2 Unschönheiten:
1. Des Rücksetzen des System-TIMERs um Mitternacht wird nicht beherrscht,
und das Programm zeigt falsche Wertte an, wenn man es um Mitternacht
herum benutzt
2. Es werden nur Sekunden, aber keine Minuten und Stunden angezeigt
(23:59:59.9 Stunden werden z.B. als 86399.9 Sekunden angezeigt).
Diese Mängel sind gar nicht so leicht zu beseitigen. Wie man es trotzdem
schafft, zeigt mein folgendes Programm STOPUHR3.BAS. Die Beseitigung der beiden
Problempunkte hat mich einige Schweißtropfen gekostet. Dafür ist das aber dann
auch schon fast die ideale Stoppuhr.
Code: |
'******************************************************************
' STOPUHR2.BAS = Komfort-Stoppuhr mit min, sec u. 1/10 sec Anzeige
' ============
' Dieses Q(uick)Basic-Programm nutzt den System-TIMER zur
' Realisierung einer Stoppuhr, die die vergangenen Minuten und
' Sekunden sowie die 1/10 Sekunden anzeigt.
' Das Nullsetzen des TIMERS um Mitternacht wird beruecksichtigt,
' so dass das Programm auch um Mitternacht herum richtig
' funktioniert. Dies habe ich getestet, indem ich die PC-Zeit auf
' einen Wert kurz vor Mitternacht gestellt und dann die Stoppuhr
' gestartet habe. Die maximal messbare Zeit betraegt 24h.
'
' (c) Thomas Antoni, 6.4.2005
'******************************************************************
'
'******** Vorbesetzungen und Anzeige der Bedienhinweise ***********
CLS
PRINT " STOPPUHR - (c) Thomas Antoni"
PRINT "==============================="
LOCATE 7
PRINT " [S] = Start/Stopp"
PRINT " [R] = Reset"
PRINT " [Esc]= Beenden"
Sekunden! = 0
StartZeit! = TIMER
Uhrlaeuft% = 0 'Uhr ist angehalten
COLOR 0, 7 'Zeitanzeige schwarz auf hellgrau
'
'******** Tasten abfragen *****************************************
DO
Taste$ = INKEY$
'
SELECT CASE Taste$
CASE "s", "S" 'Start/Stopp betaetigt
StartZeit! = TIMER - Sekunden!
IF Uhrlaeuft% = 0 THEN Uhrlaeuft% = 1 ELSE Uhrlaeuft% = 0
CASE "r", "R" 'Ruecksetzen betaetigt
Sekunden! = 0 'Stoppuhr auf 0 setzen ...
Uhrlaeuft% = 0 '... und anhalten
CASE CHR$(27) 'Programm beenden bei Esc-Taste
END
END SELECT
'
'******** Zeit in Sekunden ermitteln ******************************
IF Uhrlaeuft% = 1 THEN
IF StartZeit! > TIMER THEN 'Ist des Ruecksetzen des TIMERs
'um Mitternacht erfolgt?
Sekunden! = TIMER + 86400 - StartZeit!
'Ruecksetzen kompensieren
ELSE
Sekunden! = TIMER - StartZeit! 'kein Mitternachtssprung
END IF
END IF
'
'******** Stunden:Minuten:Sekunden fuer Anzeige ermitteln *********
'DOUBLE-Gleitpunktformat verwenden, um die Rundungsfehler klein zu
'halten. Die Ganzzahldivision "\" kann wegen Genauigkeitsproblemen
'nicht verwendet werden und ist durch INT ersetzt.
'
Sekunden# = CDBL(Sekunden!) 'Typumwandlung in DOUBLE
Stunden# = INT(Sekunden# / 3600#)
Minuten# = INT((Sekunden# - Stunden# * 3600#) / 60#)
Sekundenanzeige# = Sekunden# - INT(Sekunden# / 60#) * 60#
'
'******** Zeit anzeigen ******************************************
LOCATE 4, 2
PRINT USING "##:"; Stunden#; 'Stunden 2-stellig anzeigen
PRINT USING "##:"; Minuten#; 'Minuten 2-stellig anzeigen
PRINT USING "##.#"; Sekundenanzeige# 'Sekunden 3-stellig anzeigen
LOOP
|
------------------------------------------------------------------------------------- _________________ +++ Die beliebte QBasic CD-ROM von QBasic.de - 670 MB QBasic-Stuff mit komfortabler HTML-Oberfläche. Für nur 5 EUR bestellbar auf www.antonis.de/qbcdueb.htm +++ |
|
Nach oben |
|
|
Skilltronic
Anmeldungsdatum: 10.09.2004 Beiträge: 1148 Wohnort: Köln
|
Verfasst am: 08.04.2005, 11:35 Titel: |
|
|
Hallo
Immer wieder kommt die Frage, ob es nicht auch genauer geht als 55ms. Vielleicht könnte man den FAQ-Eintrag noch dahingehend erweitern. Dazu hätte ich folgende Idee:
Wie arbeite ich mit Zeiten unter 55ms?
Das folgende funktioniert nur unter echtem DOS richtig. Unter Windows ist die Nutzung nur eingeschränkt möglich. Aber für Messungen im Bereich von Millisekunden und darunter sollte man sowieso unter DOS arbeiten. Da erreiche ich dann mit meinem 1GHz-Athlon eine Genauigkeit von ca. 6µs, also sechs millionstel Sekunden. Theorteisch ist sogar knapp unter einer Mikrosekunde möglich!
Für die zeitliche Steuerung von Prozessen, die ungestört vom restlichen System laufen sollen, besitzt der PC einen speziellen Baustein, der von einem eigenen Quarz mit einem unabhängigen Taktsignal versorgt wird. Dieser PIT (programmierbarer Intervalltimer Typ 8253 oder 8254) besteht eigentlich aus drei Timern, die dieses Taktsignal für verschieden Aufgaben nutzen.
Timer 0 erzeugt das Signal für den TIMER-Befehl
Timer 1 ist für den Refresh des Arbeitsspeichers zuständig
Timer 2 regelt die Tonausgabe am Systemlautsprecher
Mit 0 und 2 kann man arbeiten, von Timer 1 sollte man tunlichst die Finger lassen, um keinen Absturz zu provozieren. Ich beschränke mich hier nur auf Timer 0. Im Standardmodus funktioniert er wie zwei 8-Bit-Rückwärtszähler. Der Quarz erzeugt eine Frequenz von 1193182Hz (Manche Quellen geben auch 1193180Hz an). Diese Impule gehen zum ersten Zähler. Immer beim Überlauf von 0 auf 255 erzeugt dieser ein neues Signal an seinem Ausgang, dessen Frequenz folglich 256 mal niedriger ist als die am Eingang. Der zweite Zähler teilt die Frequenz nach dem selben Prinzip nochmal um den Faktor 256 herunter.
Quarz 1193182Hz -> 8-Bit Teiler -> 4660.87Hz -> 8-Bit Teiler -> 18,2Hz
18,2Hz entsprechen einer Periode von 55ms und damit haben wir schon die Begründung für die Auflösung des TIMER-Befehls. Der arbeitet nämlich genau mit den Signalen, die der zweite 8-Bit-Zähler ausgibt.
Warum so krumme Zahlen? Wenn man die Frequenz von 18,2Hz nochmal durch 2^16 teilt, kommt ein Takt von 0,0002778Hz heraus - eine Periodendauer von fast genau einer Stunde (3599,59 sek.). Wenn man es genau ausrechnet, müsste eine Stoppuhr mit TIMER allerdings nach 24 Std. knapp 10 Sekunden zu viel anzeigen.
Der Trick ist nun, dass sich der Stand der beiden 8-Bit Zähler mit INP() auslesen lässt. Dabei liegt im Standardmodus immer zuerst der untere, dann der obere Zählerstand an. Ähnlich wie beim Auslesen der Farbwerte mit OUT, wo auch R, G und B nacheinander unter der selben Adressen abgefragt werden. Nach dem lesen des einen liegt beim nächsten mal automatisch der andere Wert an. Die Pit belegt die Registeradressen 64-67 (bzw. 40h- 43h)
64: Timer 0
65: Timer 1
66: Timer 2
67: Steuerbyte
Zum Steuerbyte später.
Mit
Code: | lowbyte = INP(64)
highbyte = INP(64)
t = TIMER |
kann man einen Zeitpunkt also bis zu 65536 mal genauer bestimmen als mit TIMER allein. Wenn in dem Fall z.B. lowbyte=117 und highbyte=53 ist, dann sind seit dem letzten Sprung von TIMER
(65536 - lowbyte - highbyte * 256) / 1193182
also ca. 43,5ms vergangen. Nicht vergessen - der Zähler läuft rückwärts!
Es kann nur passieren, dass wärend des Auslesens von lowbyte gerade beide Zähler auf 0 stehen. Wenn in der nächsten Programmzeile das highbyte gelesen wird, kann der Zähler schon etwas weitergelaufen sein und auf 255 umgeschlagen haben. Je nach Anwendung muss man dies noch abfangen. Wenn man aber immer nur einen der beiden Zähler, erledigt sich dieses Problem von selbst. Eine millisekundengenaue Stoppuhr könnte im einfachsten Fall so aussehen:
Code: | zeit = 0
DO : LOOP WHILE INKEY$ = "" 'Start mit Taste
lb = INP(64)
hbalt = INP(64)
DO
lb = INP(64)
hb = INP(64)
d = hbalt - hb
IF d < 0 THEN d = d + 256
zeit = zeit + d
hbalt = hb
LOOP WHILE INKEY$ = "" 'Stop mit Taste
PRINT USING "#####.###" ;256 * zeit / 1193182; : PRINT "Sekunden" |
Das lowbyte wird nicht weiter verwendet, muss nur mit ausgelesen werden. Trotzdem sind die drei Nachkommastellen keine Übertreibung. Benutzt man nur das lowbyte, wird sogar auf millionstel Sekunden genau gemessen. Je nach dem, was die Rechnergeschwindigkeit zulässt.
Die Funktionen des PIT lassen sich über das Steuerbyte aber auch verändern. Das ist etwas komplizierter, aber eigentlich der richtige Weg ihn zu nutzen. Schliesslich ist es ja ein programmierbarer Intervalltimer. Wie bei vielen Steurregistern hat jedes Bit innerhalb des Bytes eine eigene Bedeutung.
Bit 0: Zählweise binär (=0) oder im BCD-Code (=1)
Bit 1-3: Betriebsart Impuls (=010) etc.
Bit 4-5: siehe unten
Bit 6-7: Timerauswahl (00= TImer 0, 10 = T1, 01 =T2)
Mit Bit 4 und 5 kann man auswählen, ob und welche der Zähler benutzt werden.01 bedeutet, das beim Auslesen immer nur das highbyte ausgegeben wird, bei 10 nur das lowbyte.. 11 ist der Standardmodus, bei dem immer beide Byte nacheinander übergeben werden. Bei 00 wird der Zählerstand zwischengespeichert, um das oben erwähnte Weiterlaufen wärend des Auslesens zu vermeiden.
Darüber hinaus kann man auch noch Werte in die Zähler hineninschreiben und so festlegen, auf welchen Wert sie nach 0 umschlagen sollen. Man ist nicht an die 65535 bis 0 gebunden. Ist der Modus 11 = "beide Byte ausgeben" gewählt, müssen beide Werte geschrieben werden, sonst nur der eine der ausgelesen werden soll. Der andere ist dann wie ausgeschaltet. Werden diese Werte gändert, läuft der Takt für TIMER natürlich nicht meht mit 55ms sondern schneller Wenn man z.B. anstellen von 55ms nur noch eine haben will, kann man den Zähler entsprechend einstellen. Normal wird von 65535 bis 0 herutergezahlt.65536/55 ist ca. 1192. Also darf nur noch ab 1191 gezählt werden. Das passt nicht mehr in ein Byte, da brauchen wir beide. Also Bit 4 und 5 des Steuerbytes auf eins. Das ganze Byte sieht dann so aus:
00110100 = 52
00 für Zähler 0
11 für beide Zähler
010 für Betriebsart Impuls
0 für binäres Zählen
1192 ist 4*256 + 168. Der PIT muss also wie folgt konfiguriert werden:
Code: | OUT 67, 52
OUT 64, 167
OUT 64, 4 |
Das höherwertige Byte auf 4 nicht 3, weil rückwärts gezählt wird und das 4. Byte ja nicht mehr ganz durchgezählt wird. Schon läuft der Timer 55 mal schneller. Nicht mehr mit 18,2Hz sondern mit 1kHz. Wenn man jetzt jede Sekunde eine Abfrage mit TIMER macht, steigt dessen Stand nicht um 1 sondern um 55. Die Zeit bis zum Überlauf von TIMER von 86399 auf 0 dauert dann natürlich auch nicht mehr 24 Stunden (bzw. 23:59:50,2 s.o.) sondern nur noch eine knappe 3/4 Stunde. So lassen sich ganz bequem die verschiedenen Beispielstoppuhren, die mit dem TIMER-Befehl arbeiten auf die gewünschte Genauigkeit einstellen.
Hier noch ein guter Link in dem alle Funktionen des PIT, vor allem die verschiedenen Betriebsarten etc. beschrieben sind: http://www.sharpmz.org/mz-700/8253ovview.htm
Wie gesagt gilt das alles so nur unter DOS. Was davon unter welcher Windowsversion funktioniert müsst ihr selbst ausprobieren. Ist jetzt auch etwas ausführlich geworden, aber vielleicht ist das eine oder andere interessante dabei.
Gruss
Skilltronic _________________ Elektronik und QB? www.skilltronics.de ! |
|
Nach oben |
|
|
Thomas Antoni
Anmeldungsdatum: 12.10.2004 Beiträge: 220 Wohnort: Erlangen
|
Verfasst am: 11.04.2005, 18:25 Titel: Vielen Dank Skilltronik! |
|
|
Vielen Dank Skilltronik für den ausführlichen Beitrag! Ich habe mir das für die QB-MonsterFAQ vorgemerkt. _________________ +++ Die beliebte QBasic CD-ROM von QBasic.de - 670 MB QBasic-Stuff mit komfortabler HTML-Oberfläche. Für nur 5 EUR bestellbar auf www.antonis.de/qbcdueb.htm +++ |
|
Nach oben |
|
|
Skilltronic
Anmeldungsdatum: 10.09.2004 Beiträge: 1148 Wohnort: Köln
|
Verfasst am: 11.04.2005, 22:01 Titel: |
|
|
Bitteschön. Freut mich, dass sich doch noch jemand dafür interessiert...
Gruss
SkilltroniC _________________ Elektronik und QB? www.skilltronics.de ! |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|