Interrupt-problem (PIC18LF2320) *Löst* *Fungerar*

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Interrupt-problem (PIC18LF2320) *Löst* *Fungerar*

Inlägg av JimmyAndersson »

Jag har kollat datablad, google, forum mm, men inte lyckats lösa ett problem:

För att lära mig interrupt så har jag gjort ett MikroBasic-program som gör detta:
*Knapp "RUN" ska köra igång en loop som tonar en lysdiod (kopplad till en DAC och styrd med SPI) upp och ner, om och om igen.
*Knapp "STOP", tja den släcker lysdioden och så händer inget mer förrän man trycker "RUN".

Knapparna läses av med ADC. Interruptet ska köra igång kollen av vilken knapp som trycktes ner. Det lämpligaste interruptet jag har hittat är ADIF (bit 6 i PIR1.) Den interrupt-flaggan sätts när en A/D-omvandling är klar.
*Här kommer frågetecken nr 1: Den omvandlingen görs väl bara när jag läser av ADC? Men med vad ska jag starta ADC? Hade tänkt att interruptet skulle starta detta.

Jag är helt "lost" här...
Jag vet att en interrupt ska vara så kort och snabb som möjligt, utan massa delay och sådant. Åtminstone i MikroBasic är det så att man inte ska starta en procedur i en interrupt-rutin. Därför är det bättre att bara sätta flaggor/variablar som man sedan läser av i en annan procedur.
*Här kommer frågetecken nr2: För att läsa av dessa flaggor behöver jag då en loop (i 'main' eller en annan procedur t.ex DAC-uppdateringen) som ständigt kollar om variablerna har ändrats. Kan man inte då lika gärna läsa av ADC'n i denna loop?

Jag hänger inte med alls.


Kortfattat så är programbeskrivningen denna:

1. Ingenting händer förrän man trycker RUN-knappen.
2. När RUN har tryckts så ska lysdioden tona upp/ner om och om igen.
3. Trycker man STOP så ska lysdioden släckas och förbli släckt tills man trycker RUN.

Detta test är en nedbantad version av ett större projekt. Det är därför som jag vill använda interrupt. Jag är alltså inte ute efter något annat än att lära mig hur jag ska lägga upp procedurerna och interrupt-kollen på ett bra sätt.

Det "större" projektet skrev jag om här.

Heeelp! :)


edit: Rubriken...
Senast redigerad av JimmyAndersson 13 december 2005, 15:06:50, redigerad totalt 2 gånger.
Användarvisningsbild
EagleSpirit
Inlägg: 1288
Blev medlem: 27 maj 2003, 23:15:48
Ort: Västerås
Kontakt:

Inlägg av EagleSpirit »

Kollade lite i databladet för PIC och jag tror det är en komparator du ska konfigurera att skapa ett interrupt. Det verkar som att den mäter och jämför i princip hela tiden och sen så jämför den antingen med en annan ingång eller ett internt satt värde. Kolla i databladet på s223 (225 i pdfen). Där finns en figur vad komparatorn kan göra om den använder interrupt. Kanske kan vara något?

Anledningen till att du ska använda interrupt är att du kan göra annat och sen när något viktigt händer så avbryts orginalprogrammet som i den tidpunkten inte är viktigt och utför det där nya som har hänt, t.ex. en knapptryckning. När den gjort det som står i interruptet så återgår µCn dit den var när interruptet skapades.

Det du säger att man kan kolla av flaggor funkar endast som man har relativt låg prioritet på interrupten. De som har hög prioritet måste ske på en gång. I ditt fall tycker jag egentligen att det är låg prioritet men det är lättast att börja med hög prioritet. Då lägger du in kommandona som ska utföras när en viss knapp har tryckts i interrupt-rutinen så att de sker på en gång och sen går tillbaka till orginalprogrammet.

Hmm, kanske svårt att förstå men fråga igen om det är något som är konstigt.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Den interrupt-flaggan (ADIF) sätts när en A/D-omvandling är klar.

Korrekt !

> Den omvandlingen görs väl bara när jag läser av ADC?

Det är lite oklart vad du menar med "läser av". Omvandligen sker först
(du startar den själv enligt beskrivningen i databladet), och när den är
klar sätts ADIF och du kan läsa av de två register som innehåller resultatet.

> Men med vad ska jag starta ADC?

Det finns en punktlista med 7 punkter kallad "The following steps
should be followed to do an A/D conversion" i databladet.
Har du kollat ?

> Hade tänkt att interruptet skulle starta detta.

Precis tvärt om! När ADC'n är klar, triggar den ett interrupt (d.v.s sätter ADIF, om det även sker ett interrupt beror på en del annat...).

> Därför är det bättre att bara sätta flaggor/variablar som man sedan läser av i en annan procedur.

Det är generellt sätt en bra programarkitektur, ja. Inte bara för MikroBasic....

> För att läsa av dessa flaggor behöver jag då en loop (i 'main' eller en annan procedur t.ex DAC-uppdateringen) som ständigt kollar om variablerna har ändrats. Kan man inte då lika gärna läsa av ADC'n i denna loop?

Tja, det är upp till dig. Men de flesta "riktiga" program gär även en massa annat, och då är det bättre att låta ADCn köra i bakgrunden och ge ett interrupt när den är klar.

Jag skulle lägga avläsningn av ADC registren och avkodningen av knapparna i ISR'en. Sedan låta ISR'en avsluta med att sätta en flagga som talar om driftläget (RUN/STOP). Sedan kan main-loopen bara kolla denna flagga och göra vad som behövs.

> Detta test är en nedbantad version av ett större projekt.

OK. Desstå viktigare då att ha en arkitektur på applikationen från början som inte blir en återvändsgränd halvvägs in i projektet. Ditt upplägg ser OK ut, tycker jag.

> Jag är alltså inte ute efter något annat än att lära mig hur jag ska lägga upp procedurerna och interrupt-kollen på ett bra sätt.

Visst, i generella termer, men du får ingen Basic kod från mig i alla fall... :-)
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

>men du får ingen Basic kod från mig i alla fall...

:lol: Det går bra ändå. Lite jobb måste jag göra själv. :)


Tack för svaren!! Ska läsa igenom era inlägg igen och labba så jag lär mig. Interrupt (och timers) avskräcker nog de flesta ibörjan, men jag kände att det var dags att "ta tjuren vid hornen". :)


edit: Polletten trillade ner ganska fort. Koden blir betydligt smidigare med interrupts!
(Är inte riktigt klar ännu, jag får felmeddelandet "0:0 0 Linker error: adclib_a_d_adc_read_param_channel: argument not found" när jag har "knapp_nr = Adc_Read(0)" i interrupt-proceduren.) Ska se vad det beror på. "Adc_Read" är förresten en modul i MikroBasic för att läsa av A/D'n. Ska prova läsa av A/D'n utan att använda den modulen.
Användarvisningsbild
EagleSpirit
Inlägg: 1288
Blev medlem: 27 maj 2003, 23:15:48
Ort: Västerås
Kontakt:

Inlägg av EagleSpirit »

Jag måste fråga, när skulle man ha nytta av AD interruptet? Hur lång tid tar avläsningen? PICen kan ju inte hinna utföra många instruktioner från det att man startat avläsningen tills den är klar. Är det något jag har missat?

JimmyAndersson: Vad betyder 0:an? Felet kanske beror på att det behövs nå mer i "Adc_read"-kommandot?
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

EagleSpirit: 0:an betyder att det är AN0-pinnen jag läser av. Det hade blivit "ADC_Read(1)" om jag läst av AN1. Kommandot fungerade när jag körde den i en annan procedur eller main. Det är bara i interrupt-proceduren den inte fungerar. Läste att man inte kan anropa procedurer i interrupt-delen. Multiplikation och division fungerar tydligen inte heller i en interrupt-procedur (enligt MikroElektronika's forum). Kanske är det samma sak med moduler som t.ex ADC_Read.

Jag är lite inne på att köra med komparator som du föreslog tidigare. Tänkte bara få själva interrupt-delen att fungera först.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Hur lång tid tar avläsningen?

*Avläsningen* går fort, det är bara två register som skal läsas, och det görs
*efter* interruptet hur som helst.

*Konverteringen* däremot tar en viss tid, och under den tiden är det lite onödigt att bara sitta syslolös och vänta. Det är inte några jättelånga tider,
kanske 50 us, men det motsvarar ju å andra sidan 500 instruktioner vid 40 Mhz...

Adc_Read väntar på resultatet och använder inte interrupt. För det får
man nog "köra" registren direkt. Nollan i anropet är ADC kanalen, för övrigt.

Adc_Read inte bara *läser* från ADC modulen, den kör en hel konvertering, vilket ju inte är det som du vill. I ISR'en skall bara resultatatet läsas från de två ADC registren. Tyvärr verkar MikroBasic sakna separata funktioner för att starta en ADC konvertering och för att läsa resultatet. Snopet...

Som du märker, Jimmy, så blir det så att ju mer man vill använda processorn
fullt ut, ju mer blir Basic'en ett "assembler-skal" eftersom många av de
inbyggda funktionena inte ger tillgång till alla sätt att köra processorn.
Man har ju fortfarande tillgång till flödeskontroll m.m, men det blir i alla fall mindre och mindre "ren" Basic kvar.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

>det blir i alla fall mindre och mindre "ren" Basic kvar.

Precis! De som inte bestämt sig för vilket programmeringspråk de ska välja borde läsa dessa inlägg.

-Anar att jag kommer konvertera till "assemblerismen" förr eller senare... :)


När vi ändå är inne på det: Hur stor skillnad är det på Basic och C i dessa fall? Skulle man tjäna något på att välja C istället för Basic, eller är det bättre att i såfall välja assembler med en gång? (Frågar mest av nyfikenhet, eftersom jag ändå tänker ta steget direkt till asm sedan.)
Jag har programmerat en del i C, så jag vet hur koden är uppbyggd, men har aldrig tänkt så mycket på C-programmering av mikrokontrollers.


edit: Jag slapp felmeddelanden när jag gjorde såhär:

Kod: Markera allt

     knapp_nr_lo = ADRESL
     knapp_nr_hi = ADRESH
     knapp_nr = knapp_nr_hi or knapp_nr_lo   'Slår ihop dem som ett word istället...
Användarvisningsbild
EagleSpirit
Inlägg: 1288
Blev medlem: 27 maj 2003, 23:15:48
Ort: Västerås
Kontakt:

Inlägg av EagleSpirit »

sodjan skrev: *Konverteringen* däremot tar en viss tid, och under den tiden är det lite onödigt att bara sitta syslolös och vänta. Det är inte några jättelånga tider,
kanske 50 us, men det motsvarar ju å andra sidan 500 instruktioner vid 40 Mhz...

Adc_Read väntar på resultatet och använder inte interrupt. För det får
man nog "köra" registren direkt. Nollan i anropet är ADC kanalen, för övrigt.
Ja det var konverteringen jag menade. Det tar alltså så lång tid, ja då kan det ju vara bra att ha det interruptet. Kanske inte helt värdefullt men om man vill göra A/D omvandlingar en gång per 10ms så kan det ju vara bra.

Jag vet inte hur bra microbasic är på att blanda men det är ju en hel del funktioner som skulle underlättaprogrammeringen om man använde ett annat språk som C eller Basic. Jag kör endast assembler och det tar ju väldigt lång tid att testa några enkla grejjer, även om man kan språket. Ska nog gå över till C på något sätt så att det går lite fortare med programutvecklingen. Problemet är ju att man aldrig hittar tid :(
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Hur stor skillnad är det på Basic och C i dessa fall?

Jag tror inte att det är så mycket vilket språk man väljer i sig som gör skillnaden, utan kvaliteten/flexibiliteten i de inbyggda funktionsbiblioteken. Här kan det skillja mycket mellan olika Basic's så väl som mellan olika C kompilatorer.

Sen, normalt är ASM det man startar med, för att sedan titta på andra verktyg när det blir aktuellt,

När det gäller C for PIC18, så är det bara att plocka ner "Student Edition" av C18 från Microchip. Full-funktion men en del av optimeringen lägger av efter 60 dagar (då man kan installera om, så vitt jag vet).
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

Än så länge har jag inte fått koden att fungera. Lysdioden är släckt hela tiden. Hela kopplingen är samma som i tråden jag länkade till tidigare. Tänkte bara skriva några rader ifall ni ser något jag har missat.
För attt inte koden ska bli för lång så skriver jag bara de delar som har hand om interrupt och A/D-delen.


I init-proceduren ser raderna för interruptet ut såhär:

Kod: Markera allt

    Setbit(PIE1, ADIE) ' A/D-converter Interrupt enable bit
    Setbit(INTCON, GIE) ' Global Interrupt enable bit
    Clearbit(PIR1, ADIF) ' A/D-converter Interrupt -- markeras som not completed. Clearas.

Interrupt-proceduren ser ut såhär i sin helhet:

Kod: Markera allt

sub procedure interrupt
  if TestBit(PIR1, ADIF) = 1 then
     knapp_nr_lo = ADRESL ' Läser av ADC's låga byte
     knapp_nr_hi = ADRESH ' Läser av ADC's höga byte
     knapp_nr = knapp_nr_hi or knapp_nr_lo  ' Slår i hop dessa till ett word
  end if

     'RUN
      if knapp_nr = 512 then run = 1
      end if

      'STOP
      if knapp_nr = 470 then run = 0
      end if

     ClearBit(PIR1, ADIF)
end sub

Efter det ligger main, som i sin helhet ser ut såhär:

Kod: Markera allt

main:

    Init

    While true
      if run = 1 then ' RUN
          prog = %1100000000000000  ' Programbitarna
        for x = 0 to 4095 step 7
          value = prog or x
          DAC_Output(value)      ' Sending
          delay_ms(10)
        next x
      else ' STOP
        DAC_Output(%1100000000000000)   ' Sending tomt...
      end if
    Wend

Hinner inte skriva mer i kväll. Ser ni något galet så..... :)
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Det verkar väll ganska osannolikt att du *varje* gång skulle få *exakt* 512 eller 470 från ADC !? Du behöver sannolikt testa en "range".

Var startas ADC konvertringen ?
Ett sätt (om du kontinuerligt vill polla knapparna) är att återstarta konverteringen sist i ISR'en. Notera att ADCn inte är "free running", alltså kör av sig själv, du måste kicka igång den varje gång (d.v.s sätta ADON biten, om jag inte minns fel). Du måste även göra en första start av ADCn i din startup/init kod, annars kommer du ju aldrig till ISR'en alls...

Jag har inte funderat helt på det, men bör inte :

knapp_nr = knapp_nr_hi or knapp_nr_lo

vara något i stil med :

"knapp_nr = knapp_nr_hi * 256 + knapp_nr_lo

Varför använder du "or" här ?

Jag minnst inte bakgrunden, men jag utgår från att du hade mycket bra anledning till att använda ADC'n för tangenterna....
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Det blev ju frågat om prog. språk också o jag vill fasthålla C som den rätta grejen. Eller rättare....assembler och C.

Assembler till de enklare sakerna och C till de mer komplexa program. Man kan såklart blanda vid behov men det är bäst att bara göra när man har mycket speciella krav på svarstid eller en viss funktion.

Sen funderade jag lite på programmet i sig men där har sodjan redan sagt det viktiga.

En OR är en bitmässig OR och kommer alltså enbart att göra 2 st 8-bitars ord till 1 st gemensamt 8-bitars ord.
Användarvisningsbild
JimmyAndersson
Inlägg: 26578
Blev medlem: 6 augusti 2005, 21:23:33
Ort: Oskarshamn (En bit utanför)
Kontakt:

Inlägg av JimmyAndersson »

Börjar från slutet: Att jag använder ADC'n för tangenterna beror mest på att det då bara krävdes en "pinne" för att komma åt hela tangentbordet (med 17 knappar.)

Ang "or": Hade inte tänkt på att man kunde lösa det som du gjorde. :)

Du har helt rätt i att jag inte får exakt t.ex 512 varje gång. I ett annat test (innan jag lade till interrupt-delen) så körde jag med
if (knapp_nr >= 511) and (knapp_nr <= 513) och det fungerade bra. Vet inte varför jag missade det i den här koden.


Problemet med varför det inte fungerar nu ligger nog i ADC-konverteringen. Jag har ingen första start av ADC'n i init-delen. Ska fixa till det.
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Även 511-513 är ett ganska "smalt" intervall. ADC avläsningar kan ofta (utan speciell hänsyn vid design av mönsterkort och programet) variera med i värsta fall upp till 10 "enheter" mellan avläsningar. T.ex så rekomenderas det att man sätter processorn i "sleep" under konverteringen för att processorn själv inte skall störa. ADIF kommer sedan att "väcka" processorn ur sleep när den känsliga delen är över. Dock behövs kanske bara detta om man vill ha en nogranhet på +/- en eller två bitar i resultatet...
Skriv svar