Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht Das deutsche QBasic- und FreeBASIC-Forum
Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
 
FAQFAQ   SuchenSuchen   MitgliederlisteMitgliederliste   BenutzergruppenBenutzergruppen  RegistrierenRegistrieren
ProfilProfil   Einloggen, um private Nachrichten zu lesenEinloggen, um private Nachrichten zu lesen   LoginLogin
Zur Begleitseite des Forums / Chat / Impressum
Aktueller Forenpartner:

Timer

 
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu QBasic.
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen  
Autor Nachricht
psygate



Anmeldungsdatum: 05.04.2005
Beiträge: 304
Wohnort: Wien und der Computer

BeitragVerfasst am: 05.04.2005, 18:48    Titel: Timer Antworten mit Zitat

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? grinsen
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
jb



Anmeldungsdatum: 14.01.2005
Beiträge: 2010

BeitragVerfasst am: 05.04.2005, 20:22    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
psygate



Anmeldungsdatum: 05.04.2005
Beiträge: 304
Wohnort: Wien und der Computer

BeitragVerfasst am: 06.04.2005, 10:46    Titel: Hm.... Antworten mit Zitat

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?! weinen
Was ist da das Problem?? Er stoppt nämlich NIE!

HILFE... weinen weinen peinlich
---------------------------------------
psy, der Anfänger


Zuletzt bearbeitet von psygate am 06.04.2005, 10:50, insgesamt einmal bearbeitet
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Skilltronic



Anmeldungsdatum: 10.09.2004
Beiträge: 1148
Wohnort: Köln

BeitragVerfasst am: 06.04.2005, 11:30    Titel: Re: Hm.... Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
psygate



Anmeldungsdatum: 05.04.2005
Beiträge: 304
Wohnort: Wien und der Computer

BeitragVerfasst am: 06.04.2005, 11:41    Titel: Re: Hm.... Antworten mit Zitat

THX! Wenn das jetzt geht! Konnte es nicht testen, weil ich in der Schule sitze... happy

1. Wenn das geht, dann vielen Dank!
Ja, jb Code hätte ich gerade noch mti eminen Kenntnissen entwerfen können happy
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... weinen Kopf schütteln durchgeknallt mit dem Kopf durch die Mauer wollen

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

Zitat:

4. Sieh dir das mal an: http://forum.qbasic.at/viewtopic.php?t=555

oder das: http://forum.qbasic.at/viewtopic.php?t=58

Ganz großen THX an dich Silk durchgeknallt

PS: Ich möchte SUB unter allen Umständen vermeiden, die machen mein Prog unnötig komplizierter und größer... lachen
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
psygate



Anmeldungsdatum: 05.04.2005
Beiträge: 304
Wohnort: Wien und der Computer

BeitragVerfasst am: 06.04.2005, 14:14    Titel: Neue Frage; Antworten mit Zitat

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? mit dem Kopf durch die Mauer wollen lachen
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
code



Anmeldungsdatum: 19.01.2005
Beiträge: 154

BeitragVerfasst am: 06.04.2005, 14:18    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden
psygate



Anmeldungsdatum: 05.04.2005
Beiträge: 304
Wohnort: Wien und der Computer

BeitragVerfasst am: 06.04.2005, 14:22    Titel: Antworten mit Zitat

Ich hoff' doch stark, dass das agle ist?! grinsen durchgeknallt ansonsten bin ich R.I.P.
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Skilltronic



Anmeldungsdatum: 10.09.2004
Beiträge: 1148
Wohnort: Köln

BeitragVerfasst am: 06.04.2005, 15:00    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
jb



Anmeldungsdatum: 14.01.2005
Beiträge: 2010

BeitragVerfasst am: 06.04.2005, 15:35    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
psygate



Anmeldungsdatum: 05.04.2005
Beiträge: 304
Wohnort: Wien und der Computer

BeitragVerfasst am: 06.04.2005, 17:10    Titel: Antworten mit Zitat

*lölz* Danke, hab mich schon gewundert lachen peinlich mit dem Kopf durch die Mauer wollen

EDIT:

War wieder mal voreilig.... mit dem Kopf durch die Mauer wollen das kommt davon wenn man nciht liest! Danke Silktronnic

Ich versuch das mal....
sagt mal, wie kommt man ins dos, ohne disketten laufwerk? grinsen
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden
Thomas Antoni



Anmeldungsdatum: 12.10.2004
Beiträge: 220
Wohnort: Erlangen

BeitragVerfasst am: 06.04.2005, 19:57    Titel: Zu dem Thema habe ich mir für die QB-MonsterFAQ vorgemerkt.. Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Skilltronic



Anmeldungsdatum: 10.09.2004
Beiträge: 1148
Wohnort: Köln

BeitragVerfasst am: 08.04.2005, 11:35    Titel: Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Thomas Antoni



Anmeldungsdatum: 12.10.2004
Beiträge: 220
Wohnort: Erlangen

BeitragVerfasst am: 11.04.2005, 18:25    Titel: Vielen Dank Skilltronik! Antworten mit Zitat

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
Benutzer-Profile anzeigen Private Nachricht senden E-Mail senden Website dieses Benutzers besuchen
Skilltronic



Anmeldungsdatum: 10.09.2004
Beiträge: 1148
Wohnort: Köln

BeitragVerfasst am: 11.04.2005, 22:01    Titel: Antworten mit Zitat

Bitteschön. Freut mich, dass sich doch noch jemand dafür interessiert...

Gruss
SkilltroniC
_________________
Elektronik und QB? www.skilltronics.de !
Nach oben
Benutzer-Profile anzeigen Private Nachricht senden Website dieses Benutzers besuchen
Beiträge der letzten Zeit anzeigen:   
Neues Thema eröffnen   Neue Antwort erstellen    Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht -> Allgemeine Fragen zu QBasic. Alle Zeiten sind GMT + 1 Stunde
Seite 1 von 1

 
Gehe zu:  
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.

 Impressum :: Datenschutz