Interrupt

Fra Holstebro HTX Wiki
Skift til: navigering, søgning

Nogle gange har man brug for, hvad man måske kunne kalde en slags multitasking, hvor man udover den normale kode, der kører FOREVER loop også har noget kode der skal afvikles på bestemte tidspunkter. Det kan man gøre med interrupt.

Hvad sker der ved interrupt

Interrupt betyder at afbryde, og det der netop sker er, at den kode der afvikles bliver afbrudt af en hændelse (tid, skift på et ben, AD færdig eller hvad det kan være).

Når koden afbrydes, så sker det ved at der kaldes en speciel adresse / rutine.

Hvis man arbejder med interrupt i assembler, så sker der det, at man kalder adresse 4 i PIC'en (kaldet en interrupt-vector), hvorefter man som programmør fuldt ud har ansvaret for hvad der så skal ske (typisk skal man gemme CPU-status og W-registeret), så skal man udføre noget og til slut reetablere det man har gemt, og returnere fra interruptet.

Hvis man arbejder i JAL, så er det noget enklere, da man blot skriver en interrupt-rutine, hvor man først tjekker på om det er den givne hændelse der har interruptet, og hvis det er, så udfører man det man ønsker.

Man kan godt have flere interrupt-rutiner i JAL. Det eneste man skal være klar over er, at man ikke kvæler processoren i for mange interrupts, samt at man skal huske at afstille det der interruptede.

Eksempel på anvendelse af interrupt

Dette eksempel gennemgår hvordan man kan lave et timer-interrupt, der sker hvert 4. millisekund, så man ud fra dette kan lave et ur der tæller sekunder, minutter og timer.

Det centrale i interruptet er interrupt-rutinen der kan skrives som følger:

 procedure interrupt_handler is pragma interrupt
    if intcon_tmr0if then
       TMR0 = timer_value  -- Sæt timeren til den afpassede værdi
       tim_int 
       -- Slet TOIF for at re-enable timer interrupt
       intcon_tmr0if = False
    end if
 end procedure

Navnet på proceduren betyder ikke noget, men det er vigtigt at der står pragma interrupt, da det er disse keywords der angiver at det er en rutine der skal kaldes, når der sker et interrupt.

Der undersøges så på det bit der hedder TMR0IF, som ligger i INTCON. Det er TiMeR 0 Interrupt Flag, altså et bit der sættes, når det er timer 0 der har udløst interruptet.

Hvis det er Timer 0, så starter man med at skrive en ny værdi i TMR0, så den kan tælle videre derfra (beskrives senere).

Så kaldes den procedure tim_int, der håndterer selv tids-registreringen, også mere om dette senere.

Når vi har serviceret dette, så er det vigtigt at TMR0IF bliver afstillet igen, ellers vil der komme et nyt interrupt fra samme kilde igen, lige efter vi har returneret fra proceduren.

For at der overhovedet kan komme et interrupt fra timeren, så skal interruptet slåes til. Det gøres som følger:

 -- Initialiser interruptet
 intcon_tmr0ie = True     -- Sæt timerinterrupt aktivt
 intcon_inte = False      -- Passiver Port B ben 0 interrupt
 intcon_rabie = False     -- Passiver Port B ben 4-7 kanttrigget interrupt
 intcon_gie = True        -- Enable interrupt generelt
 --

Her er det TMR0IE der bliver sat i INTCON. Det betyder at TiMeR 0 Interrupt Enable sættes, altså at dette interrupt nu er aktivt. Bare for en sikkerheds skyld afstilles de andre interrupts.

Den anden ting der skal stilles for at der kan komme interrupt er at det generelle interrupt slås til ved at sætte GIE (General Interrupt Enable) i INTCON.

Specielt for Timerinterrupt

Nu er det sikret at interruptet kan komme, og at det bliver serviceret - tilbage i indstillingerne er at bestemme hvor tit det skal komme. Her skal vi have fat i OPTION_REG og TMR0. Koden ser ud som følger:

 -- Starten af initialiseringskoden
 -- Bit 7 til 1 : Port B pull up disabled
 -- Bit 6 til 0 : Port B-0 interrupt på faldende kant
 -- Bit 5 til 0 : Clock til TMR0 fra den interne clock (4MHz / 4)
 -- Bit 4 til 0 : Kant for clock til TMR0 (ikke relevant)
 -- Bit 3 til 0 : Timer rate til TMR0 (hvis den er 1 er det WDT)
 -- Bit 2-0 Timer rate
 --   000       2
 --   001       4
 --   010       8
 --   011      16
 --   100      32
 --   101      64
 --   110     128
 --   111     256
 OPTION_REG = 0b_1000_0011    -- Se ovenstående eller datablad for nærmere detaljer
 TMR0 = timer_value

Bit 7 og 6 har ikke noget med Timer 0 at gøre, men ligger i dette register, så de er også nævnt her.

Bit 5 angiver at takten der skal tælles med stammer fra den takt der angiver processorens hastighed - hvis man anvender en anden clock-frekvens skal man naturligvis til at ændre sine beregninger for clocken. I beregningen skal man tage højde for at der deles med 4 i forhold til den oprindelige clock-frekvens, så når vi bruger 4 MHz er den frekvens vi starter med her altså 1 MHz.

Bit 4 er ikke relevant i denne sammenhæng, det er kun hvis man bruger et eksternt ben til at give clock-signaler, så kan det betyde noget om det er på forkant eller på bagkant det sker.

Bit 3 angiver at den timer-hastigehed vi angiver faktisk også kommer ind i Timer 0.

Bit 0-2 angiver med 3 bit hvilken delingsfaktor der skal på interruptet. Her har jeg valgt 011, altså at den 1 MHz vi starter med deles med 16. Det angiver hvert tællerskridt.

Det er altså denne værdi der skrives i OPTION_REG Her angivet som en binær værdi for nemheds skyld).

Den værdi der skrives i TMR0 er 6. Grunden til dette er at vi gerne vil have interrupt for hver 4. millisekund. Det får vi ved at TMR0 er et Byte register, og da timer 0 tæller opad, så vil det komme til at tælle 250 gange (256 - 6) inden der sker overflow, og altså interrupt. Da vi starter med 1 MHz svarer tiden til 1 mikrosekund, og hvert tælleskridt er altså 16 mikrosekunder, og når vi har 250 af dem, så får vi 250 * 16 = 4000 mikrosekunder, altså 4 millisekunder mellem hvert interrupt, under forudsætning af at vi stiller TMR0 til 6 hver gang der sker et interrupt, men det gør vi jo også i interrupt-proceduren.

Dette var forklaringen på alle værdierne, men for at gøre det lidt lettere, så kan man få omregnet sine ønsker til koden ved at gå ind på en pic timer calculator for at få sine værdier, og rent faktisk også får koden (godt nok i C), men det er et godt skridt i den rigtige retning.

Endelig så er der tilbage at forklare hvordan vi kan få sekunder, minutter og timer til at fungere. Det sker i proceduren tim_int, der ser ud som følger:

 -- Procedure der i interruptet håndterer optællingen af tid til et ur.
 procedure tim_int is
    ms_4 = ms_4 + 1
    if (ms_4 == 250) then
       ms_4 = 0
       sekund = sekund + 1
       if (sekund == 60) then
          sekund = 0
          minut = minut + 1
          if (minut == 60) then
             minut = 0
             time = time + 1
             if (time == 24) then
                time = 0
             end if
          end if
       end if
    end if   
 end procedure

Variablen ms4 tæller fra 0 til 250, og hver gang den nulstilles er der gået 1000 millisekunder, altså et sekund, og det betyder at sekund-variablen tælles en op.

Når sekundvariablen når 60 så nulstilles den, og minutvariablen tælles en op. Tilsvarende gøres med minutvariablen, så der tælles timer op, og timerne nulstilles så ved 24.

Hvis man ønskede at bygge dato på, så skulle der bygges videre på denne procedure til at håndtere dag, måned og år, hvis man ville det.

Den samlede kode, der er implementeret med display-visning ved hjælp af ALCD-modulet ligger i en zip-fil her.

Andre interruptkilder

Som standard har de PIC-kredse vi bruger følgende interrupts:

Timer0 som vist i eksemplet før.

Eksternt interrupt fra et ben (kan indstilles til forkant og bagkant)

Interrupt, når EEPROM brænding er færdig.

Interrupt på niveauskift på et antal ben - hvilke ben det er kan ses i tabellen herunder.

Ud over det, så kan de PIC-kredse vi arbejder med andre ting med interruptet - man er selvfølgelig nødt til at gå i databladet for den enkelte processor for at se hvordan det virker, så dette er bare en oversigt over hvilke muligheder der er.

PIC16F84 PIC16F628 PIC12F675 PIC16F684 PIC16F690 PIC16F877
AD Nej Nej Ja Ja Ja Ja
Comperator Nej Nej Ja 2 stk 2 stk Nej
EEPROM Ja Ja Ja Ja Ja Ja
INT - eksternt ben Ja Ja Ja Ja Ja Ja
Niveau skift Port B4-7 Port B4-7 Port A0-5 Port A0-5 Port A0-5 og Port B4-7 Port B4-7
Timer 0 (8 bit) Ja Ja Ja Ja Ja Ja
Timer 1 (16 bit) Nej Ja Ja Ja Ja Ja
Timer 2 (8 bit) Nej Ja Nej Ja Ja Ja
USART (seriel) Nej Ja Nej Nej Ja Ja
Capture Compare Nej Ja Nej Ja Ja 2 stk
Oscillator Fail Nej Nej Nej Ja Ja Nej
Synkron seriel Nej Nej Nej Nej Ja Ja
Parallel slave port - - - - - Ja
Bus Collision - - - - - Ja

Demo-eksempler på interrupt

Demo-eksemplerne er ikke lavet til at udføre noget praktisk, men udelukkende tænkt til at demonstrere hvordan interruptet initialiseres (indstilles og sættes i gang) og lige så meget kode i interruptet til at man kan se at det fungerer - det er simple funktioner der udføres som at vippe med en udgang, så man kan måle / se reaktionen.

Koderne kan hentes i denne ZIP-fil.

For at interruptet kan fungere skal det slås til. Det er dels de enkelte interrupts, men også det globale interrupt GIE der skal slås til.

Ud over dette har hovedkoden blot et tomt forever loop.

INTCON_GIE = true     -- Enable alle interrupt

forever loop
   -- I denne kode sker der intet,
   -- men der kunne også udføres kode der ikke er så tidskritisk
end loop

Interrupt koden er skrevet ud i hvert sit modul, der i princippet kan fungere individuelt. Hvert modul har sin egen interrupt-rutine, men JAL sørger for at alle interrupt-rutiner bliver serviceret.

include timer1
include timer2
include int

Timer 0 interrupt

Dette interrupt er sat op til at vippe med pin_a4 for hver 64,000 ms ved en clockfrekvens på 4 MHz.

De 64 ms er beregnet ud fra prescaleren og den værdi TMR0 reloades med samt den clock-frekvens PIC'en arbejder med delt med 4.

Ved 4 MHz får timeren en frekvens på 1 MHz, så er det så simpelt at produktet af prescaleren og den tid man reloader TMR0 med er det antal mikrosekunder man ønsker.

Tid = PS * Timercount = 256 * 250 = 64000 mikrosekunder

Det timercount man får opnår man ved at reloade tælleren med en værdi, således at den kommer til at tælle 250 gange inden den løber over, så reload-værdien er 256 minus det ønskede timercount.

Reload TMR0 = 256 - 250 = 6

Koden ser ud som følger:

-- Demo til Timer 0 Interrupt

pin_a4_direction = output

INTCON_TMR0IE = true    -- Aktiver Timer 0 interrupt
INTCON_TMR0IF = false   -- Afstil interruptet
OPTION_REG_T0CS = false    -- Timer 0 source fra Fosc/4
OPTION_REG_T0SE = false    -- Rising edge for T0 clock
OPTION_REG_PSA = false    -- Prescaler til Timer 0
OPTION_REG_PS = 0b_111    -- Prescaler til 256

-- Interruptrutine - kaldes automatisk
procedure timer_0_int is pragma interrupt
   if INTCON_TMR0IF then    -- Reager på Timer 0 interrupt
      TMR0 = 6
      INTCON_TMR0IF = false
      pin_a4 = ! pin_a4
   end if
end procedure

Det giver et output på pin_a4 som følger:

Int-timer0.png
Output fra demo-program på timer0-interrupt

Timer 1 interrupt

Dette interrupt er sat op til at vippe med pin_c5 for hvert halve sekund.

-- Demo til Timer 0 Interrupt

pin_C5_direction = output

PIE1_TMR1IE = true    -- Enable interrupt
PIR1_TMR1IF = false
INTCON_PEIE = true    -- Aktiver ekstra interrupt (bl.a. timer 1)
T1CON_TMR1CS = false    -- Timer 0 source fra Fosc/4
T1CON_TMR1ON = true    -- Rising edge for T0 clock
T1CON_T1OSCEN = true    -- Prescaler til Timer 0
T1CON_T1CKPS = 0b_11    -- Prescaler til 8

-- Interruptrutine - kaldes automatisk
procedure timer_1_int is pragma interrupt
   if PIR1_TMR1IF then    -- Reager på Timer 0 interrupt
      TMR1 = 65535 - 62500
      PIR1_TMR1IF = false
      pin_C5 = ! pin_C5
   end if
end procedure

Det giver et output på pin_c5 som følger:

Int-timer1.png
Output fra demo-program på timer1-interrupt

Timer 2 interrupt

Dette interrupt er sat op til at vippe med pin_a0 med forskelligt interval, startende med 1,8 ms og op til 65 ms.

-- Demo til Timer 2 Interrupt

pin_a0_direction = output

-- Indstil timer 2 til at bestemme pulslængde
-- Her er demonstreret hvordan man kan få samme tider med forskellige oscillatorer
if target_clock == 4_000_000 then
T2CON_TOUTPS = 0b_0010   -- Postscaler til / 3
elsif target_clock == 8_000_000 then
T2CON_TOUTPS = 0b_0101   -- Postscaler til / 6
elsif target_clock == 20_000_000 then
T2CON_TOUTPS = 0b_1110   -- Postscaler til / 15
else
pragma error "Oscillatorfrekvens ikke defimeret"
end if

-- Her sættes tiden til langsomst muligt
T2CON_TOUTPS = 0b_1111   -- Postscaler til / 16

T2CON_TMR2ON = true   -- Tænd timer 2
T2CON_T2CKPS = 0b_10  -- Prescale 16
PIE1_TMR2IE = true    -- Enable interrupt
INTCON_PEIE = true    -- Aktiver ekstra interrupt (bl.a. timer 2)

-- Interruptrutine - kaldes automatisk
procedure timer_2_int is pragma interrupt
   if PIR1_TMR2IF then    -- Reager på Timer 2 interrupt
      PIR1_TMR2IF = false
      PR2 = PR2 + 1       -- Lav en skiftende tid på interruptet
      if PR2 == 0 then
         PR2 = 5
      end if
      pin_a0 = ! pin_a0
   end if
end procedure

Det giver et output på pin_a0 som følger:

Int-timer2-1.png
Output fra demo-program på timer2-interrupt

Set i en anden timebase ser det ud som følger:

Int-timer2-2.png
Output fra demo-program på timer2-interrupt timebase 10 ms

Kanttrigget RA2 interrupt

Dette er et af de oprindelige interrupts fra de tidlige PIC-kredse, hvor man kan indstille om det er positivt gående eller negativt gående der skal interruptes på, men man kan ikke ændre på hvilket ben det er forbundet til. På PIC12F675, PIC16F684 og PIC16F690 er interruptet placeret på pin_a2, på PIC16F84, PIC16F628 og PIC16F877 er interruptet placeret på pin_b0.

I dette eksempel er interruptet er sat op til at vippe med pin_a1 når der kommer en forkant på pin_a2.

-- Demo til kanttrigget Interrupt

pin_a2_direction = input
pin_a1_direction = output

INTCON_INTE = true    -- Aktiver eksternt interrupt på RA2
INTCON_INTF = false   -- Afstil interruptet
OPTION_REG_INTEDG = true    -- Rising edge of int

-- Interruptrutine - kaldes automatisk
procedure int_interrupt is pragma interrupt
   if INTCON_INTF then    -- Reager på pin A2 kant interrupt
      INTCON_INTF = false
      pin_a1 = ! pin_a1
   end if
end procedure

For at illustrere at der sker et skift på alle forkanter af pin_a2, så sættes pin_a2 til pin_a0, der er timer 2, som giver en varierende puls, som så bliver halveret over til pin_a1.

Det giver et output hvor pin_a0 ar den blå kurve, og pin_a1 er den røde kurve som følger:

Int-kant.png
Output fra demo-program på kant trigget interrupt på RA2

Niveau-skift interrupt

Dette interrupt er sat op til at vippe med pin_c6 når der kommer en forkant på pin_b4.

-- Demo til Ports A B Change Interrupt

pin_c6_direction = output
pin_b4_direction = input

INTCON_RABIE = true    -- Aktiver Timer 0 interrupt
INTCON_RABIF = false   -- Afstil interruptet
-- Mulige input er RA0 til RA5 - vær opmærksom på at oscillator og reset kan blokere:
-- RA4 og RA5 virker ikke, når der bruges ekstern oscillator
-- RA3 virker ikke ved ekstern reset
-- Andre mulige input er RA4 til RA7 - her kan også ligge andre funktioner
IOCB_IOCB4 = true     -- Enable interrupt fra pin_a3

-- Interruptrutine - kaldes automatisk
procedure porta_int is pragma interrupt
   if INTCON_RABIF then    -- Reager på Port A Change interrupt
      if pin_b4 then -- reager kun på et skift til høj
         pin_c6 = ! pin_c6
      end if
      INTCON_RABIF = false
   end if
end procedure

For at demonstrere dette interrupt hvor der sker et skift på alle forkanter af pin_b4, så sættes pin_a2 til pin_a0, der er timer 2, som giver en varierende puls, som så bliver halveret over til pin_a1. Denne forbindes videre til pin_b4, som så giver yderligere en halvering ud til pin_c6. På denne måde deles frekvensen med 4 - og puls-pause-tiderne ganges med 4 som det kan ses på følgende optagelse:

Int-change.png
Output fra demo-program på chamge interrupt på pin_c6

Serielt modtage interrupt

Dette interrupt er til den serielle port i asynkront mode. Der skal indstilles hvordan den serielle port skal kommunikere med hastighed og antal bit. Når der ikke kommunikeres er den serielle linje høj. En asynkron seriel karakter består af en lav startbit og 8 databit samt en høj startbit som vist her:

Int-seriel.png
Asynkron seriel karakter med en lav startbit, 8 databit og en høj stopbit

For at kunne kommunikere via interruptet skal man først have indstillet baudrate. Det gør man her ved at inkludere baudrate. Derefter slås de forskellige ting til for at kunne modtage asynkront og interrupte.

include baudrate

pin_b5_direction = input   -- RX/DT pin input (modtagerben)
pin_b7_direction = output  -- TX/CK pin output (senderben)

PIE1_RCIE = true      -- Aktiver serielt receive interrupt
PIR1_RCIF = false     -- Afstil interruptet
INTCON_PEIE = true    -- Aktiver ekstra interrupt (bl.a. seriel modtagelse)
RCSTA_SPEN = true     -- Enable den serielle port
TXSTA_SYNC = false    -- Sæt den serielle port til Asynkron mode
RCSTA_CREN = true     -- Enable modtagelse

TXSTA_TXEN = true     -- Enable sending på den serielle port til echoet
var byte tx_antal = 0 -- Tæller der bruges til sending
var byte rc_byte      -- Den modtagne byte

Når dette er indstillet vil man kunne modtage en byte serielt på RX-benet. Modtagelsen af en byte som den viste udløser dette interrupt.

-- Interruptrutine - kaldes automatisk
procedure serial_rc_interrupt is pragma interrupt
   if PIR1_RCIF then    -- Reager på serielt modtage interrupt
      PIR1_RCIF = false
      if RCSTA_FERR then
         RCSTA_SPEN = false
         RCSTA_SPEN = true
      elsif RCSTA_FERR then
         RCSTA_SPEN = false
         RCSTA_SPEN = true
      else
         rc_byte = RCREG   -- Hent den modtagne byte
         tx_antal = 0
         TXREG = rc_byte   -- Send den igen som echo (vil starte TX-interrupt)
      end if
   end if
end procedure

I interruptet sendes den modtagne byte tilbage på TX-benet. Dette kaldes at lave Echo.

Når man gør det i jaledits serielle terminal ser det ud som følger:

Int-receive.png
Visning af hvordan serielt modtage-interrupt reagerer ved at give et echo til terminalen

Serielt sende interrupt

Som med modtage-interruptet kan man på den serielle port sende en byte i asynkront mode. Indstillinger med hastighed og bits gælder også for senderen. Sendingen sker ved at der skrives en karakter til senderegisteret TXREG. Dette interrupt kommer når registeret er klar til at modtage en ny karakter, så man på denne måde kan få sendt karakterer hurtigt efter hinanden.

Der skal igen laves en række indstillinger for at få sende-interruptet til at fungere:

pin_b5_direction = input   -- RX/DT pin input (modtagerben)
pin_b7_direction = output  -- TX/CK pin output (senderben)

PIE1_TXIE = true      -- Aktiver serielt receive interrupt
INTCON_PEIE = true    -- Aktiver ekstra interrupt (bl.a. seriel modtagelse)
RCSTA_SPEN = true     -- Enable den serielle port
TXSTA_SYNC = false    -- Sæt den serielle port til Asynkron mode

TXSTA_TXEN = true     -- Enable sending på den serielle port til echoet
PIR1_TXIF = false     -- Afstil interruptet

I dette eksempel arbejder sende-interruptet sammen med det modtage-interruptet der er beskrevet ovenfor. Når der modtages en karakter, så sendes den tilbage som et echo. Når TXREG er klar til en ny karakter kommer der et TX-interrupt, hvor man så kan fortsætte med at sende, og her sendes den samme karakter så 4 gange mere, og der sendes CR og LF som giver en ny linje i terminalvinduet. Dette er implementeret som følger:

-- Interruptrutine - kaldes automatisk
procedure serial_TX_interrupt is pragma interrupt
   if PIR1_TXIF then       -- Reager på serielt sende interrupt
      PIR1_TXIF = false
      if tx_antal < 6 then
         if tx_antal < 4 then
            TXREG = rc_byte   -- Send den sidst den modtagne byte
         else
            if tx_antal < 5 then
               TXREG = 0x0D      -- Send CR
            else
               TXREG = 0x0A      -- Send LF
            end if
         end if
         tx_antal = tx_antal + 1
      end if
   end if
end procedure

Int-transmit.png
Terminal-vinduet der viser at hver karakter returneres 5 gange efterfulgt af et linjeskift

Synkron seriel port interrupt

PIC'en kan også arbejde med synkron kommunikation - ikke testet.


AD konvertering interrupt

Når man anvender AD-konvertering, så sætter man AD-konverteren i gang, og alt efter indstillingerne, så går der noget tid inden man kan aflæse det konverterede. I ADC holst biblioteket venter man blot indtil konverteringen er færdig.

Dette interrupt kan indstilles til at ske når konverteringen er færdig, så man kan få PIC'en til at lave andre ting mens konverteringen sker.

Her illustreres den opsætning der skal laves for at indstille AD-konverteringen til at fungere på pin_c2 der har tilknyttet analog kanal 6:

pin_c2_direction = input   -- Analog kanal 6 input
jansel_ans6 = true         -- Sæt kanal 6 som AD
adcon1_adcs = 0b_110       -- 16 us clock ved 4 MHz (176 us konvertering)
adcon0_vcfg = false        -- Vref til Vdd
adcon0_adfm = false        -- Venstre-justeret output
adcon0_chs = 0b_0110       -- Konverter kanal 6
adcon0_adon = true         -- Slå AD'en til

Herefter ses det der skal til for at AD-konverteren interrupter:

PIR1_ADIF = false     -- Afstil interruptet
PIE1_ADIE = true      -- Aktiver AD interrupt
INTCON_PEIE = true    -- Aktiver ekstra interrupt (bl.a. seriel modtagelse)

For at teste sættes pin_c3 som output og der defineres en variabel til AD-konverterings resultatet. Som det sidste startes AD-konverteringen for at sætte gang i festen.

pin_c3_direction = output  -- til test
var byte ad_byte      -- Den modtagne byte
adcon0_go = true      -- Start konverteringen

Selve interruptet aflæser AD-resultatet og vipper med pin_c3 til testen, og den næste konvertering sættes i gang.

-- Interruptrutine - kaldes automatisk
procedure serial_ad_interrupt is pragma interrupt
   if PIR1_ADIF then       -- Reager på AD interrupt
      PIR1_ADIF = false
      ad_byte = ADRESH     -- Hent den konverterede byte
      pin_c3 = ! pin_c3    -- Lav en indikation i hardwaren
      adcon0_go = true     -- Sæt en ny konvertering i gang
   end if
end procedure

Som det kan ses her løber den rundt på 210 us. Grunden til at tiden er længere end 176 us er at interruptet skal reagere og der udføres lidt kode inde i interruptet inden den næste konvertering startes.

Int-ad.png
Illustration der viser at AD-interrupt sker med 210 us mellemrum

Compare/Capture Timer 1 interrupt

Dette interrupt har mange forskellige indstillinger til timer 1 sammen med CCPR1 der er et sammenlignings-register, som kan udløse interrupt når registeret og timer 1 har samme værdi. Indstillingsmulighederne ligger på hvad der skal ske med timer 1 når der er lighed, og hvordan interruptet skal dannes (deling med 1, 4 eller 16).


EEPROM write operation interrupt

En skrivning til EEPROM tager en vis tid. Dette interrupt anvendes til at registrere hvornår skrivningen er færdig, så man kan skrive næste byte.


Comperator C1 interrupt

Den analoge comperator C1 kan indstilles til sammenligning med en spænding enten eksternt eller internt. Ved enten positivt eller negativt skift kan det indstilles til at give et interrupt.


Comperator C2 interrupt

Den analoge comperator C2 kan indstilles til sammenligning med en spænding enten eksternt eller internt. Ved enten positivt eller negativt skift kan det indstilles til at give et interrupt.


Oscillator fejl interrupt

Der kan internt i PIC'en registreres om oscillatoren har fungeret korrekt (givet konstant frekvens). Hvis der har været en fejl kan der udløses et interrupt, men selvfølgelig først efter oscillatoren er kommet i gang igen, da det kræver oscillator at gennemføre kode, altså også et interrupt.