Vous êtes sur la page 1sur 50

Programmation C pour systmes embarqus

Sylvain MONTAGNY sylvain.montagny@univ-savoie.fr Btiment chablais, bureau 13 04 79 75 86 86


Retrouver tous les documents de Cours/TP sur le site www.master-electronique.com

Prsentation des cours : Sommaire


l

Cours : 10.5 h en 7 sances


l l l

1re partie : Rappel sur le langage C (Exercices de base) 2me partie : La programmation en langage C avance 3me partie : Prsentation du TP : Ralisation dun algorithme de compression de donnes.

Universit de Savoie

Prsentation TP
l TP

: 20 h en 5 sances

Le but de ce projet est d'crire un programme de compression de fichiers textes, sans perte d'information. On demande galement d'crire un dcompresseur qui devra restaurer le fichier original. Lalgorithme propos ici est l'algorithme de Huffman.

Universit de Savoie

Examen

Une note :
l l

18 points : Examen de TP avec une partie thorique. 2 points proviennent du travail fait en TP

Universit de Savoie

1re partie : Rappel sur le langage C (exercices de base)


l

Donner lexcution du code suivant :


#include <stdio.h> #include <stdlib.h> int main(void){ unsigned char i; unsigned char tab[5]={1,2,4,8,16}; for (i=0;i<5;i++) { printf("Le %d lement est %d\n",i+1,tab[i]); } return EXIT_SUCCESS; }

Universit de Savoie

1re partie : Rappel sur le langage C (exercices de base)


l

Donner lexcution du code suivant :


#include <stdio.h> int main() { int i,j; for(i=0;i<5;i++){ for(j=5-i;j<5;j++){ printf("++"); } printf("\n"); } return EXIT_SUCCESS; }

Universit de Savoie

1re partie : Rappel sur le langage C (exercices de base)


l

crire une fonction C calculant la longueur d'une chane de caractres, donne en argument. Le prototype de la fonction est le suivant :

int longueur(char *s)

Universit de Savoie

1re partie : Rappel sur le langage C (exercices de base)


l

crire une fonction C calculant la longueur d'une chane de caractres, donne en argument.
#include <stdlib.h> int longueur(char *s) { int n = 0; while (s[n] != '\0') { n++; } return n; }

Universit de Savoie

1re partie : Rappel sur le langage C (exercices de base)


Soit un texte donn par une chane de caractres. Le but est de compter le nombre d'occurrences de chaque lettre minuscule. Question 1 : Raliser les dclarations suivantes :
l

Le texte (chane de caractre constante) sera dclar dans un tableau nomm ch . Vous afficherez la chane de caractre lcran. Un tableau d'entiers statique nomm occ . pour compter les occurrences de chaque lettre de lalphabet dont la taille est fixe par une constante (correspondant au nombre de lettre de lalphabet). Un pointeur nomm p pour parcourir le texte.

Universit de Savoie

1re partie : Rappel sur le langage C (exercices de base)


#include <stdio.h> #define NB_LETTRE 26; void main(void) { /* dclaration d'une chane <=> tableau de caractres. */ char ch[]="ceci est une chane de test"; /* dclaration d'un pointeur sur une chane de caracteres. */ char *p = ch; /* dclaration d'un tableau de 26 cases */ int occ[NB_LETTRE]; printf("Chane en mmoire : %s\n",ch); }

Universit de Savoie

1re partie : Rappel sur le langage C (exercices de base)


l

Question 2 : Initialiser le tableau doccurrence zro :


/* initialisation du tableau des occurrences 0. */ int i=0; for (i=0; i<NB_LETTRE;i++) occ[i]=0;

Universit de Savoie

11

1re partie : Rappel sur le langage C (exercices de base)


l

Question 3 : Compter les occurrences jusqu la fin de la chane de caractre :


/* parcours de la chane jusquau \0 */ while (*p != '\0') { if ( (*p >= 'a) && (*p <= 'z) ) { occ[*p-'a'] = occ[*p-'a'] + 1; } p++; }

Universit de Savoie

12

1re partie : Rappel sur le langage C (exercices de base)


l

Question 4 : Afficher le contenu du tableau occ

for (i=0; i<nb_lettres; i++) { printf("Nombre de %c : %d\n", 'a'+i,occ[i]); }

Universit de Savoie

13

2me partie : La programmation en langage C avance


l l l l l l l l l l l l l l l l

Lisibilit du code, les types de variables, les typedef, occupation mmoire, port des variables, les oprateurs, manipulation de registre, les structures, les pointeurs, le main(), pointeurs, la pile, type de fonction, allocation dynamique, les options doptimisations la compilation, les erreurs classiques du C

14

Lisibilit du code C (1)


l

Exercice :
Raliser un code qui imprime les N premiers lments d'un tableau dentier A[] en insrant un espace entre les lments et en commenant une nouvelle ligne aprs chaque dixime chiffre.
void main(void){ int A[80],N,i; scanf(%d,&N); for (i=0; i<N; i=i+1){ printf("%d", A[i]); if ((i%10) == 9) printf("\n"); else printf(" "); }
15

Universit de Savoie

Lisibilit du code C (3)


l

Voici une deuxime faon de coder, trs pratique mais beaucoup moins lisible.
void main(void){ int A[80],N,i; scanf(%d,&N); for (i=0; i<n; i++) printf("%d%c", a[i], (i%10==9)?'\n':' '); }

Universit de Savoie

16

Lisibilit du code C (4)


l

Quelques quivalences parfois viter


Op. Fonction += Addition et affectation
-= Soustraction et affectation *= Multiplication et affection /= Division et affectation %= Modulo et affectation ++ Incrmentation Exemple

nombre += 5;
nombre -= 6; nombre *= 3; nombre /= 2; nombre %= 4; nombre++;

Equivalence nombre=nombre+5

nombre = nombre % 4 nombre = nombre + 1; nombre = nombre - 1; y x x y = = = = x x + 1 x + 1 x


17

-- Dcrmentation nombre--; y = x++ y = ++x

Universit de Savoie

Lisibilit du code C (5)


#include <stdio.h> main(t,_,a)char*a;{return!0<t?t<3?main(-79,-13,a+main(-87,1_,main(-86,0,a+1)+a)):1,t<_?main( t+1, _, a ):3,main( -94, 27+t, a )&&t == 2 ?_ <13 ?main ( 2, _+1, "%s %d %d\n" ):9:16:t<0?t<-72?main( _, t,"@n'+,#'/*{}w+/w#cdnr/+,{}r/*de}+,/*{*+,/w{%+,/w#q#n+ ,/#{l,+,/n{n+,/+#n+,/#;#q#n+,/+k#;*+,/'r :'d*'3,}{w+K w'K:'+}e#';dq#'l q#'+d'K#!/+k#;q#'r}eKK#}w'r}eKK{nl]'/#;#q#n'){)#}w'){){nl]'/ +#n';d}rw' i;# ){nl]!/n{n#'; r{#w'r nc{nl]'/#{l,+'K {rw' iK{;[{nl]'/w#q#n'wk nw' iwk{KK{nl]!/w{%'l##w#' i; :{nl]'/*{q#'ld;r'}{nlwb!/*de}'c ;;{nl'{}rw]'/+,}##'*}#nc,',#nw]'/+kd'+e}+;#'rdq#w! nr'/ ') }+}{rl#'{n' ')# }'+}##(!!/"):t<-50?_==*a ?putchar(31[a]):main(-65,_,a+1):main((*a == '/') + t, _, a + 1 ):0<t?main ( 2, 2 , "%s"):*a=='/'||main(0,main(-61,*a, "!ek;dc i@bK'(q)-[w]*%n+r3#l,{}:\nuwloca-O;m .vpbks,fxntdCeghiry"),a+1);}
The International Obfuscated C Code Contest >> http://www.ioccc.org/

Lisibilit du code C (6)


l

Rgles respecter :
l l l

Mettre des commentaires explicites Ne pas trop compresser le code Respecter une homognit dans votre faon de coder. Organiser la mise en page de votre code, ou respecter celle dj existante.

Universit de Savoie

19

Les types de variables (1)


char = 1 octet (signed ou unsigned) l Int, long, double, float dpendent de la cible processeur utilise.
l

Afin de connatre la taille (en octet) dune variable, on utilise la fonction sizeof() :
l

printf( int=%d octets , sizeof(int));

Note : Il nexiste pas de type Boolen en C

Universit de Savoie

20

Les types de variables (2)


l

Cas dune compilation pour processeur 32 bits

l l

Voir le cas dun compilateur C pour PIC16F ou PIC18F (microchip) Voir le cas dun compilateur C pour DSP TMS320 (Texas Instruments) (page suivante)

Universit de Savoie

21

Les types de variables (3)

Universit de Savoie

22

Les types de variables (4)


l

Donner la reprsentation binaire des nombres suivants :


l l l l

char a=64; unsigned char b=64; char c=128; unsigned char d=128;

Quel est laffichage des fonctions suivantes?


l l l l

printf(%d printf(%d printf(%u printf(%u

, , , ,

a); c); a); c+a);

Note : Une dclaration est signed par dfaut gnralement. Note : %d -> entier signed / %u -> entier unsigned
Universit de Savoie 23

Les types de variables (5)


l

Conversion explicite :
La conversion de type consiste transformer un type de valeur en un autre, en respectant la syntaxe suivante (<type>) <expression>

Conversion implicite :
Lorsque les deux oprandes sont de type diffrent, le compilateur prvoit une conversion implicite suivant l'ordre : { char -> int -> long -> float -> double } et { signed -> unsigned }

Universit de Savoie

24

Les types de variables (6)


Dcrivez le conversion du type, ainsi que les affectations du code suivant :
int main(void) { int n, m, l; double d; d = 5; n = (int) 3.4; n = 1; m = 5; d = 2; l = (int) (m / d); d = n / m; d = n / ((double) m); d = 'A' * 6.0 m + 0xA2CL; return 0; }
Universit de Savoie 25

Porte des variables (1)


Globale / Locale
l

Les variables locales sont dclares dans la fonction les utilisant. les variables globales en dbut de programme. Le linker attribue une adresse fixe et dfinitive ces dernires pendant toute la dure du programme. L'utilisation de variables locales amliore considrablement la lisibilit et la scurit des donnes dans un programme en C. Les variables locales sont par dfaut "automatiques" , cres l'entre de la fonction qui les dclare et dtruites la sortie. Pour cela elles sont ranges dans la pile, zone mmoire particulire, destine primairement au stockage des donnes de retour des sous programmes.

Universit de Savoie

26

Porte des variables (2)


l

static : permet une variable locale dtre persistante et donc de conserver sa valeur pendant les appels successifs de la fonction.
#include <stdio.h> void f(void) { static int i = 0; /* i ne sera initialis quune fois*/ int j = 0; /* j sera initialis chaque fois */; i++; j++; printf("i vaut %d et j vaut %d.\n", i, j); } int main(void) { f(); f(); f(); return 0; }
Universit de Savoie 27

Porte des variables (3)

Cas des variables globales et Static . Une variable globale est dj persistante. Lobjectif de la nommer en static est simplement de la privatiser au fichier o elle est dclare. Cest--dire quelle ne pourra pas tre utilise depuis un autre fichier.

Universit de Savoie

28

Porte des variables (4)


l

extern : permet de spcifier que la variable a t dclarer dans un autre fichier. Si on omet ce terme, une nouvelle variable est crer avec une nouvelle allocation mmoire.
/* File : ext.c */ #include <stdio.h> void next(void); void next1(void); int a1=1; /* definition of external (non static)*/ void main(void){ a1=2; printf("a1=%d\n",a1); next(); next1(); printf("a1=%d\n,a1); }

// a1=2

29

Porte des variables (5)


/* File file1.c */ int b1=0; void next(void) { char a1; a1='a'; b1=77; } /* File file2.c */ extern int a1; void next1(void) { float b1; b1=19.2; a1=13; }

30

Qualificateur de variables (1)


l

Le C dfinit des qualificateurs pouvant influer sur une variable :


l

const : pour dfinir une variable dont la valeur ne doit jamais changer ; volatile : dsigne une variable dont les accs ne doivent pas tre optimiser par le compilateur. Cette variable sera relue depuis son emplacement dorigine chaque accs. En effet, cela est important lorsque dautre sources (priphrique matriel, processus, etc) accde la variable en mme temps que notre programme.

Une variable peut avoir plusieurs qualificateurs


Universit de Savoie 31

Qualificateur de variables (2)


Qualificateur 'const'
La classe const indique au compilateur que la valeur de la variable ne doit pas changer. Il est donc impratif d'assigner une valeur la dclaration de la variable, sans quoi toute tentative de modification ultrieure entranera une erreur de la part du compilateur : tudier les codes suivants :

const int i = 0; i = 1;

Universit de Savoie

32

Qualificateur de variables (3)


void fonction( const char * pointeur ) { pointeur[0] = 0; pointeur = "Nouvelle chane de caractres"; } char * const pointeur = "Salut tout le monde !"; pointeur = "Hello world !"; const char * const pointeur = "Salut tout le monde !"; pointeur = "Hello world !"; pointeur[0] = 0;

Universit de Savoie

33

uint8_t * pReg = (uint8_t *) 0x1234; // Wait for register to become non-zero while (*pReg == 0) { } // Do something else

Qualificateur de variables (4)


Qualificateur 'volatile'
int * pReg= (int *) 0x 1234; while (* pReg==0) { } >> Le compilateur va optimiser la boucle while en considrant que la lecture de *pReg nest jamais modifie. En ralit, elle peut tre modifie par :
l l l

Un priphrique dentre/sortie mapp en mmoire Une interruption Une autre tche

Universit de Savoie

34

valuation des expressions boolennes (1)


l

Le C ne possde pas de type boolen ddi. Dans ce langage, n'importe quelle valeur diffrente de zro est considre vraie, zro tant considr comme faux. Ce qui veut dire que n'importe quelle expression peut tre utilise l'intrieur des tests (entier, rels, pointeurs, tableaux, etc.). Cela peut conduire des expressions pas toujours trs claires, comme :
int a; a = une_fonction(); if (a) { /* ... */ }

On prfrera :
int a; a = une_fonction(); if (a != 0) { /* ... */ }

Attention :
int a = 0; b = 2; if (a = b) { /* Le code qui suit sera toujours excut ... */ }
Universit de Savoie 35

valuation des expressions boolennes (2)


Les oprateurs logiques de comparaisons (&& et ||, similaires smantiquement leur quivalent binaire & et |) ont une excution totalement diffrente. l Dans le cas du ET logique (&&), si l'oprande gauche s'value faux (valeur zro), on sait dj que le rsultat du ET sera faux et donc ce n'est pas la peine d'valuer l'oprande droite. De la mme manire si l'oprande gauche d'un OU logique (||) est valu vrai, le rsultat sera aussi vrai (valeur !=0) et donc l'valuation de l'oprande droite est inutile.
l if (z != 0 && a / z < 10) { printf("Tout va bien\n"); }

Universit de Savoie

36

Les manipulations de bits (1)


l

Les manipulations de bits sont beaucoup utilises dans lembarqu. Pour contrler un priphrique matriel, on retrouve des registres de 8, 16 ou 32 bits quil faut modifier. Mettre 1 le bit 4 de a :
Unsigned int a = 0x000F; /* 0000 0000 0000 1111 */

Mettre zro le bit 3 de a :


Unsigned int a = 0x000F; /* 0000 0000 0000 1111 */

Faire une fonction int set_bit(int mot, int nbr) qui


retourne le mot modifi lemplacement nbr.

37

Les manipulations de bits (1)


l

Les manipulations de bits sont beaucoup utilises dans lembarqu. Pour contrler un priphrique matriel, on retrouve des registres de 8, 16 ou 32 bits quil faut modifier. Mettre 1 le bit 4 de a :
unsigned a = 0x000F; /* 0000 0000 0000 1111 */ unsigned b = 0x0010; /* 0000 0000 0001 0000 */ unsigned c = a | b; /* 0000 0000 0001 1111 soit 0x001F */

Mettre zro le bit 3 de a :


unsigned a = 0x000F; /* 0000 0000 0000 1111 */ unsigned b = 0xFFF7; /* 1111 1111 1111 0111 */ unsigned c = a & b; /* 0000 0000 0000 0111 soit 0x0007 */
Universit de Savoie 38

Les manipulations de bits (2)


l

Tester si le bit 2 de a est 1 :


unsigned a = 0x000F; /* 0000 0000 0000 1111 */

Tester si le bit 3 de a est 1 et si le bit 15 est 0 :


unsigned a = 0x000F; /* 0000 0000 0000 1111 */

39

Les manipulations de bits (2)


l

Tester si le bit 2 de a est 1 :


unsigned a = 0x000F; /* 0000 0000 0000 1111 */ if (a & (1 << 2)) { printf("bit 2 = 1"); } else { printf("bit 2 = 0"); }

Tester si le bit 3 de a est 1 et si le bit 15 est 0 :


unsigned a = 0x000F; /* 0000 0000 0000 1111 */ if ( a & (1 << 3)!=0 && a&(1<<15)==0 ) { printf("bit 2 = 1 et bit 15=0"); } else { printf("bit 2 = 1 et bit 15=0 nest pas vrifi"); }
40

Le main()
l

Le main() est le point dentre dune application. Dans un systme embarque sans systme dexploitation, le point dentre du programme sera prcis dans la phase ddition de liens par linitialisation du vecteur dinterruption nomm RESET.

Universit de Savoie

41

A quoi sert un pointeur ?

Universit de Savoie

42

Les tableaux (1)


l

Un tableau est un regroupement conscutif de donne de mme type et de taille fixe.


// Tableau 2 dimensions void main(void){ int tableau[4][3]; int i,j; for(i=0;i<4;i++){ for(j=0;j<3;j++){ tableau[i][j]=0; } } }
43

// Tableau 1 dimension void main(void){ int tableau[4]; int i; for(i=0;i<4;i++){ tableau[i]=0; } }

Universit de Savoie

Les tableaux (2)


tableau[0] tableau[1] tableau[2] tableau[3] tableau[0][0] tableau[0][1] tableau[0][2] tableau[1][0] tableau[1][1] tableau[1][2] tableau[2][0] tableau[2][1] tableau[2][2] tableau[3][0] tableau[3][1] tableau[3][2]
Universit de Savoie 44

Les tableaux (3)


l l

Passage de tableaux en paramtre des fonctions. Un tableau nest jamais pass en paramtre, cest son adresse qui est fournie.

Universit de Savoie

45

Organisation logicielle (1)


0xFFFFFFFF stack SP (Stack Pointer)

address space

heap (dynamically allocated) data segment Data : (static and global) code segment (=program) PC (Program Counter)

0x00000000

Universit de Savoie

46

Organisation logicielle (2)


l l

Code segment : Emplacement ou se trouve le code compil. Data segment :


l

Data : contient toutes les variables static et globales (initialises ou non) Heap : Le tas est gr dynamiquement. Cest une zone de donne qui grossi la rservation de zone mmoire (malloc) et qui se rduit lors de la libration (free).

Stack : Cest une zone de stockage de type LIFO. Elle contient les adresses de retour des fonctions et les variables locales. Cette zone mmoire est beaucoup plus rapide que lutilisation du Heap.
Universit de Savoie 47

Organisation logicielle (2)


Imposer une adresse physique pour une variable ou une constante
l

Les registres des microcontrleurs sont des adresses imposes par le concepteur du C, or le linker d'un compilateur C a le contrle total des adresses, il choisit ou sont ranges variables et constantes. On peut aussi imposer une adresse une variable. Attention, il faut tre certain que vous soyez le seul utiliser cette adresse pour ne pas crer derreur de segmentation.

#define mamem *(unsigned char *)0x80 char c; void main (void){ mamem = 0xAA; c=mamem; }
48

Optimisation du code (1)


l

Dans le contexte de lembarqu, il est important de connatre les options de compilation doptimisation. Il y a en effet un compromis trouver entre la taille de lexcutable produit et le temps dexcution.

Universit de Savoie

49

Optimisation du code (2)


l

Option -O0 (niveau 0)


l l l l

Allocates variables to registers Performs loop rotation Eliminates unused code Simplifies expressions and statements

Option -O1 (niveau 1)


l l l

Performs all -O0 optimizations, and: Removes unused assignments Eliminates local common expressions

Option -O2 (niveau 2) (default optimization level)


l l

Performs all -O1 optimizations, and: Performs loop optimizations


Universit de Savoie 50