|
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 |
blackdrake
Anmeldungsdatum: 29.05.2007 Beiträge: 11
|
Verfasst am: 30.05.2007, 15:29 Titel: PIT-Timer funktioniert bei Sounds nicht |
|
|
Hallo.
Ich habe mich ein wenig mit den PIT-Timern beschäftigt, weil SLEEP mit durch Tastendruck abgebrochen werden kann und keine Millisekunden zählen kann, FOR..NEXT CPU-Geschwindigkeits-Abhängig ist und TIMER nur bis 0.56 Millisekunden zählen kann und bei Mitternacht das Programm durch herunterspringen auf 0 zum Absturz bringt.
Ich habe einen PIT-Timer in ein Spiel eingebaut, das davor FOR..NEXT nutzte. Das Spiel stürzte darauf ständig ab. Nun habe ich den Grund dafür gefunden: Es war die PLAY-Prozedur, die Töne wiedergibt. Ich habe nun ein Testprogramm zusammengestickt, das den Fehler genau rekonstruiert.
PS: Hier habe ich die PIT-ASM-Variante genommen, bei Basic-16Bit und Basic-8Bit kommt es auch zum Absturz.
Hier die komplette BAS-Datei:
Code: | DECLARE SUB MdelayASM (Ziel&, asm$)
Millisek% = 1
'8253-Timer 16-Bit-Zielwert:
'Pro Millisekunde werden 1193,18 Tics gez„hlt (65536 / 54,92549 )
ziel16& = 65535 - (Millisek% * 1193.18)
'- WICHTIG BEI ZAEHLER 2: Lautsprecher ueber Port 61h, Bit1 aktivieren ------
OUT (&H61), INP(&H61) OR 1
i = 0
CLS
CALL MdelayASM(ziel16&, asm$)
DEF SEG = VARSEG(asm$) 'Das Speicher-Segment von asm$ festlegen
Offset% = SADD(asm$) 'den Speicher-Offset vom asm$ speichern
DO
CALL ABSOLUTE(Offset%) 'Delay erzeugen (ASM-Routine aufrufen)
i = i + 1
IF i MOD 1000 = 0 THEN
PRINT i
PLAY "mb l32 eeeeddddcccc" 'Diese Zeile bringt das Programm zum Absturz!!!
END IF
LOOP UNTIL INKEY$ = "x"
DEF SEG 'Standart Segment wiederherstellen
SUB MdelayASM (Ziel&, asm$)
Lo% = Ziel& MOD 256 'LowByte aus Ziel& ermitteln
Hi% = Ziel& \ 256 'HighByte von Ziel& ermitteln
Ziel$ = CHR$(Lo%) + CHR$(Hi%) 'zu einem String zusammensetzen
'(INTEL-Schreibweise: LowByte links)
' ------ Created with Absolute Assembly 2.1 by Petter Holmberg, -97. ------- '
asm$ = ""
asm$ = asm$ + CHR$(&HE4) + CHR$(&H61) ' IN AL,61 ;Port 61h lesen
asm$ = asm$ + CHR$(&HC) + CHR$(&H1) ' OR AL,01 ;Bit1 setzen (Laustspr. an)
asm$ = asm$ + CHR$(&HE6) + CHR$(&H61) ' OUT 61,AL ;und nach Port 61h ausgeben
asm$ = asm$ + CHR$(&HB0) + CHR$(&HB4) ' MOV AL,B4 ;AL mit 180 (B4h) laden
asm$ = asm$ + CHR$(&HE6) + CHR$(&H43) ' OUT 43,AL ;und auf Port 43h ausgeben
asm$ = asm$ + CHR$(&HB0) + CHR$(&HFF) ' MOV AL,FF ;AL mit 255 laden (FFh)
asm$ = asm$ + CHR$(&HE6) + CHR$(&H42) ' OUT 42,AL ;und auf Port 42h ausgeben (LowByte)
asm$ = asm$ + CHR$(&HE6) + CHR$(&H42) ' OUT 42,AL ;und auf Port 42h ausgeben (HighByte)
asm$ = asm$ + CHR$(&HE6) + CHR$(&H42) ' OUT 42,AL ;nochmal f?r schnelle Prozessoren
asm$ = asm$ + CHR$(&HB0) + CHR$(&H80) ' Pit: MOV AL,80 ;Marke "Pit";AL mit 128 (80h) laden
asm$ = asm$ + CHR$(&HE6) + CHR$(&H43) ' OUT 43,AL ;und auf Port 43h ausgeben (CounterLatch)
asm$ = asm$ + CHR$(&HE4) + CHR$(&H42) ' IN AL,42 ;Byte von Port 42h nach AL lesen (LowByte)
asm$ = asm$ + CHR$(&H88) + CHR$(&HC4) ' MOV AH,AL ;und nach AH schieben
asm$ = asm$ + CHR$(&HE4) + CHR$(&H42) ' IN AL,42 ;Byte von Port 42h nach AL lesen (HighByte)
asm$ = asm$ + CHR$(&H86) + CHR$(&HE0) ' XCHG AH,AL ;AH/AL tauschen, AX hat den 16-Bit Wert
asm$ = asm$ + CHR$(&H3D) + Ziel$ ' CMP AX,(Ziel) ;AX mit Zielwert vergleichen
asm$ = asm$ + CHR$(&H77) + CHR$(&HEF) ' JA Pit ;wenn groesser (Ziel noch nicht erreicht) nach Pit springen
asm$ = asm$ + CHR$(&HCB) ' RETF ;sonst zurueck nach Basic
' ------ Created with Absolute Assembly 2.1 by Petter Holmberg, -97. ------- '
END SUB |
Weiß irgendwer Rat?
Gruß
blackdrake |
|
Nach oben |
|
|
Jojo alter Rang
Anmeldungsdatum: 12.02.2005 Beiträge: 9736 Wohnort: Neben der Festplatte
|
Verfasst am: 30.05.2007, 16:05 Titel: |
|
|
Versuche mal diese PITcal-Routine:
Code: |
'Vor dem Programmstart:
DIM SHARED PIT(1) AS LONG
T& = 0: V = 5
FOR W = 1 TO V
T& = T& + PITCal
NEXT
PIT(0) = T& / V
FUNCTION PITCal&
P& = 0: DEF SEG = 0: X% = (PEEK(&H46C) + 1) AND 255
WHILE X% <> (PEEK(&H46C) AND 255): WEND
WHILE X% = (PEEK(&H46C) AND 255)
P& = P& + 33
FOR T% = 1 TO 19: WAIT (64), 128, 128: WAIT (64), 128: NEXT
WEND
PITCal& = P& * 11.02
END FUNCTION
SUB Warte (Seconds#) 'Dieses hier aufrufen, mit einem sekundenwert. 0.5 ist dann eine halbe sekunde.
D& = FIX(Seconds# * PIT(0))
FOR T& = 0 TO D&: WAIT 64, 128: WAIT 64, 128, 128: NEXT
END SUB |
_________________ » Die Mathematik wurde geschaffen, um Probleme zu lösen, die es nicht gäbe, wenn die Mathematik nicht erschaffen worden wäre.
|
|
Nach oben |
|
|
blackdrake
Anmeldungsdatum: 29.05.2007 Beiträge: 11
|
Verfasst am: 30.05.2007, 16:39 Titel: |
|
|
Hallo Jojo
Vielen Dank für die Routine! Damit funktioniert es
Gruß
blackdrake |
|
Nach oben |
|
|
Jojo alter Rang
Anmeldungsdatum: 12.02.2005 Beiträge: 9736 Wohnort: Neben der Festplatte
|
Verfasst am: 30.05.2007, 17:10 Titel: |
|
|
kein problem _________________ » Die Mathematik wurde geschaffen, um Probleme zu lösen, die es nicht gäbe, wenn die Mathematik nicht erschaffen worden wäre.
|
|
Nach oben |
|
|
Skilltronic
Anmeldungsdatum: 10.09.2004 Beiträge: 1148 Wohnort: Köln
|
Verfasst am: 30.05.2007, 18:43 Titel: |
|
|
Hallo,
ich hätte da auch noch einen Vorschlag. Würde mich interessieren, ob das bei Dir funktioniert.
Code: | OUT 67, 36 'Nur hoeherwertiges Byte auslesen
OUT 64, 0 'PIT initialiesieren
DO
wzeit% = 1000 'Wartezeit in Millisekunden
GOSUB warten
PRINT "Tick"
LOOP
warten:
nwz% = wzeit% * 4.661 'Zaehler laeuft mit 4661 Hz
tgesamt% = 0
ialt% = INP(64)
DO
i% = INP(64)
dt% = ialt% - i%
ialt% = i%
IF dt% < 0 THEN dt% = dt% + 256
tgesamt% = tgesamt% + dt%
LOOP WHILE tgesamt% < nwz%
RETURN |
Gruß
Skilltronic _________________ Elektronik und QB? www.skilltronics.de ! |
|
Nach oben |
|
|
blackdrake
Anmeldungsdatum: 29.05.2007 Beiträge: 11
|
Verfasst am: 31.05.2007, 02:40 Titel: |
|
|
Hallo.
Die zweite Variante funktioniert leider in dem Zusammenhang nicht. Aber danke für den Beitrag.
Gruß
blackdrake |
|
Nach oben |
|
|
Flo aka kleiner_hacker
Anmeldungsdatum: 23.06.2006 Beiträge: 1210
|
Verfasst am: 31.05.2007, 19:59 Titel: |
|
|
Skilltronic hat Folgendes geschrieben: | Hallo,
ich hätte da auch noch einen Vorschlag. Würde mich interessieren, ob das bei Dir funktioniert.
Code: | OUT 67, 36 'Nur hoeherwertiges Byte auslesen
OUT 64, 0 'PIT initialiesieren
DO
wzeit% = 1000 'Wartezeit in Millisekunden
GOSUB warten
PRINT "Tick"
LOOP
warten:
nwz% = wzeit% * 4.661 'Zaehler laeuft mit 4661 Hz
tgesamt% = 0
ialt% = INP(64)
DO
i% = INP(64)
dt% = ialt% - i%
ialt% = i%
IF dt% < 0 THEN dt% = dt% + 256
tgesamt% = tgesamt% + dt%
LOOP WHILE tgesamt% < nwz%
RETURN |
Gruß
Skilltronic |
[100%-offtopic]
@skilltronics: GOSUB...
war das jetzt quick n dirty oder machst du in "normalen" programmen auch goto/gosub? *ytwinky hol* _________________ MFG
Flo
Satoru Iwata: Wer Spaß am Spielen hat, fragt nicht nach Grafik.
zum korrekten Verstaendnis meiner Beitraege ist die regelmaessige Wartung des Ironiedetektors unerlaesslich. |
|
Nach oben |
|
|
Eternal_pain
Anmeldungsdatum: 08.08.2006 Beiträge: 1783 Wohnort: BW/KA
|
Verfasst am: 31.05.2007, 20:11 Titel: |
|
|
Alternativ könnte man es ja auch so umschreiben...
Code: |
Declare Sub warten
dim key as string
Dim shared wzeit%
OUT 67, 36 'Nur hoeherwertiges Byte auslesen
OUT 64, 0 'PIT initialiesieren
DO
key=inkey$
wzeit% = 100 'Wartezeit in Millisekunden
warten
?"Tick"
LOOP until key=chr$(27)
Sub warten
nwz% = wzeit% * 4.661 'Zaehler laeuft mit 4661 Hz
tgesamt% = 0
ialt% = INP(64)
DO
i% = INP(64)
dt% = ialt% - i%
ialt% = i%
IF dt% < 0 THEN dt% = dt% + 256
tgesamt% = tgesamt% + dt%
LOOP WHILE tgesamt% < nwz%
tick=tick+1
End Sub
|
_________________
|
|
Nach oben |
|
|
Skilltronic
Anmeldungsdatum: 10.09.2004 Beiträge: 1148 Wohnort: Köln
|
Verfasst am: 31.05.2007, 21:57 Titel: |
|
|
kleiner_hacker hat Folgendes geschrieben: |
[100%-offtopic]
@skilltronics: GOSUB...
war das jetzt quick n dirty oder machst du in "normalen" programmen auch goto/gosub? *ytwinky hol* |
Ich wusste, das sowas kommt. Ich hatte es sogar schon umgeschrieben und wollte meinen Beitrag entsprechend editieren, hab' es mir dann aber doch verkniffen, weil ich dachte, dass ja jeder hier versteht, dass es nicht um einen Schönschreibwettbewerb geht, sondern um das Auslesen des PIT bei gleichzeitigem Gebrauch von PLAY. Und obwohl ich nicht weiss, was Dich das interessiert - ja, ich arbeite gern mit lokalen Subs, vor allem bei Progrmmen, die weniger als 20 Zeilen haben und auch GOTO wird von mir nicht prinzipiell verschmäht. Sind ja schliesslich meine Programme.
Viel mehr würde mich aber interessieren, warum bei Jojos Version die PLAY-Anweisung funktioniert, bei blackdrakes und meiner aber nicht. Würde mich freuen, wenn das jemand aufklären könnte. Das es wohl daran liegt, das der PIT auch für die Takterzeugung der Töne zuständig ist und sich da irgendwie selbst in die Quere kommt, denke ich verstanden zu haben. Mir geht es ums Detail.
Ach, und @Eternal_pain: Das tick = tick + 1 ist unnötig, weiter oben steht ja PRINT "Tick" und nicht PRINT tick. Das soll einem nur Zeigen, das was passiert.
Gruß
Skilltronic _________________ Elektronik und QB? www.skilltronics.de ! |
|
Nach oben |
|
|
Jojo alter Rang
Anmeldungsdatum: 12.02.2005 Beiträge: 9736 Wohnort: Neben der Festplatte
|
Verfasst am: 31.05.2007, 22:13 Titel: |
|
|
kann es vlt daran liegen, dass deine INP benutzt? inp(64) ist ja nahe am pc-speaker output dran... _________________ » Die Mathematik wurde geschaffen, um Probleme zu lösen, die es nicht gäbe, wenn die Mathematik nicht erschaffen worden wäre.
|
|
Nach oben |
|
|
Eternal_pain
Anmeldungsdatum: 08.08.2006 Beiträge: 1783 Wohnort: BW/KA
|
Verfasst am: 31.05.2007, 22:19 Titel: |
|
|
dast tick=tick+1 hab ich vergessen rauszunehmen als ich damit rumprobiert habe _________________
|
|
Nach oben |
|
|
Skilltronic
Anmeldungsdatum: 10.09.2004 Beiträge: 1148 Wohnort: Köln
|
Verfasst am: 31.05.2007, 23:37 Titel: |
|
|
Jojo hat Folgendes geschrieben: | kann es vlt daran liegen, dass deine INP benutzt? inp(64) ist ja nahe am pc-speaker output dran... |
Kannst Du mir auch erklären, wo der Unterschied zwischen WAIT und INP() liegt bzw. was an dem einen "näher" an der Rechner-Lautsprecherausgabe dran ist als beim anderen? Was mich wundert ist, dass das Problem mit PLAY auch dann auftritt, wenn ich den 2. PIT mit INP(&h48) benutze oder per Konfigurationsbyte den Zähler 0 wähle. Tonerzeugung soll angeblich über Zähler 2 laufen, in meinem Beispiel stelle ich per Steuerbyte Zähler 0 ein und trotzdem spinnt es im Zusammenhang mit PLAY.
In der Routine von blackdrake wird hier
Code: | asm$ = asm$ + CHR$(&HB0) + CHR$(&HB4) ' MOV AL,B4 ;AL mit 180 (B4h) laden
asm$ = asm$ + CHR$(&HE6) + CHR$(&H43) ' OUT 43,AL ;und auf Port 43h ausgeben |
doch im Prinzip das Gleiche gemacht, wie bei meinem OUT 67, 36 (Bit 3 und 6 gesetzt) ,nur wird hier statt mit 36 eben mit 180 (Bit 3, 5, 6 und 8 gesetzt) bei PIT 1 der Zähler 2 gewählt und beide Zählerbytes ausgelesen. PLAY kann doch nicht alle Kanäle des PIT lahmlegen, bei Deinem Beispiel geht es ja auch. Hast Du die PIT-Routine denn selbst geschrieben und wenn nicht, wo hast Du die her und steht da Näheres dazu?
Gruß
Skilltronic _________________ Elektronik und QB? www.skilltronics.de ! |
|
Nach oben |
|
|
blackdrake
Anmeldungsdatum: 29.05.2007 Beiträge: 11
|
Verfasst am: 01.06.2007, 14:58 Titel: |
|
|
Hallo.
Zitat: | Tonerzeugung soll angeblich über Zähler 2 laufen |
Hat mein ersteres, nicht mit PLAY funktionierendes, Beispiel nicht auch den 2. PIT benutzt?
Code: | '- WICHTIG BEI ZAEHLER 2: Lautsprecher ueber Port 61h, Bit1 aktivieren ------
OUT (&H61), INP(&H61) OR 1 |
Gruß
blackdrake |
|
Nach oben |
|
|
Skilltronic
Anmeldungsdatum: 10.09.2004 Beiträge: 1148 Wohnort: Köln
|
Verfasst am: 01.06.2007, 22:42 Titel: |
|
|
blackdrake hat Folgendes geschrieben: | Hat mein ersteres, nicht mit PLAY funktionierendes, Beispiel nicht auch den 2. PIT benutzt?
Code: | '- WICHTIG BEI ZAEHLER 2: Lautsprecher ueber Port 61h, Bit1 aktivieren ------
OUT (&H61), INP(&H61) OR 1 |
|
Also es gibt zwei PITs mit je drei Zählern, in Deinem Beispiel wird - soweit ich das verstehe und wie oben beschrieben - Zähler 2 (Zählweise 0-2, also der dritte Zähler) vom 1. PIT benutzt. Was das mit dem Lautsprecher aktivieren soll, verstehe ich nicht.
Aber ich habe jetzt eine Einstellung gefunden, bei der die Warteschleife korrekt läuft und PLAY gleichzeitig im Hintergrund spielt:
Code: | DECLARE SUB warten (wzeit%)
CLS
OUT 67, 100 'Zaehler 1, nur hoeherwertiges Byte auslesen
OUT 65, 0
PLAY "MB cdefl2ggl4aaaal2g"
DO
warten 1000 '1000 Millisekunden warten
PRINT "Tick"
LOOP WHILE INKEY$ = ""
SUB warten (wzeit%)
nwz% = wzeit% * 4.661 'Zaehler laeuft mit 4661 Hz
tgesamt% = 0
ialt% = INP(65)
DO
i% = INP(65)
dt% = ialt% - i%
ialt% = i%
IF dt% < 0 THEN dt% = dt% + 256
tgesamt% = tgesamt% + dt%
LOOP WHILE tgesamt% < nwz%
END SUB |
Das ist mit Zähler 1 von PIT 1. Diese Einstellung hatte ich bisher nicht probiert, weil ich mal gelesen hatte, dass dieser Zähler für den Speicher-Refresh zuständig ist und man damit einen Absturz provozieren kann, aber es funktioniert bei mir tadellos.
Übrigens habe ich fast alles was ich über den PIT weiss, von diesen beiden Seiten:
http://www.sharpmz.org/mz-700/8253ovview.htm
http://ivs.cs.uni-magdeburg.de/bs/lehre/sose99/bs1/aufgaben/aufgabe3/timer.shtml
Gruß
Skilltronic _________________ Elektronik und QB? www.skilltronics.de ! |
|
Nach oben |
|
|
Steini63
Anmeldungsdatum: 11.11.2004 Beiträge: 28 Wohnort: 30926 Seelze
|
Verfasst am: 02.06.2007, 12:16 Titel: |
|
|
Hallo Leute,
den Code, den blackdrake benutzt hat, stammt von mir ; PITDELAY.BAS aus www.franksteinberg.de/SOURCE/TIMING.ZIP. In der ZIP sind übrigens auch noch einige Dokus und andere Beispiele drin. Dass es zu Problemen kommt, wenn der "missbrauchte" Zähler1 wieder seine eigentliche Aufgabe übernehmen soll, nämlich Töne erzeugen, ist zwangsläufig.
Zitat: | '- WICHTIG BEI ZAEHLER 2: Lautsprecher ueber Port 61h, Bit1 aktivieren ------
OUT (&H61), INP(&H61) OR 1 |
Wenn dieses Bit nicht gesetzt wird, wird Zähler2 einfach nicht aktualisiert bzw. ist nicht auslesbar.
Zum Thema Zähler1:
So wie ich das verstanden habe, ist nicht klar mit welchem Wert der Timer zählt. Bei Zähler0 ist es immer der volle Umfang (65535 bis 0). Bei Zähler2 gibt man den Startwert selber vor. Zähler1 ist mit irgendeinem Zählerstand initialisiert. Nach Ablauf diese Zählerstandes wird jeweils ein Speicherrefresh ausgelöst.
Warum kommt es bei Skilltronic nicht zum Absturz? Weiß ich auch nicht. Aber ich hebe ein paar Vermutungen:
- Moderne RAM-Speicher brauchen das garnicht mehr oder der Refresh wird anders erzeugt.
- Windows emuliert den PIT nur und der Refresh wird garnicht beeinflusst.
Vielleicht lohnt es, den 2. PIT zu bemühen. Ich habe das damals nicht gemacht, weil ich auf einem DOS-Palmtop programmiert habe und der hatte keinen. _________________ Viele Grüße Steini
http://www.FrankSteinberg.de +++++++ Planung ist das Ersetzen des Zufalls durch den Irrtum +++++++ |
|
Nach oben |
|
|
Skilltronic
Anmeldungsdatum: 10.09.2004 Beiträge: 1148 Wohnort: Köln
|
Verfasst am: 02.06.2007, 12:40 Titel: |
|
|
Hallo
Ich vermute auch, dass es sich um ein Problem mit der Emulation durch Windows handelt. Unter DOS lässt sich z.B. auch der Startwert und damit das Teilerverhältnis des Zählers setzen und damit die Geschwindigkeit von TIMER einstellen. So kann man z.B. den Takt von 54ms auf 1ms heruntersetzen. Unter Windows geht das nicht. Ausserdem schlägt der mit TIMER ausgelesene Wert unter DOS immer schön beim Überlauf des Zählers um, unter Windows scheint das nichts mehr miteinander zu tun zu haben.
Das habe ich durch Ausprobieren herausgefunden, was die Hintergründe angeht, stehe ich aber noch ziemlich im Nebel. Mit dem 2. PIT habe ich auch herumprobiert, allerdings mit sehr seltsamen Ergebnissen. Die Einstellung PIT 1 und Zähler 1 ist wie gesagt die einzige, mit der bei mir PLAY und PIT-Abfrage gleichzeitig funktioniert.
Gruß
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.
|
|