C nyelvű programfejlesztés PIC18 mikrovezérlőkre Összeállította: Molnár Zsolt Óbudai Egyetem, KVK, MAI 2012. november.
Bevezetés A gyakorlatban felmerülő, mikrovezérlővel felépülő áramkörök esetében az adott feladat megoldására általában magas szintű programnyelven érdemes megírni a működtető programot. Kivételt képeznek a nagysebességű és nagy biztonságú alkalmazások, amikor végrehajtási sebesség, vagy a kód működésének, részleteinek ismerete fontos. A C nyelvű kódok lefordításkor a létrejövő alacsony szintű kód nem egyértelműen megfeleltethető a C forrásnak, az eredmény sok mindentől függ (pl. programszerkezet, fordító beállításai.) Természetesen működésben (jó esetben) nincs különbség az egyes változatok között, de futási időben, a használt alacsony szintű utasítások fajtájában és számában, vagy a használt regiszterek tekintetében igen. (Ezek a dolgok az oldalhatások miatt problémákat jelenthetnek.) A C nyelvű programok áttekinthetősége, olvashatósága, kényelmi szolgáltatásai, a gyors eredményre jutás ugyanakkor mindenképpen a C nyelvű fejlesztés mellett szól. A mérés célja az, hogy a PIC18-as családnál az eddigiekben megszerzett széleskörű assembly szintű programozási ismereteket kiegészítsük a C nyelvű programozás megismerésével. Összehasonlíthatóvá válik a két programozási nyelv, az MPLAB hibakeresési eszköztára pedig C nyelvű fejlesztés során esetenként némileg más filozófiával használható, mint az eddigiekben. A mérés során a jól ismert környezetet (MPLAB, ICD2, PicDEM2 Plus) használjuk továbbra is, kiegészítve a Microchip PIC18-as családhoz készült C fordítójával. A mérésen a Lite változatot használjuk, de létezik a Standard és Professional változat is, amely kisebb méretű, gyorsabb futású kódot hoz létre. A fordító, ingyenes verziója letölthető a www.microchip.com oldalról. 2
A fejlesztőrendszer beállítása Hozzunk létre projektet, amelyben végrehajthatjuk a következő pontban ismertetett mintafeladatot! Ehhez indítsuk el az MPLAB fejlesztőrendszert! A Project Wizard-ot (Project Project Wizard) elindítva egy párbeszéd-ablak nyílik meg (1. ábra). Kattintsunk a Tovább gombra! Válasszuk ki a mikrovezérlő típust, amelyre a programot írni akarjuk! A demópanelen PIC18F452 típus található, ez az alapértelmezett. Ha nem ez jelenik meg eszközként (Device), akkor állítsuk be (2. ábra), majd lépjünk tovább! 1. ábra 2. ábra A következő lapon (3. ábra) állítsuk be a projekt könyvtárát (létrehozással vagy kiválasztással)! Ezután hozzáadhatunk forrásokat a projekthez (4. ábra), ezt most átléphetjük (Tovább)! Ha van mintaprogram, include fájl vagy egyéb állomány, amit a projektben szeretnénk használni vagy kezelni, itt hozzáadhatjuk. 3. ábra 4. ábra 3
Az utolsó ablakban egy összegzést ad az MPLAB a projekt beállításairól (5. ábra). Lépjünk ki a Befejezés-re kattintva! 5. ábra 6. ábra A Projekt ablakban (ha nem látható, bekapcsolhatjuk a View Projekt menüből) megjelenik a létrehozott projekt szerkezete a forrás-kategóriákkal (6. ábra). Állítsuk be a projekt típusát, azaz azt, hogy milyen fordítóval szeretnénk dolgozni (Project Select Language Toolsuite )! Válasszuk ki az Microchip C18 toolsite-ot (7. ábra)! 7. ábra 8. ábra A projekt jelenleg (hacsak a negyedik lépésben nem adtunk hozzá fájlokat) nincsenek fájlok (forrás vagy egyéb állomány). Adjunk hozzá egy új forrásfájlt (File New), és mentsük el tetszőleges néven a projektkönyvtárba (File Save As, nevet megadva: pl. mintapelda.c) (8. ábra)! Ezek után adjuk hozzá a létrehozott fájlt a projekthez! Kattintsunk jobb gombbal a Project ablak Source során, és válasszuk az Add Files pontot! Adjuk a projekthez az előbbiekben létrehozott forrásfájlt, majd kattintsunk a Megnyitás gombra! Ezzel az alapvető beállításokat megtettük. Továbbléphetünk a mintapélda megoldására. 4
Egy mintafeladat megoldása Mintapéldánkban a korábbi mérésekből ismert assembly mintapéldát (feladat_4.asm) dolgozzuk át C nyelvre. A programmagyarázatot (komment) helyhiány miatt nem közöljük, a példa magáért beszél. Az eredeti forrás fejléce a következő volt (feladatmegadás): ;********************************************************************************** ;* feladat_4.asm ;********************************************************************************** ;* A program TIMER1 megszakításának használatával PORTB0 állapotát ;* TIME*10ms-onként invertálja. A program TIME=0-ra nem működik! ;* A PicDem2 Plus panel órajele 4MHz, a programban ezt vettük alapul ;********************************************************************************** A két forráskódot a könnyű érthetőség miatt igyekeztünk minél jobban összhangba hozni, a helyenként kissé szokatlan szerkezet vagy programfelépítés ennek köszönhető. A változók elhelyezését a fordítóra bíztuk. A villogtatott LED portlábát definiáltuk (LED_0), természetesen ez elhagyható, ha a portlábra közvetlenül hivatkozunk. Ugyancsak a fordító helyezi el a memóriában az egyes függvényeket, így a megszakítás-kiszolgálást is. Az interrupt minősítő a magas szintű megszakításrutint azonosítja (0x08 című megszakításvektor), a low_priority interrupt minősítő amit most itt nem használunk pedig az alacsony szintűt (0x18 című megszakításvektor). A TIME változót ne felejtsük el feltölteni a program futásának vizsgálata közben! 5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 feladat_4.c #include "p18f452.h" unsigned char TIME; unsigned char TIME_WORK; #define LED_0 LATBbits.LATB0 void TMR1_ISR(); void InterruptHandlerHigh (void); #pragma code InterruptVectorHigh = 0x08 void InterruptVectorHigh (void) _asm goto InterruptHandlerHigh _endasm #pragma code #pragma interrupt InterruptHandlerHigh void InterruptHandlerHigh () if (PIE1bits.TMR1IE && PIR1bits.TMR1IF) TMR1_ISR(); else _asm reset _endasm void main() LATBbits.LATB0=0; TRISB=TRISB&0xFE; T1CONbits.TMR1ON=1; TMR1H=0xD8; TMR1L=0xF0; PIR1bits.TMR1IF=0; PIE1bits.TMR1IE=1; INTCONbits.PEIE=1; INTCONbits.GIE=1; TIME=100; TIME_WORK=TIME; while(1); void TMR1_ISR() TMR1H=0xD8; TMR1L=0xF0; if (!--TIME_WORK) LED_0=!LED_0; TIME_WORK=TIME; PIR1bits.TMR1IF=0; 6
Vizsgálja meg a program működését a szokásos eszközök használatával (szimulátor, debugger)! Mérési feladatok Írja át az előző PIC18-as mikrovezérlő családdal foglalkozó méréseken vizsgált, illetve megírt assembly programokat a mérésvezető kijelölése és utasításai alapján C kódra! Vizsgálja meg a C forrásból készülő assembly kódot (View Disassembly Listing)! Próbáljon töréspontot helyezni a C kódban, illetve az assembly kódban! Használja ki a programok vizsgálata, tesztelése és hibakeresése során a korábbi méréseken megismert hibakeresési eszközök (Stopper, Watch Window, logikai analizátor, naplózás, gerjesztések) adta lehetőségeket! 7
1: #include "p18f452.h" 2: 3: unsigned char TIME; 4: unsigned char TIME_WORK; 5: 6: #define LED_0 LATBbits.LATB0 7: 8: void TMR1_ISR(); 9: void InterruptHandlerHigh (void); 10: 11: #pragma code InterruptVectorHigh = 0x08 12: void InterruptVectorHigh (void) 13: 14: _asm 15: goto InterruptHandlerHigh GOTO 0xe 16: _endasm 17: 18: 19: #pragma code 20: #pragma interrupt InterruptHandlerHigh 21: void 22: InterruptHandlerHigh () MOVFF 0xfda, 0xfe4 MOVFF 0xfe2, 0xfda MOVFF 0xfe9, 0xfe4 MOVFF 0xfea, 0xfe4 MOVFF 0xff6, 0xfe4 MOVFF 0xff7, 0xfe4 MOVFF 0xff5, 0xfe4 MOVFF 0xff3, 0xfe4 MOVFF 0xff4, 0xfe4 MOVFF 0xffa, 0xfe4 LFSR 0, 0 x2 DECF 0xfe8, W, ACCESS BNC 0x46 MOVFF 0xfee, 0xfe4 BRA 0x3c LFSR 0, 0x2 DECF 0xfe8, W, ACCESS BNC 0x56 MOVFF 0xfee, 0xfe4 BRA 0x4c MOVF 0xfe6, F, ACCESS 23: 24: if (PIE1bits.TMR1IE && PIR1bits.TMR1IF) MOVF 0xf9d, W, ACCESS ANDLW 0x1 BZ 0x68 MOVF 0xf9e, W, ACCESS ANDLW 0x1 BZ 0x68 25: 26: TMR1_ISR(); RCALL 0xda 27: 28: else BRA 0x6a 29: 30: _asm 31: reset RESET 32: _endasm 33: 34: MOVF 0xfe5, F, ACCESS LFSR 0, 0x1 DECF 0xfe8, W, ACCESS BNC 0x7c MOVFF 0xfe5, 0xfed BRA 0x72 LFSR 0, 0x1 x2 DECF 0xfe8, W, ACCESS BNC 0x8c MOVFF 0xfe5, 0xfed BRA 0x82 MOVFF 0xfe5, 0xffa MOVFF 0xfe5, 0xff4 MOVFF 0xfe5, 0xff3 MOVFF 0xfe5, 0xff5 MOVFF 0xfe5, 0xff7 MOVFF 0xfe5, 0xff6 MOVFF 0xfe5, 0xfea MOVFF 0xfe5, 0xfe9 MOVFF 0xfe5, 0xfda RETFIE 0x1 8
35: 36: 37: void main() 38: 39: LATBbits.LATB0=0; BCF 0xf8a, 0, ACCESS 40: TRISB=TRISB&0xFE; xfe ANDWF 0xf93, W, ACCESS MOVWF 0xf93, ACCESS 41: 42: T1CONbits.TMR1ON=1; BSF 0xfcd, 0, ACCESS 43: TMR1H=0xD8; xd8 MOVWF 0xfcf, ACCESS 44: TMR1L=0xF0; xf0 MOVWF 0xfce, ACCESS 45: 46: PIR1bits.TMR1IF=0; BCF 0xf9e, 0, ACCESS 47: PIE1bits.TMR1IE=1; BSF 0xf9d, 0, ACCESS 48: INTCONbits.PEIE=1; BSF 0xff2, 0x6, ACCESS 49: INTCONbits.GIE=1; BSF 0xff2, 0x7, ACCESS 50: 51: TIME=100; MOVLB 0 x64 MOVWF 0x8a, BANKED 52: TIME_WORK=TIME; MOVFF 0x8a, 0x8b 53: 54: while(1); BRA 0xd6 55: 56: 57: void TMR1_ISR() 58: 59: TMR1H=0xD8; xd8 MOVWF 0xfcf, ACCESS 60: TMR1L=0xF0; xf0 MOVWF 0xfce, ACCESS 61: 62: if (!--TIME_WORK) MOVLB 0 DECF 0x8b, F, BANKED BNZ 0xee 63: 64: LED_0=!LED_0; BTG 0xf8a, 0, ACCESS 65: TIME_WORK=TIME; MOVFF 0x8a, 0x8b 66: 67: PIR1bits.TMR1IF=0; BCF 0xf9e, 0, ACCESS 68: --- E:\MPASM_MPLINK_PIC18_LT_Branch_3_42\pic18- lt\cxx-framework\src\traditional\proc\p18f4320.asm MOVWF 0xff3, ACCESS LFSR 0, 0 x2 RCALL 0x19e CPFSLT 0xfea, ACCESS BRA 0x1a6 CLRF 0xfee, ACCESS BRA 0x19e MOVF 0xff3, W, ACCESS CPFSLT 0xfe9, ACCESS CLRF 0xfee, ACCESS BRA 0x1a8 --- E:\MPASM_MPLINK_PIC18_LT_Branch_3_42\pic18- lt\cxx-framework\src\traditional\startup\c018i.c GOTO 0x1b0 LFSR 0x1, 0x100 LFSR 0x2, 0x100 CLRF 0xff8, ACCESS BCF 0x1, 0x6, ACCESS CALL 0xf2, 0 CALL 0x1cc, 0 CALL 0xb2, 0 BRA 0x1c0 x6 MOVWF 0xff6, ACCESS MOVWF 0xff7, ACCESS MOVWF 0xff8, ACCESS MOVLB 0 MOVWF 0x85, BANKED MOVWF 0x86, BANKED BNZ 0x114 TSTFSZ 0x85, BANKED BRA 0x114 BRA 0x18e MOVWF 0x80, BANKED MOVWF 0x81, BANKED 9
MOVWF 0x82, BANKED MOVWF 0xfe9, ACCESS MOVWF 0xfea, ACCESS MOVWF 0x83, BANKED MOVWF 0x84, BANKED MOVFF 0xff6, 0x87 MOVFF 0xff7, 0x88 MOVFF 0xff8, 0x89 MOVFF 0x80, 0xff6 MOVFF 0x81, 0xff7 MOVFF 0x82, 0xff8 MOVLB 0 MOVF 0x83, F, BANKED BNZ 0x16a MOVF 0x84, F, BANKED BZ 0x178 MOVWF 0xfee, ACCESS DECF 0x83, F, BANKED BC 0x164 DECF 0x84, F, BANKED BRA 0x16a MOVFF 0x87, 0xff6 MOVFF 0x88, 0xff7 MOVFF 0x89, 0xff8 MOVLB 0 DECF 0x85, F, BANKED SUBWFB 0x86, F, BANKED BRA 0x10c --- E:\MPASM_MPLINK_PIC18_LT_Branch_3_42\pic18- lt\cxx-framework\src\traditional\stdclib\ init.c 10