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