Introduktion till C för enchipsdatorer Lektion 1 Introduktion till C för enchipsdatorer
Kursinnehåll Innehåll C föreläsningar Viss del repetition Om användning av C för inbyggda system i allmänhet Använda C för programmering av PIC enchipsdator Plan för de närmaste två veckorna Preliminär, kan anpassas efter önskemål
Planering v1 v1. Lektion 1: Introduktion till C för enchipsdatorer C kontra assembler Datatyper och variabler Lagringsklasser och kvalificerare Operatorer v1. Lektion 2: Programstruktur och kompileringsprocess (1) Symboliska konstanter Villkorssatser Vektorer Funktioner Kompilering av C program v1. C Lab1: Förstå C och skiftregister för portexpansion Undersök ett C program Utöka programmet till multiplikator med skiftregister och display
Planering v2 v2. Lektion 3: Programstruktur och kompileringsprocess (2) Inline assembler Interrupt Kompileringsprocessen v2. Lektion 4: Programmeringstekniker Bit-fält i struct Pekare Programoptimering v2. C Lab 2: PIC Termometer Skiftregister från Lab 1 Konstanter i EEPROM
Dagens Agenda C kontra assembler Datatyper och variabler Storlek Användning Lagringsklasser och kvalificerare Hur skall en specific variabel lagras, respektive behandlas av kompilatorn? Operationer Aritmetiska Logiska Bitvis logiska
C kontra Assembler C Assembler Ganska effektivt Högre abstraktionsnivå, portabel kod Lättare att hantera större projekt Assembler Snabbhet, mindre kodstorlek Svårt att hantera större projekt
ANSI C C Varför ANSI C? Andra Programmeringsspråk Första utgåvan av C publicerad 1978 ANSI C, American National Standards Institute’s Standard för C (1989) Varför ANSI C? Kompilatorstöd (ex. PICC Lite –gratis!) Utbredd användning (ca.80 % av alla inbyggda system projekt 1999-2000) Bra stöd för hårdvarunära programmering Andra Programmeringsspråk C++ (Objektorienterad efterföljare, ej lika effektivt -producerar mer kod, standard?) Ada (Stöd för parallella processer i språket, används till största delen i försvarsindustri)
Inledande Exempel Ganska lätt att förstå! Ett tal räknas upp från 0 till 1000 (3E8) unsigned int j; for(j = 0 ; j<1000; j++) continue; Betydligt svårare! (reg d lägsta byte, reg e högsta byte) Adress Maskinkod Assembler 0003EC 18D CLRF 0xd ;clear register d 0003ED 18E CLRF 0xe ;clear register e 0003EE A8D INCF 0xd, F ;incr. d put back in d 0003EF 1903 BTFSC 0x3, 0x2 ;run next if reg. 3 bit 2 = 1 (statuz z=1) 0003F0 A8E INCF 0xe, F ;incr. d put back in e 0003F1 3003 MOVLW 0x3 ;load 3 to work 0003F2 20E SUBWF 0xe, W ;sub f-w put in w (1st 253 in w) 0003F3 30E8 MOVLW 0xe8 ;load e8 to work 0003F4 1903 BTFSC 0x3, 0x2 ;run next if reg. 3 bit 2 = 1 (statuz z=1) 0003F5 20D SUBWF 0xd, W ;sub f-w put in w 0003F6 1C03 BTFSS 0x3, 0 ;run next if reg. 3 bit 0 = 0 0003F7 2BEE GOTO 0x3ee ;back to 3ee
Variabler En variabel avser ett visst minnesutrymme Variabler deklareras av en viss datatyp Storlek och värde på variabler Viktigt att använda rätt datatyp m.a.p. minneskrav, korrekthet och prestanda I föregående exempel unsigned int 16 bitar (två register krävs)
Datatyper Heltalstyper bit (1 bit, 0 eller 1, ej ANSI C standard men stöds av PICC och kan användas för att spara minne) Mindre heltal char (8 bitar, signed or unsigned) default unsigned, ändras i kompilatorinställningarna) Andra större heltal (little endian, minst värda byten på lägsta adressen) short = int (16 bitar, signed) unsigned short = unsigned int (16 bitar, unsigned) long (32 bitar, signed) unsigned long (32 bitar, unsigned)
Flyttal Flyttal (tal med flytande decimalpunkt), notera att heltalet (alltid =1 för alla tal utom 0) i signifikanden ej lagras – används för ökad precision float (24 bitar) double (32 bitar, välj 24 eller 32 i kompilatorinställningarna) Det som skiljer är noggrannhet
Flyttalsrepresentation (PICC Manual) Ex: Pi ≈ 3,1415926 1 1,00 1001 0000 1111 1110 1101 001 Med double 24 bit-> Pi=3,141602 0 100 0000 0 100 1001 0001 0000 Med double 32 bit-> Pi=3,141593 0 100 0000 0 100 1001 0000 1111 1101 1011 Varför?
Storlek på datatyper (PICC Manual)
Blandning av datatyper Typomvandling sker från ”lägre” till ”högre” typ Vad händer? unsigned int u; if (u >-1) Alltid falskt! -1 omvandlas till unsigned (1111 1111 1111 1111) Antag: int 16 bit och long 32 bit Då är -1L < 1U men -1L > 1UL (L suffix för long, U suffix för unsigned, UL suffix för unsigned long)
Talformat (PICC Manual) Se upp med att använda 0 före ett tal Det betyder att det tolkas som oktalt
Lagringsklasser Lagringsklasspecificerare talar om hur en variabel lagras Extern Global, extern behöver inte deklareras om den definieras i samma fil före den används Auto Behöver ej anges, automatisk allokering, i PICC bank 0 (kan ändras med bank kvalificerare) Static Extern blir osynlig utanför källfilen Auto variabels värde kvarstår utanför funktion Register Lagra helst i register, inte aktuellt i vår PIC där vi endast arbetar med register
Kvalificerare Datatypkvalificerare talar om hur kompilatorn skall tolka en variabel const Variabler med konstant värde (läggs i programminne, observera att detta inte gäller konstanta pekare) volatile Talar om för kompilatorn att värdet kan ändras emellan successiva accesser Förhindrar att kompilatorn optimerar till synes redundanta avsnitt Viktigt att tänka på vid interrupt och minne som delas av flera processorer Speciella datatypkvalificerare (PICC) absolute Specific adress kan anges för globala och statiska variabler volatile unsigned char @ 0x06; persistent, bank ock eeprom
Exempel I filen pic1684.h är SFR deklarerade och mappade till specifika adresser: Lagringsklass kvalificerare datatyp absolut @ adress static volatile unsigned char PORTB @ 0x06; static unsigned char bank1 OPTION @ 0x81; static volatile bit RB7 @ (unsigned)&PORTB*8+7; static bank1 bit RBPU @ (unsigned)&OPTION*8+7; Varför är inte OPTION volatile?
Operatorer Aritmetiska Logiska (Förväxla ej med bitvis) Jämförelse +,-,*,/ Modulus %, ger rest vid heltalsdivision Ex: 25%10 = 5 Logiska (Förväxla ej med bitvis) &&, ||, ! Jämförelse ==, >=, <=,>,<
Bitmanipulation Bitvisa operatorer, används på heltalstyper Varje operand behandlas som en ordnad bitvektor, jämförs bit för bit Ett komplementet ~ varje bit inverteras Och & Returnerar 1 om båda bitarna är 1 Eller | Returnerar 1 om någon av bitarna är 1 Exlusivt eller ^ Returnerar 1 om ena biten är 1 och den andra 0 Skift operatorn Skifta vänster << Skifta höger >> a = b << 6 (innehållet i b skiftas 6 steg åt vänster, de 6 bitarna längst till vänster i b förvinner, fylls på med nollor från höger Se upp med högerskift och signed integer Om neg. tal kan det fyllas med ettor från vänster (kompilatorberoende PICC sign extension dvs. med ettor)
Maskning Ett bitmönster transformeras till ett annat genom en logisk bitvis operation Testa enstaka bit If (bitvar & 0x04) //Alt. 1: test av bit 2 If (bitvar & (1 << 2)) //Alt. 2: test av bit 2 Sätta enstaka bit Bitvar = Bitvar | (1 << 2); // Sätt bit 2 till 1 Bitvar |= (1 << 2); // Sätt bit 2 till 1 Nollställa enstaka bit Bitvar &= ~(1 << 2) //Nollställ bit 2 Kombinera bitar ur flera register nVolt = 0 | ADRESH; nVolt = (nVolt << 8) | ADRESL;
Defaultvärden för konstanter Se upp med att masken är lika stor som operanden! unsigned long j j=0xFFFFFFFF; j &= ~(1 << 15); // j kan bli 0x00007FFF! j &= ~(1 << 16); // j kan bli 0xFFFFFFFF! 1 default int 16 bitar, istället 1L (suffix för long) j &= ~(1L << 15); // j blir 0xFFFF7FFF! j &= ~(1L << 16); // j blir 0xFFFEFFFF! char i; i=0x55; if (~i == 0xAA) //Lurigt, heltalsbefordring till int ger: ~0x0055 = 0xFFAA
Testa flera bitar Om man vill testa fler bitar Ex. testa om bit 0 och 1 är satta if (bitvar & 0x03) True för bit 0 eller bit 1 if ((bitvar & 0x03) == 0x03) if (bitvar & 0x01 && bitvar & 0x02) Båda måste vara true