Fórum témák

» Több friss téma
Cikkek » PIC programozás C nyelven - CCS - I. lecke
PIC programozás C nyelven - CCS - I. lecke
Szerző: deguss, idő: Jan 28, 2007, Olvasva: 61931
Lapozás: OK   4 / 4
Interruptok kezelése

Sok interrupt létezik, mely megszakítja a processzor addigi munkáját és egy speciális függvényt dolgoz le, az ISR-t. Hogy milyen "interruptszavakat" használhatunk, az függ a használt mikrokontroller típusától. A leggyakoribbak, és magyarázataik:

#INT_xxxxLeírás
#INT_ADAnalog-digital konverzió vége
#INT_EXT"External interrupt", azaz külső megszakítás, lsd. a letni példát.
#INT_LOWVOLTAlacsony tápfesz. Brown-out-ot érdemes ilyenkor kikapcsolni, (inkább haladóknak)
#INT_RBPort B4-B7 pinek egyikén állapotváltozás. (Ez még sleep üzemmódból is fel tudja kelteni a processzort
#INT_RDARS232 buffer-regisztereibe adat érkezett. Csak a hardveres receive PIN-re vonatkozik.
#INT_RTCC / #INT_TIMER0Timer 0 túlcsordulás
#INT_TIMER1Timer 1 túlcsordulás
#INT_TIMER2Timer 2 túlcsordulás
#INT_SSPSPI vagy I2C "forgalom"

Ezeket az "interruptszavakat" mindig az interrupt service routine függvény elé kell írni, a compiler csak így fogja helyesen értelmezni. Ezek a függvényeknek nem lehet átadni értéket, és nem is adnak vissza semmit.


A következőkben bemutatásra kerül egy példa, ami pl. egy szervó vezérlőjelének alacsony szintjét méri, a TIMER1 modul segítségével. Egy gombnyomásra elmenti az éppen aktuális pulzusszélességet a PIC belső EEPROM-jába, hogy egy áramszünet után ki tudja azt onnan olvasni.

  1. #include <16F819.h>     
  2. #zero_ram
  3. #device adc=8  *=16
  4. #fuses HS,NOWDT,NOPROTECT,NOMCLR,NOPUT,BROWNOUT,NOLVP,NOCPD
  5. #use delay(clock=8000000)
  6. #use fast_io( A )       //a compiler nem ellenőrzi, hogy valóban kimenetnek
  7. //van-e állítva a TRISX regiszter, ha ír a PORTX-be.
  8. #use fast_io( B )
  9.  
  10. #define SERVO      PIN_B0          //szervó jel
  11. #define KEY_SET  PIN_B1      //egy nyomógomb
  12.  
  13. #byte   T1CON = 0x10        //pointer a TIMER1 beállító regiszterére
  14. #byte   TMR1L = 0x0E              //TIMER1 alsó 8 bit
  15. #byte   TMR1H = 0x0F              //TIMER1 felső 8 bit
  16.  
  17. enum interr { lowtohigh=0, hightolow=1 } edge=hightolow;        
  18. // két állapot, ez kell az élfelismeréshez
  19. enum states { left=1, off=0, right=2 } index=off;
  20. // index lámpák állapota (nem kerülnek kiadásra)
  21.  
  22. int16 time_ellapsed;    //16 bites integer az idő méréséhez
  23. int16 temp4eeprom;      //16 bites integer az EEPROM adat ki- és beviteléhez
  24. float MIDDLE;      //lebegőpontos változó, a "középállás" megjegyzésére.
  25. //nem minden szervó áll középállásban egy pl. 1,3ms pulzusszélességű jeltől
  26. int wtoeepromH,wtoeepromL;      //EEPROMBA írás változói
  27.  
  28. //===========================================================================
  29. #int_EXT
  30. void int_EXT_isr() {
  31. //===========================================================================
  32.         if (edge == hightolow){ 
  33.                 bit_set(T1CON,0);       //T1CON.TMR1ON on
  34.                 ext_int_edge(L_TO_H);
  35.                 edge = lowtohigh;
  36.         }
  37.         else {
  38.                 bit_clear(T1CON,0);     //T1 off
  39.                 time_ellapsed = make16(TMR1H,TMR1L);
  40.                 set_timer1(0);
  41.                 ext_int_edge(H_TO_L);
  42.                 edge = hightolow;
  43.         }
  44. }
  45.  
  46. //===========================================================================
  47. void init(void){
  48. //===========================================================================
  49.         set_tris_a(0xFF);
  50.         set_tris_b(0b00000111);
  51.         output_b(0x00);
  52.         port_b_pullups(true);
  53.  
  54.         temp4eeprom = (int16)(read_eeprom(0x2101)&0xff) *
  55.                                 0x100+(read_eeprom(0x2100)&0xff);
  56.         MIDDLE = (float)temp4eeprom;
  57.         ext_int_edge(H_TO_L);
  58.         enable_interrupts(INT_EXT);
  59.  
  60.         setup_timer_1 ( T1_INTERNAL | T1_DIV_BY_1 );   
  61. // 8,192 ms-on belül túlcsordulna, de kell az 1:1-es előosztó a jó
  62. // felbontás miatt
  63.         set_timer1(0)//elvileg elhanyagolható
  64.         enable_interrupts( GLOBAL );   
  65. }
  66.  
  67. //===========================================================================
  68. void main() {
  69. //===========================================================================
  70. init();
  71. for(;;){        //ugyan az mint a while(1),
  72.                 //csak így nem ad figyelmeztetést a compiler
  73.    if (!input(KEY_SET)){
  74.       output_b(0x00);
  75.       delay_ms(100);
  76.       if (!input(KEY_SET)){     //aktív állapotban alacsony szintű,
  77.                                 // mert pull-up ellenállás van rajta.
  78.          delay_ms(1000);                //várunk egy kicsit
  79.          if (!input(KEY_SET)){  //biztos hosszan nyomja a gombot?
  80.             wtoeepromH = make8(time_ellapsed,1); //1 byte-ot shiftelünk, MSB
  81.             wtoeepromL = time_ellapsed-(wtoeepromH*0x100);      //LSB
  82.             write_eeprom (0x2100, wtoeepromL);    //EEPROM-ba írás
  83.             write_eeprom (0x2101, wtoeepromH);
  84.            
  85.             temp4eeprom = (int16)(read_eeprom(0x2101)&0xff) *
  86.                                 0x100+(read_eeprom(0x2100)&0xff);
  87. //EEPROM-ból kiolvasás, és konverzió először 16 bites integerre, majd
  88.             MIDDLE = (float)temp4eeprom;        //float számmá alakítás
  89.         }
  90.       }
  91.    }
  92.  
  93.    if (edge == hightolow){
  94. /* Itt történik a pulzus hosszának a kiértékelése. Ekkor már a
  95. time_ellapsed változóban van az érték, amit TIMER1 mért. A következő
  96. logikával pl. egy jobbra (index.right) vagy egy balra (index.left)
  97. indexet lehet vezérelni.
  98. A megfelelő PIN-ek állítása a program egy későbbi részében történhet. */
  99.  
  100.    if ((time_ellapsed > (0.56*MIDDLE)) && (time_ellapsed < (0.92*MIDDLE)))
  101.       //0,8-1,1ms
  102.       index = left;
  103.    else if ((time_ellapsed > (1.08*MIDDLE)) && (time_ellapsed < (1.43*MIDDLE)))
  104.       //1,3-1,6ms
  105.       index = right;
  106.    else index = off;
  107.  
  108.         }
  109. }//end of while
  110. }//end of main

Remélem érthető a program, vagy ha nem is elsőre, de többszöri átolvasásra, és saját kísérletezgetésre mindenki megérti.
Egy tanács: A timer1-et azért nem a normál enabel_interrupts(TIMER1); függvénnyel használom, mert nem tudom, milyen ASM kódot generál neki a Compiler, de biztos, hogy olyat, amivel az időzítő indítása tovább tartana, mint egy egyszerű bit_set()-függvénnyel, amit egy az egyben "bsf" utasításnak fordít, amit a processzor egyetlen ciklus alatt elvégez.

Egy-két kép a programról:

Remélem sikerült egy kis bepillantást nyújtani a PIC-ek programozásába C nyelven. Mindenkinek elsősorban kitartás és szorgalmat kívánok hozzá!

Szerk.: Köszönöm unicorn visszajelzését, mely szerint a demo verziójú fordító nem telepíti rendesen a header fájlokat.
Itt megtalálható a leggyakrabban használt közel 300 PIC header fájla, ezeket a Devices mappába csomagoljuk ki.
Következő: »»   4 / 4
Értékeléshez bejelentkezés szükséges!
Bejelentkezés

Belépés

» Elfelejtett jelszó
» Regisztráció
Hirdetés
A használat feltételeiAdatvédelemGY.I.K., Használati útmutató és szabályokImpresszumHiba jelentése
Lapoda.hu     XDT.hu     HEStore.hu