Att avlusa en rad Assembler tar lika lång tid som att avlusa en rad C. Att skriva i C gör att man är utlämnad till kompilatorns sätt att göra assembler koden. Assembler ger fullständig kontroll över tider. C är ett standardiserat sätt att skriva program. C ger betydligt större möjlighet att strukturer sitt program. C ger möjligheter att återanvända kod i större utsträckning #include <pic.h> #include <sys.h> char LEFT,RIGHT,MOTORHASTIGHET; void main(void) if (LEFT == RIGHT) MOTORHASTIGHET = 0xFF; else MOTORHASTIGHET = 0; while(1) continue; P16F84: MOVFW LEFT ; Flytta LEFT till W-registeret 1 cykel 1 word XORWF RIGHT,W ; Jämför LEFT med RIGHT 1 cykel 1 word BTFSC Z ; Om LEFT=RIGHT blir Z=1 2 cykel 1 word GOTO PLATTAN 1 cykel 1 word CLRF MOTORHASTIGHET 1 cykel 1 word GOTO SLUT 1 cykel 1 word PLATTAN: MOVLW 0xFF 1 cykel 1 word MOVWF MOTORHASTIGHET 1 cykel 1 word SLUT: GOTO SLUT 1 cykel 1 word
Att arbeta med flyttal och matematiska funktioner i assembler kräver stora kunskaper om assembler programmering. I PIC-C finns detta färdigt. Nackdelen är dock att kompilatorn kräver mycket minne i processorn för att realisera funktionerna. Att utföra följande program kräver 1175 words program ROM. 55 bytes RAM. Om man byter ut raden till. Kommer programmet att svälla endast till 1315 byte ROM och 63 byte RAM. Slutsatsen av detta bör bli att flyttal och tyngre matematiska funktioner bör användas med förstånd. #include #include #include <pic.h> <sys.h> <math.h> #define C 3.141592/180.0 double i,svar; void main(void) for (i=0;i<=180;i+=10) svar = sin(i*c); Building MATH.HEX... Compiling MATH.C: Command line: "E:\HT-PIC\BIN\PICC.EXE -G -O -Zg9 -D32-16C65 G:\PIC\ROBOTLAB\MATH.C" Enter PICC -HELP for help Memory Usage Map: User segment: $0013 - $0038 $0026 (38) bytes Program ROM: $0000 - $0012 $0013 (19) words Program ROM: $0377 - $080D $0497 (1175) words Bank 0 RAM: $0020 - $0056 $0037 (55) bytes Build completed successfully.
För att kontrollen över tider i ett C-program kan timern användas. Ett alternativ till detta kan vara att inkludera assembler i programmet. Följande program låter en utgång vara hög under 9cykler, vid 4MHz kristall blir detta 9us. Detta görs enligt följande. #include #include <pic.h> <sys.h> void main(void) PORTA = 0; TRISA = 0; #asm BSF NOP NOP NOP NOP NOP NOP NOP NOP BCF #endasm porta,0 porta,0 while(1) continue;
MPLAB är en integrerad utvecklings miljö för alla PIC-processorer. Det finns en editor att skriva programmet i. Det finns projekthantering för att underlätta utvecklings arbetet. Programmet innehåller även simulerings möjlighet så som stimulerning av portar, möjlighet att titta på variableri sk watch fönster. Från MPLAB sker även assemblering eller kompilering. Den eventuella assemblatorn eller kompilatorn finns inte i MPLAB. Utan dessa ligger som externa program som anropas från MPLAB. PIC-C kommer från tredjepartsleverantören Hi-TECH. MPLAB Stödjer detta program vilket medför att C kan skrivas, kompileras och simuleras i MPLAB utan alltför stora problem.
Nedan följer en kort genomgång av olika begrepp för C-programmering. Detta skall läsas i anslutning med robot_c.c Initiering Huvudprogram ISR Efter reset kommer processorn att anropa funktionen main(). I denna funktion skall initiering och huvudprogram ligga. Vid interruptförfrågan exekveras funktionen interrupt(). Nedan följer olika exempel på slingor. Alt1. Alt2 Alt3 for (x=0;x<10;x++) Led^=1; X=10 While( x>0 ) Led^=1; x--; Do Led^=1; x++; while( x<10 )
IF-else satsen används för att utrycka beslut. Den skrivs på formen if (uttryck) sats; else if (uttryck) sats; else if (uttryck) sats; else sats; Switch -satsen är ett flevägsval som prövar om uttrycket övensstämmer med ett at ett antal konstanta heltalsvärden och förgrenar sig där efter. Switch (uttryck) case konstantuttryck: satser; case konstantuttryck: satser; default: satser; Genom att kunna ersätta värden, uttryck,tecken mm med en egen vald förklaring kan programmet göras mer lättläst. # define timervalue 217 När kompilatorn hittar timervalue i programkoden, kommer den att ersätt uttrycket med talet 217.
I Hitec-C kan följande variabel deklarationer göras. bit 1 boolean char 8 signed or unsigned integer unsigned char 8 unsigned integer short 16 signed integer unsigned short 16 unsigned integer int 16 signed integer unsigned int 16 unsigned integer long 32 signed integer unsigned long 32 unsigned integer float 24 real double 24 or 32 real Deklarationer kangöras flera sätt. Vi kommer att behandla:globala, lokala, automatiska, statiska. Globala: Deklarationen görs utanför en funktion.( I början på programmet) Variabeln kommer därmed att bli tillgänglig för hela programmet. Nackdelen är att variabeln tar upp plats även då den inte används. Lokal: Deklareras inuti funktionen. MPLAB kan ej visa dessa variabler i sitt Watch-fönster. Talrepresentation kan ske på följande sätt: Binär Oktal Decimal Hexadecimal Siffrorna 0 och 1 följt av B Ex. 000101b Siffrorna 0 till 7 följt av O,Q,o,q Ex. 18Q Siffrorna 0 till 9 följt av D,d eller ingenting Ex. 102d Siffrorna 0 och 9, bokstäverna A till F inledande med 0x alt följt av H,h Ex. 0x2F 2Fh
ex * multiplikation + addition - subtraktion / division = lika med > större än >= större än eller lika med < mindre än <= mindre än eller lika med <> inte lika med mod modulus & Bitvis AND ^ Bitvis XOR Bitvis OR not Bitvis 1-komplement << or shl Skifta vänster >> or shr Skifta höger rol Rotera vänster ror Rotera höger svar = (A>>5)&1; // Skiftar bit 4 till bit0 och maskar sedan ut bit 0 Om A sätts till 0010001b kommer svar att bli 1.
C har två möjligheter att öka och minska en variabelsvärde. För att öka används ++ och för att minska --. Ex. n=5; x = n++; // Efter att denna rad är exekverad kommer x =5 och n = 6. n=5; x = ++n; // Efter att denna rad är exekverad blir x=6 och n=6. Raden utförs alltså med prioritet från vänster. Uttryck som i = i + 2; kan skrivas på ett mer kompakt sätt. i += 2; Uttrycket x *= y + 1; Kommer att betyda x = x * (y+1)
Funktioner används, för att få en bättre struktur och att återanvändning av kod skall underlättas. En funktion kan ha in- och utparametrar, detta är dock inte nödvändigt. Hur funktioner skrivs visas med följande exempel. Programbeskrivning: Talen A och B skall multipliceras med varandra. Svaret skall sedan tilldelas variabeln C. Observera att Variablerna A och B är char medan C är integer. #include #include <pic.h> <sys.h> char A,B; int C; int mult(char a,char b) return a*b; // a,b är lokala variabler // Multiplicerar talen a och b med varandra void main(void) A=10; B=212; C=mult(A,B); while(1) continue;
Ett realtidssystem läser in och bearbetar data inom samma tidsintervall som utmatning av data skall ske. Då vi använder en enchipsdator kommer så gott som samtliga applikationer att vara i realtid. Utmaningen blir att skriva program som kan få processorn att utföra flera saker samtidigt. Multitasking. Ett mindre lyckat exempel på detta är Windows 3.11. Formatering av diskett samtidigt som man skriver i någon ordbehandlare. Datorn formaterar en liten stund, för att sedan släppa över kontrollen till ordbehandlaren för ett tag. En temperaturlogger skulle kunna vara ett exempel på icke realtidssystem. Den lagrar data, som vid ett senare tillfälle bearbetas. Multitasking i t.ex en PIC16F84, realiseras genom att dela upp programmet i mindre uppgifter. Dessa måste sedan kommunicerar med varandra via flaggor och register. Uppgifterna utförs i tur och ordning och efter det behov som applikationen kräver det. Då flera uppgifter skall göras år programmet aldrig stanna för att vänta på en händelse skall inträffa. EX En lysdiod skall togglas när knappen trycks ner. while(1) while(knapp==0) // Väntar tills knapp är tryckt continue Led ^=1; while(knapp==1) // Väntar tills knapp är släppt continue while(1) if (knapp ==1 && knappold ==0) Ã'HWHNWHUDUÃDWWÃNQDSSHQV Knapptryckt = 1;ÃÃWLOOVWnQGÃKDUÃJnWWÃIUnQÃÃWLOOÃ Knappold = knapp; if (Knapptryckt == 1) Led ^=1; Knapptryckt = 0;
För att illustrera hur ett realtidsprogram kan, ska vi titta på en mindre larm konstruktion. Funktionen är som följer: Larmet skall ha en till- och frånbrytare som är momentan. Med andra ord vid första trycket skall larmet slås på, vid andra trycket skall det slås av. Larmet har en larmkontaktingång som kan utlösa larmet. Detta kan bara hända om larmet är påslaget. Det skall finnas en lysdiod som indikerar påslagen enhet, samt en blinkande med frekvensen 2Hz för indikering av utöst larm. För att åstadkomma detta bryter vi ner programmet i mindre funktionsblock. Se skiss. void Avstuds (): Eliminerar kontaktstudsar. void LarmTill(): Varje gång Till/Från brytaren går från 0 till 1 togglar flaggan TILL. void Larm(): Ser till att det bara går att utlösa larmet när flaggan TILL = 1; void LarmLed(): Ger blink funktionen till Lysdioden larmsignal. Nu kan varje funktion programmeras var för sig. Dessa kan på ett betydligt lättare sätt simuleras och testas var för sig.
PB.0 Larm Till/Från brytare LarmTillIn void Avstuds() Avstudsning LarmTillAvstuds void LarmTill() 1 bit räknare PB.2 Lysdiod Larm Till / Från Till void Larm() Aktiverad void LarmLed() PB.3 PB.1 Larmkontakt Larmkontakt Lysdiod Larmsignal void LedOsc() osc. 2 Hz Blink #include #include <pic.h> <sys.h> /* Programbeskrivning: * * Enkelt larm * * Larmet kan kopplas till eller från med hjälp av momentan strömställare. * En lysdiod indikerar att larmet är påslaget. * Då larmkontaken sluts kommer en lysdiod att börja blinka med frekvensen 2Hz. * För att larmet skall utlösas måste Larmet vara påslaget och larmkontakten sluten. * * Larm Till/Från Ingång PORTB.0 * Larmkontakt Ingång PORTB.1 * Lysdiod Till/från indikering Utgång PORTB.2 * Larmindikering Utgång PORTB.3 */ #define #define PORTBIT(adr, bit) ((unsigned)(&adr)*8+(bit)) FLAGBIT(adr, bit) ((unsigned)(&adr)*8+(bit)) #define timervalue -62 static volatile unsigned char FLAG1 @ 0x20; static volatile unsigned char FLAG2 @ 0x21; static bit LarmTillIn @ PORTBIT(PORTB, 0); static bit LarmKontakt @ PORTBIT(PORTB, 1); static bit LarmTillLed @ PORTBIT(PORTB, 2); static bit LarmLed @ PORTBIT(PORTB, 3); static bit LarmTillInOld @ FLAGBIT(FLAG1, 0); static bit LarmTillAvstuds @ FLAGBIT(FLAG1, 1); static bit LarmTillAvstudsOld @ FLAGBIT(FLAG1, 2); static bit Blink @ FLAGBIT(FLAG1, 3); static bit Aktiverad @ FLAGBIT(FLAG1, 4); static bit Till @ FLAGBIT(FLAG1, 5); static bit AvstudsStart @ FLAGBIT(FLAG1, 6);
static bit LarmTillInTemp @ FLAGBIT(FLAG1, 7); static bit TempBit @ FLAGBIT(FLAG2, 0); int LedTimer; char AvstudsTimer;
void interrupt timer(void) TMR0 = timervalue; LedTimer++; if (AvstudsStart == 1) AvstudsTimer++; T0IF = 0; void Avstuds(void) LarmTillInTemp = LarmTillIn; switch(larmtillavstuds) case 0: if ((LarmTillInTemp ==1) && (LarmTillInOld == 0)) AvstudsStart = 1; else if ((LarmTillInTemp == 0) && (LarmTillInOld == 1)) AvstudsTimer = 0; AvstudsStart = 0; if (AvstudsTimer > 10) AvstudsTimer = 0; AvstudsStart = 0; LarmTillAvstuds = 1; break; case 1: if ((LarmTillInTemp ==0) && (LarmTillInOld == 1)) AvstudsStart = 1; else if ((LarmTillInTemp == 1) && (LarmTillInOld == 0)) AvstudsTimer = 0; AvstudsStart = 0; if (AvstudsTimer > 10) AvstudsTimer = 0; AvstudsStart = 0; LarmTillAvstuds = 0; break; default:break; LarmTillInOld = LarmTillInTemp;
void LarmTill(void) TempBit=LarmTillAvstuds; if (TempBit == 1 && LarmTillAvstudsOld==0) Till^=1; LarmTillAvstudsOld =TempBit; void Larm(void) if (Till == 1 && LarmKontakt == 1) Aktiverad = 1; else Aktiverad = 0; void LedOsc(void) if (++LedTimer>250) LedTimer = 0; Blink ^= 1; void LarmLedTill(void) LarmLed = Blink & Aktiverad;
main() FLAG1 = 0; PORTA = 0x00; PORTB = 0x00; TRISA = 0x00; TRISB = 0b00000011; // PA bit 0 ingång PSA = 0; // Använd prescaler till TMR0 PS0 = 1; // Prescaler satt till dela med 16 PS1 = 1; PS2 = 0; T0IF = 0; T0CS = 0; TMR0 = timervalue; T0IE = 1; GIE = 1; // Väljer intern oscillator // nollställ tmr0 16*62 = 992uS 1mS while(1) // Här börjar huvudprogrammet Avstuds(); LarmTill(); Larm(); LedOsc(); LarmLedTill();