Avatar billede bjarke Nybegynder
18. september 1999 - 21:31 Der er 6 kommentarer og
1 løsning

Interrupt

/*
- Nedenstående eksempel er kopieret fra TC hjælpen og ændret. Jeg forestillede mig, at man kunne bruge interrupten til at lave et ur, som kørte oppe i hjørnet af skærmen, men den gik ikke. Hverken at lægge koden i selve interrupt-rutinen, eller kalde funktionen ur(). Kan dette ikke lade sig gøre - og hvordan?

- og hvad betyder (...)

- og findes der nogle links til materiale om interrupts?
*/

#include <stdio.h>
#include <iostream.h>
#include <dos.h>
#include <conio.h>

/* The clock tick interrupt */
#define INTR 0X1C

void ur()
    {
    int x = wherex();
    int y = wherey();

    struct  time t;

    gettime(&t);
    gotoxy(73,1);
    printf("%2d:%02d:%02d",
            t.ti_hour, t.ti_min, t.ti_sec);
    gotoxy(x,y);
    }

void interrupt ( *oldhandler)(...);

int count=0;

void interrupt handler(...)
{
    disable();

//    ur();    // Dette går ikke!!!

    count++;
    enable();
  oldhandler();
}

int main(void)
{
  oldhandler = getvect(INTR);
  setvect(INTR, handler);

  while (count<40)    cout << count << endl;

  setvect(INTR, oldhandler);
  return 0;
}
Avatar billede soepro Nybegynder
20. september 1999 - 09:01 #1
Lad os tage det sidste først: (...) betyder at der kommer et "uendeligt" antal parametre - nemlig fordi det er det aktuelle kald til rutinen der bestemmer hvormange parametre der rent faktisk er. Et godt enkesempel på rutine er printf: den tager jo alt fra 1 til (uendelig) mange parametre.

Du har fuldstændig ret i at du ikke kan kalde ur() inde i interrupt-handler rutinen. Interrupts er beregnet til at håndtere "her og nu" afbrydelser, f.eks. at der (igen) er gået 1/60 sek. Det er derfor god latin at interrupt handlere skal være så korte som muligt - og at de aldrig -gentager ALDRIG- må kalde andre dele af dit program. Hvorfor de ikke må det ??? Ja, den primære grund er jo selvfølgelig at rutinen skal kunne nå at afslutte inden den kaldes igen som følge af et nyt interrupt - men timer tick som du bruger i dit ekspempel, altså inden for 1/60 sek. Men mere vigtigt er den logik/kode den genereres når du skrive 'interrupt' foran funktionen, og skriver 'disable()' i starten/'enable()' i slutningen af rutinen. Ordet 'interrupt' for nemlig rutinens entry-kode til som det allerførste, at gemme indholdet at alle CPUens registre. Du skal jo tænke på at interruptet kan komme midt i at du laver noget andet - og maskinen skal jo holde rede på hvor den skal fortsætte. 'disable()' forhindrer i princippet at andre interrupts (herunder også timer tick selv) kommer til førend 'enable()' bliver kaldt. Hvis du derfor skal kalde videre til en anden rutine i samme program, skal den jo i princippet gøre det samme - og det er her det går galt.

Hvis du skal have din ur-funktion til at fungere, skal du derfor lave selv opdateringen af uret selv - ved at skrive direkte til skærmhukommelsen !

Jeg har et eksempel på sådan et ur - skriv igen hvis jeg skal lægge det herud.
Avatar billede bjarke Nybegynder
20. september 1999 - 12:16 #2
entry-kode == kaldet af interrupt-rutinen?

Tak, du må meget gerne lægge "uret" herud:-)
Avatar billede soepro Nybegynder
20. september 1999 - 12:46 #3
Entry-kode er den (maskin-)kode som compileren lægger ind i starten af en funktion, f.eks. til at reservere plads til og initialisere lokale variable, samt at pop'e evt. overførte parametre. Den samme kode laver hvis man bruger ordet 'interrupt' push af alle registre, herunder AX, EP, DS, SS og CS. Tilsvarende indsætter compileren det korrekte antal pop i slutningen af finktionen, sådan at alle registre har samme værdi efter kaldet, som de havde da interrupted blev "fyret" af. (Og programmet afbrudt - deraf navnet interrupt.)

Uret er her:

#include <stdlib.h>
#include <conio.h>
#include <dos.h>

/* The timer tick */
#define TIMERTICK 0X1C
struct  time curTim;
int    timX, timY;
char    curTimStr[16]; // TT:MM:SS + attributter.
void    interrupt ( *oldtimertick)(...);

/* -------------------------- HOVED PROGRAM ----------------------- */
void interrupt timertick(...)
{
  disable();

  /* Så hent nuv. tid - og smid det ud på skærmen. */
  gettime(&curTim);
  curTimStr[0]  = '0' + curTim.ti_hour / 10;
  curTimStr[2]  = '0' + curTim.ti_hour % 10;
  curTimStr[6]  = '0' + curTim.ti_min  / 10;
  curTimStr[8]  = '0' + curTim.ti_min  % 10;
  curTimStr[12] = '0' + curTim.ti_sec  / 10;
  curTimStr[14] = '0' + curTim.ti_sec  % 10;
  puttext(timX, timY, timX+8, timY, &curTimStr);
 
  oldtimertick();
  enable();
  return;
} // timertick

int main(int argc, char* argv[])
{
  /* Initier egne variable. (Forventer op til 2 params - men ingen er OK. */
  if (argc < 2 || (timX = atoi(argv[1])) < 1 || timX > 72)
    timX = 72;
  if (argc < 3 || (timY = atoi(argv[2])) < 1 || timY > 24)
    timY = 24;
  gettext(timX, timY, timX+8, timY, &curTimStr);
  curTimStr[4] = curTimStr[10] = ':';
  oldtimertick = getvect(TIMERTICK);

  /* Flyt timer tick til egen rutine - og start ny DOS skal. Hvis brugeren */
  /* skriver 'exit' afsluttes den, og dermed forsvinder også uret.        */
  setvect(TIMERTICK, timertick);

  clrscr();
  cprintf("Ur kører i position (X,Y) = (%d,%d)\r\n", timX, timY);
  cputs("Tryk på en tast for at starte DOS - ESC for at afbryde.");
  while (!kbhit());
  if (getch() != 0x1B)
    system(getenv("COMSPEC"));

  /* Sæt timer tick tilbage til gamle handler - og afslut dette program. */
  setvect(TIMERTICK, oldtimertick);
  return 0;
} // MAIN

Man SKAL køre med standard stack frame og UDEN test stack overflow, for at få programmet til at køre. (Og nogle Win95 versioner kløjs i det under alle omstændigheder.)
Avatar billede bjarke Nybegynder
20. september 1999 - 13:03 #4
Tak skal du have. Jeg må nok vente med at kigge nærmere på det til jeg kommer hjem til min compiler:-)

Jeg ved ikke hvad AX, EP osv er, ej heller hvad 'standard stack frame' og 'test stack overflow' er, men det er måske ligeså godt, at jeg selv får læst/lært lidt om de ting, fremfor at blive ved med at stille nye spørgsmål hver eneste gang jeg får et svar!

Så derfor:
Hvor/hvordan finder jeg ud af lidt mere (grundigt/grundlæggende) om interrupts?
Avatar billede bjarke Nybegynder
22. september 1999 - 14:42 #5
soepro >> nu har jeg bakset en hel del med dit lille program. Jo, det kan godt køre, men jeg skal da vist ikke prøve på andet end at trykke ESC. Hvis jeg trykker andet, eller ændrer bare en smule i programmet omkring "while(!kbhit());" så går computeren ned.

Du fatter slet ikke hvor mange gange jeg har genstartet min computer. Jeg fandt hurtigt ud af, at det kunne betale sig at starte med en startdiskette, så jeg ikke hver gang skulle vente på at windows startede.

Ud over det, så lader det til at programmet ikke er særlig glad for getch(), kan det være rigtigt?

Og som det sidste. Jeg lavede en lille løkke, som indeholdt en cscanf(). Programmet registrerede kun cirka hvert andet eller tredje tastetryk.

Det duer jo ikke rigtig at det er vældigt smart at lave et ur på den måde, hvis interrupten stort set kører hele tiden!!!
Avatar billede soepro Nybegynder
22. september 1999 - 15:42 #6
bjarke >> Som jeg skrev, så duer mit prøve program (som stammer fra dengang, jeg kun kørte DOS) ikke med alle Win95 versioner - hvorfor ved jeg ikke.

Mht. while (!kbhit()) løkken, er den jo faktisk helt unødvendig - fjern den. Mht. kaldet til system, har jeg også konstateret at der ikke går godt - men igen jeg ved ikke hvorfor.
Avatar billede bjarke Nybegynder
22. september 1999 - 15:50 #7
Nå, anyway, det virker (selv om jeg egentlig ikke kan bruge det i praksis), så du får pointene. Du fortjener også lidt point med din generelt temmelig grundige besvarelse af spørgsmål:-)

Vær's'go, 30 points!
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester