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 – 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 – 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 19992000) – 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 Ett tal räknas upp från 0 till 1000 (3E8) Betydligt svårare! (reg d lägsta byte, reg e högsta byte) Adress 0003EC 0003ED 0003EE 0003EF 0003F0 0003F1 0003F2 0003F3 0003F4 0003F5 0003F6 0003F7 Maskinkod Assembler 18D CLRF 0xd 18E CLRF 0xe A8D INCF 0xd, F 1903 BTFSC 0x3, 0x2 A8E INCF 0xe, F 3003 MOVLW 0x3 20E SUBWF 0xe, W 30E8 MOVLW 0xe8 1903 BTFSC 0x3, 0x2 20D SUBWF 0xd, W 1C03 BTFSS 0x3, 0 2BEE GOTO 0x3ee Ganska lätt att förstå! unsigned int j; for(j = 0 ; j<1000; j++) continue; ;clear register d ;clear register e ;incr. d put back in d ;run next if reg. 3 bit 2 = 1 (statuz z=1) ;incr. d put back in e ;load 3 to work ;sub f-w put in w (1st 253 in w) ;load e8 to work ;run next if reg. 3 bit 2 = 1 (statuz z=1) ;sub f-w put in w ;run next if reg. 3 bit 0 = 0 ;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 • +,-,*,/ • 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) – If (bitvar & (1 << 2)) //Alt. 1: test av bit 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) 0xFFAA //Lurigt, heltalsbefordring till int ger: ~0x0055 = 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