logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Jak uzyskać precyzyjne opóźnienia w GFA Basic na różnych komputerach?

Akane 08 Lip 2003 08:55 2212 9
REKLAMA
  • #1 280230
    Akane
    Poziom 27  
    Posty: 638
    Pomógł: 144
    Ocena: 33
    Hi

    Mam problem, od około dwóch miesięcy programuję w GFA Basic ( http://www.gfasoft.gfa.net/ ), który (raczej) nie posiada pożądnej fujnkji PAUSE, WAIT o rozdzielczości pascalowej, czyli rzędu milisekund. Rozkaz PAUSE 18 to jedna sekunda, jak pisze w helpie - to jest ułomność zegara systemowego

    Doświadczalnie można napisać program do odmierzania opóźnienia; i tak

    PROCEDURE wait10ms
    FOR qq = 0 TO 580
    FOR ww = 0 TO qq
    NEXT ww
    NEXT qq
    RETURN

    działa dobrze przy procesorze athlona 1700. A jak napisać, żeby to było kompatybilne z resztą komputerów? Tak, żeby nikt nie musiał sam dobierać stałej 580

    Ten sam problem jest w QuickBasic, ale mogę się mylić - z polskiej książki o QBasic wynika, iż czyste opóźnienie generowane przez bodajże PAUSE ma rozdzielczość jednej sekundy

    Przecież w mikrokomputerach klasy Atari, Commodore i Spectrum można było napisać PAUSE 0.001 i działało; więc gdzie jest kompatybilność??

    Programować lubię, a widząc że ktoś na forum potrzebuje prosty program, aż mnie skręca że nie będzie u niego działać.
  • REKLAMA
  • #2 280242
    Tdv
    Poziom 34  
    Posty: 2237
    Pomógł: 150
    Ocena: 53
    Odpowiedź jest prosta: na dzień dzisiejszy kazdy procesor działa z innym zegarem, a co się z tym wiąże cykl maszynowy ma inny czas trwania. Więc żadna pętla programowa nie może dawać takiego samego opóźnienia na każdym z nich! Musisz albo użyś pomiaru czasu z zegara komputera, albo rozbudować swoją pętelkę o rozpoznawanie proca, ale to już z lekka chaczy o syzyfową pracę bo pojawi się nowy procek na rynku i znowu będziesz w liściach...
  • #3 280260
    Akane
    Poziom 27  
    Posty: 638
    Pomógł: 144
    Ocena: 33
    Zgadza się, nawet pojedyńczy rozkaz w asemblerze ma zmienną liczbę taktów, przez przetwarzanie potokowe. Ale basic powinien być uniwersalny!

    Może da się odczytać coś interesującego z karty graficznej,czyli jakąś częstotliwość i takt, co by było już dużym krokiem naprzód. A może zegar czasu rzeczywistego dale możliwość odczytu chociaż setnych części sekundy? W literaturze pisze tylko o całych sekundach:(
  • REKLAMA
  • #4 280269
    Tdv
    Poziom 34  
    Posty: 2237
    Pomógł: 150
    Ocena: 53
    Nie pamiętam dokładnie ale specyfikacja IBM AT przewidywała przerwanie zegarowe co kilkanaście milisekund o ile się nie mylę. Nie wiem jak to wygląda dzisiaj, bo sporo rzeczy się zmieniło. Zresztą kiedyś możnabyło sobie dowolnie zaprogramować układ czasowy...
    Co do uniwersalności basica - to nie wiem skąd założenie, że ma być uniwersalny?!?
    Ja uważam, że jak coś jest do wsyztskiego to jest do niczego, więc jak coś jest za bardzo uniwersalne to zazwyczaj staje uciążliwe w użytku.
  • REKLAMA
  • #5 284432
    painkiller
    Poziom 13  
    Posty: 50
    procesory chba od 386 i lepsze mialy instrukcje rdtsc ktora zwracala w edx:eax jakis czas dosyc dokladne to jest tye ze trzeba znac opcoda i wywolywac przez callabsolute czy jakos tak niepamietam jak to bylo w qbasicu
  • #6 287423
    Akane
    Poziom 27  
    Posty: 638
    Pomógł: 144
    Ocena: 33
    Tak to jest z tymi PC, zauważyłem że dużo programów ma wirtualne potencjometry do generowania precyzyjnych opóźnień, chyba też tak zrobię, narazie dopiero poznaję zakamarki PC, LPT mam opanowany, pierwszy programator też (https://www.elektroda.pl/rtvforum/topic13677.html z niezbyt udolną regulacją opóźnienia, ale własnego PC mam od kilku miesięcy. Przedtem siedziałem na z80 i to bez netu :)
  • REKLAMA
  • #7 287452
    tzok
    VIP Zasłużony dla elektroda
    Posty: 38711
    Pomógł: 3166
    Ocena: 6471
    W BASICu masz polecenie TIMER, dzięki któremu możesz określić jak długo jest przetwarzana pętla:
    t=timer
    repeat
    until (timer-t)<=100
    to przykładowa pętla opóźniająca w OMIKRON.Basic'u (Atari ST), GFA Basic'em się nie bawiłem (też był na ST) ale powinno być podobnie. Być może trzeba w jakiś sposób inicjować timer, tego nie wiem - postudiuj helpa.
    W PC występują przerwania, które możesz wykorzystać do odmierzania czasu, np. int1Ch lub int08h/IRQ0 (18.2 1/sek).
  • #8 287453
    elektryk
    Poziom 42  
    Posty: 11029
    Pomógł: 439
    Ocena: 241
    Systemy linux do dokładnego odliczania bardzo krótkich odcinków czasu wykorzystują petle programowe i jakoś to działa (mimo iż nie jest zalecane czeste urzywanie). Cały trick polega na tym żeby wcześniej sobie policzyć ile cykli pętli potrzeba np na 1ms. Najprościej to zrobić:
    1. pętla czekająca na zmiane sekundy
    2. pętla czekające na zmiane sekundy, licząca ilość cykli w sekundzie.
    Wystarczy potem wartość cykli odpowiednio dzielić i już można odmierzać na dowolnym komputerze.
  • #9 287465
    Akane
    Poziom 27  
    Posty: 638
    Pomógł: 144
    Ocena: 33
    Dzięki Elektryk! super pomysł! zaraz coś skrobnę i kilka razy poprawię...
    czyli jak zwykle u każdego.

    A jedna (max dwie) sekunda nicnierobienia przez komputer nikogo nie zbawi (chodzi o programator)

    No to gotowe:

    DEFFN sekunda = VAL(RIGHT$ (TIME$,2))

    sec% = @sekunda

    DO
    LOOP WHILE @sekunda = sec% // czekaj aż sekunda się zmieni

    INC sec%
    IF sec% > 59 THEN sec% = 0 // zwiększ wzór sekundy

    FOR qq = 0 TO 9999999 // trochę przesadziłem...
    FOR ww = 0 TO qq
    NEXT ww
    IF @sekunda <> sec% // zwiększaj qq do końca sekundy
    GOTO exitFor
    ENDIF
    NEXT qq

    exitFor:
    // qq=ilość przebiegów pętli dla dednej sekundy
    PRINT qq
    END

    Na Athlonie 1700 wynik oscylował w okolicy 6000 (5858,6057)bez kompilacji do exe - co w delay=3ms daje błąd qq +- 0.25
  • #10 288432
    Akane
    Poziom 27  
    Posty: 638
    Pomógł: 144
    Ocena: 33
    A po kilku zamyśleniach urodził się program do pomiaru częstotliwości CPU u PC: (chociaż prawie za każdym razem podaje troszeczkę inne wartości, ale z małym błędem)

    W tym Basicu też jest zmienna TIMER, zwiększa się co 1ms, ale dopiero teraz zwróciłem uwagę na ten szczegół:

    PROCEDURE wait(ms)
    INC ms
    DO
    qq = TIMER
    DO
    LOOP UNTIL TIMER > qq
    DEC ms
    LOOP UNTIL ms = 0
    RETURN

    a wywołanie: @wait(10) to pauza 10ms z błędem max 1ms, bo procedura najpierw czeka na zmianę w TIMER żeby 'synchronicznie' liczyć następne milisekundy. Wyżucając INC ms, aby odmieżyć jakiś czas np. dla jakiegoś stanu na porcie trzeba najpierw poczekać na zmianę TIMERa, wpisać coś do portu, wywołać @wait(...) i zmienić wartość w porcie. Ale to tylko wiadomość dla nowicjuszy (@wait(0)nie działa dobrze)
    Załączniki:
    • test Fcpu.txt (569 Bajtów) Musisz być zalogowany, aby pobrać ten załącznik.
    • Test szybkosci komputera.zip (94.89 KB) Musisz być zalogowany, aby pobrać ten załącznik.

Podsumowanie tematu

✨ W dyskusji poruszono problem precyzyjnego odmierzania opóźnień w GFA Basic na różnych komputerach, gdzie standardowe polecenie PAUSE ma rozdzielczość rzędu sekund, co jest niewystarczające do dokładnych pomiarów milisekundowych. Ze względu na różne częstotliwości taktowania procesorów i zmienną liczbę cykli maszynowych, pętle programowe generujące opóźnienia działają różnie na różnych maszynach. Proponowano wykorzystanie zmiennej TIMER, która w GFA Basic zwiększa się co 1 ms, do synchronizacji i odmierzania krótkich opóźnień z błędem około 1 ms. Zaproponowano także metodę kalibracji pętli opóźniającej poprzez pomiar liczby iteracji w czasie jednej sekundy, co pozwala dostosować opóźnienie do konkretnego procesora bez ręcznego dobierania stałych. Wspomniano o instrukcji rdtsc dostępnej od procesorów 386, zwracającej dokładny licznik cykli CPU, oraz o przerwaniach systemowych (np. int1Ch, int08h/IRQ0) wykorzystywanych do odmierzania czasu. Dyskutowano również o ograniczeniach uniwersalności Basic oraz o możliwości wykorzystania zegara czasu rzeczywistego i karty graficznej do odczytu częstotliwości taktowania. Przykładowy kod w GFA Basic demonstruje implementację funkcji wait(ms) bazującej na zmiennej TIMER, umożliwiającej precyzyjne opóźnienia rzędu milisekund.
Wygenerowane przez model językowy.
REKLAMA