Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

odczyt milisekund w przerwaniu

29 Gru 2005 11:10 2134 10
  • Poziom 16  
    Piszę program pod dosa do monitorowania transmisji szeregowej. Potrzebuję zmierzyć czas pomiędzy dwoma znakami. Chciałbym to zrobić w funkcji obsługi przerwania od portu szeregowego po odebraniu znaku. Problem w tym, że przerwanie 21h - 2c jest chyba za wolne. Czy nie można tików procesora lub milisekund odczytać gdzieś z pamięci? Jak można zrobić to inaczej? Może RTC? Może nie w przerwaniu?
    Darmowe szkolenie: Ethernet w przemyśle dziś i jutro. Zarejestruj się za darmo.
  • Pomocny post
    Poziom 21  
    Standardowo nie masz zegara o potrzebnej rozdzielczości. Ja bym zrobił tak: napisał własną obsługę przerwania timera systemowego (nie RTC) aby uzyskać licznik do pomiaru z zadana dokładnością, podłożył ją pod tę standardową, podkręcił częstotliwość przerwań (standardowo jest to ok 18 Hz) do takiej jak potrzeba. Wtedy w przerwaniach od transmisji używał bym tego licznika do wzmiankowanego pomiaru. Trzeba jeszcze pamiętać że jeżeli nie zablokujesz całego DOS'a (np. wypisywania na ekranie czy sprawdzania klawiatury, zapisy do pliku) to niektóre pomiary będą obarczone sporym błędem (część odwołań dosowych, na pewien czas, blokuje przerwania).
  • Poziom 17  
    RDTSC dostepna jest chyba od p2
    o ile sie nie myle to jej kod maszynowy:
    dw 31h, 0fh
  • Poziom 16  
    rdtsc zwraca mi często wartości ujemne, no chyba że robie coś nie tak. Mam celka 466. Tak wygląda program:

    Code:
    #include <dos.h>
    
    #include <stdio.h>
    #include <mem.h>

    typedef struct
    {
       unsigned lo;
       unsigned hi;
    }stim;

    int main(void)
    {
       volatile stim t_beg,t_end;
       volatile unsigned ul,uh,i;
       volatile unsigned long lbeg,lend,ldif;
       char buf[100];

       clrscr();
       for(i=10;i;i--)
       {
        _asm{
           db 0x0f,0x31
           mov word ptr t_beg.lo,ax
           mov word ptr t_beg.hi,dx
        }
        delay(2);
        _asm{
           db 0x0f,0x31
           mov word ptr t_end.lo,ax
           mov word ptr t_end.hi,dx
       }
        memcpy(&lbeg,&t_beg,4);
        memcpy(&lend,&t_end,4);
        ldif = lend-lbeg;
        printf("ldif= %lu\n",ldif);
      }
       return 0;
    }


    A tak wyniki:

    Code:

    ldif= 43469
    ldif= 4294923666
    ldif= 22472
    ldif= 21785
    ldif= 4294922497
    ldif= 21193
    ldif= 20973
    ldif= 4294922719
    ldif= 21218
    ldif= 21916


    przy delayu 1 ldif ~= 12000
    przy delayu 2 ldif ~= 20000
    przy delayu 3 ldif ~= 30000
    przy delayu 4 ldif ~= 40000
    przy delayu 5 ldif ~= 50000

    Zauważyłem, że pod dosem (bez znaczenia czy jest emm386 czy nie) i windą wyniki są podobne

    problem w tym że powyżej (tzn delay>5) to mam już tylko wartości ujemne

    Skłaniam się wiec teraz do propozycji bisa i od razu mam proźbę o jakieś przykłady
  • Pomocny post
    Poziom 21  
    To rdtsc jest znaczne lepsze, bo chyba u Ciebie działa (ale jest znak zapytania w których 486 Intel to wprowadził (nieudokumentowane), oficjalnie jest chyba dopiero od Pentium).

    Może robisz błąd wielkości zwracanego wyniku. RDTSC zwraca 64 bitowy wyni, dwa słowa 32 bitowe EDX:EAX, a ty wczytujesz kawałki 16 bitowe DX:AX.I to może być powodem twojego problemu. Pamiętaj że musisz operować całą 64 bitową liczbą (trzeba własną matematykę na odejmowanie napisać)

    popatrz tutaj:
    www.midnightbeach.com/jon/pubs/rdtsc.htm
  • Poziom 17  
    ups. najprostrzy sposob.
    przeciez transmisja szeregowa idzie przez przerwanie (08h?) z zegara. podmienic robic cokolwiek (zliczac interwaly) i oddac sterowanie do poprzedniej (oryginalnej) funkcji. czestotliwosc transmisji jest programowalna - wiadomo jaki mnoznik trzeba ustawic. wymnozyc mnoznik przez ilosc interwalow i po klopocie.
    rdtsc tez jest dobre ale trzeba cale edx::eax uwzglednic no i trzeba wiedziec ile taktow schodzi na ms, oraz jaki jest narzut zwiazany z obsluga tego mechanizmu. bo dla malych czasow % moze byc duzy. co widac na przykladzie 1ms.
    nie wiem czy wyniki sa prawidlowe bo licznik jest inkrementowany co takt. nie wazne ile rozkazow zostanie wykonanych. tak wiec powinien teoretycznie dac 450.000.000 /s czyli 450.000 na milisekunde (delay 1). zatem bardziej prawdopodobne jest to ze wyniki sa nieprawidlowe a to co otrzymujesz jest tylko przypadkowo zbierzne. ja bym to sprawdzil.
    pozdrawiam zycze szampanskiej zabawy w sylwestrowa noc.

    - nie programuj w swieta : bug sie rodzi :)
  • Poziom 16  
    Poprawiłem programik wg linka od bisa i działa super. Wielkie dzięki. Jeśli ktoś chce programik po poprawkach to dajcie znać. Zamieszcze go w tym wątku.
  • Poziom 16  
    Programik pod winde. Kompilowany fasmem:
    Code:

    format PE GUI 4.0
    entry start

    include 'win32a.inc'

    ID_DIALOG          = 10 
    ID_FREQ1           = 101
    ID_MSG             = 201

    section '.data' data readable writeable

      CPUSpeed dd 123
      bf    db '%6lu MHz',0 
      output rb 20

    section '.code' code readable executable

    start:

            invoke  GetModuleHandle,0
            invoke  DialogBoxParam,eax,ID_DIALOG,HWND_DESKTOP,DialogProc,0
            or      eax,eax
            jz      exit
    exit:
            invoke  ExitProcess,0

    proc DialogProc hwnddlg,msg,wparam,lparam
            push    ebx esi edi
            cmp     [msg],WM_INITDIALOG
            je      wminitdialog
            cmp     [msg],WM_COMMAND
            je      wmcommand
            cmp     [msg],WM_CLOSE
            je      wmclose
            xor     eax,eax
            jmp     finish
      wminitdialog:
            jmp     processed
    wmcommand:
            cmp     [wparam],BN_CLICKED shl 16 + IDCANCEL
            je      wmclose
            cmp     [wparam],BN_CLICKED shl 16 + IDOK
            jne     processed
    ;obsBuga ok
        invoke SleepEx, 100, 0
        rdtsc
        push edx
        push eax
        invoke SleepEx, 1000, 0
        rdtsc
        pop ecx
        sub eax, ecx
        pop ecx
        sbb edx, ecx
        mov ecx, 1000000
        div ecx
        mov [CPUSpeed], eax
      invoke  wsprintf,output,bf,[CPUSpeed] 
      invoke  SetDlgItemText,[hwnddlg],ID_FREQ1,output
      jmp processed

    wmclose:
            invoke  EndDialog,[hwnddlg],0
    processed:
            mov     eax,1
    finish:
            pop     edi esi ebx
            ret
    endp

    section '.idata' import data readable writeable

      library kernel,'KERNEL32.DLL',\
              user,'USER32.DLL'

    ;  library  user,'USER32.DLL'


      import kernel,\
             GetModuleHandle,'GetModuleHandleA',\
             ExitProcess,'ExitProcess',\
             UpdateWindow,'UpdateWindow',\
             SleepEx,'SleepEx'

      import user,\
             DialogBoxParam,'DialogBoxParamA',\
             SetDlgItemText,'SetDlgItemTextA',\
             wsprintf,'wsprintfA',\ 
             EndDialog,'EndDialog'

    section '.rsrc' resource data readable
      RT_MANIFEST = 24
     
      directory RT_DIALOG,dialogs,RT_MANIFEST,manifests
     
      resource dialogs,ID_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,demonstration
      resource manifests,1,LANG_ENGLISH+SUBLANG_DEFAULT,man
     
      dialog demonstration,'CPU Frequency meter',0,0,250,50,WS_CAPTION+WS_POPUP+WS_SYSMENU+DS_MODALFRAME
        dialogitem 'STATIC','Frequency:',-1   ,5 ,10,35,10,WS_VISIBLE
        dialogitem 'STATIC',' ',ID_FREQ1,45,10,55,10,WS_VISIBLE;+WS_BORDER
        dialogitem 'BUTTON','Find',IDOK,195,10,50,14,WS_VISIBLE+WS_TABSTOP+BS_DEFPUSHBUTTON
        dialogitem 'BUTTON','Exit',IDCANCEL,195,25,50,14,WS_VISIBLE+WS_TABSTOP+BS_PUSHBUTTON
      enddialog

      resdata man
             db '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',13,10
             db '<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">',13,10
             db '<assemblyIdentity name="x.x.x" processorArchitecture="x86" version="5.1.0.0" type="win32"/> ',13,10
             db '<description>no</description>',13,10
             db '<dependency>',13,10
             db '<dependentAssembly>',13,10
             db '<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*" />',13,10
             db '</dependentAssembly>',13,10
             db '</dependency>',13,10
             db '</assembly>',13,10
      endres

    Poniżej plik exe spakowany zipem
  • Poziom 16  
    Programik pod win98 i xp działa ok i zajmuje tylko 3kb. Pod NT i 2000 wyświetla prawidłowy wynik i po chwili mam msgboxa. Może ma ktoś pomysł jak to poprawić?