Cours de Programmation Cible Embarqué PDF

Summary

Ce document est un cours sur la programmation cible embarquée en langage C. Le cours couvre les objectifs, l'introduction aux systèmes embarqués, les fonctions standards ANSI-C, les bibliothèques, le processus de compilation, les éléments de base, les types de données, les chaînes de caractères, la déclaration et l'initialisation, la portée des variables.

Full Transcript

Programmation cible embarqué avec le langage C Par Imen Ahmed [email protected] LISI 3 AU 2024-20251 OBJECTIFS 1. Balayer et revoir les aspects importants et e...

Programmation cible embarqué avec le langage C Par Imen Ahmed [email protected] LISI 3 AU 2024-20251 OBJECTIFS 1. Balayer et revoir les aspects importants et essentiels du langage C qu’on doit maîtriser afin de concevoir le logiciel de base d'un système numérique (système embarqué). 2. Connaître les points forts et les points faibles du langage C. 3. Maîtriser les appels d’E/S de base et formatés en langage C. Intérêt pour les systèmes embarqués. 4. Comprendre comment on développe une application embarquée en langage C à travers des exemples. 2 Chapitre 1: Introduction à la programmation embarqué 3 1. Introduction Qu’est-ce qu’un système embarqué? ❏ Un système embarqué est un système électronique et informatique intégré dans un appareil ou un produit pour accomplir une fonction spécifique. Il est souvent conçu pour être dédié à une tâche particulière. Exemples : Contrôleurs de lave-linge, systèmes de navigation GPS, dispositifs médicaux… Caractéristiques :  Intégration : Généralement intégré dans un produit plus large, comme un véhicule, un appareil électroménager ou un équipement industriel.  Fonction Spécifique : Conçu pour exécuter une ou plusieurs fonctions précises, souvent avec des ressources limitées (mémoire, processeur). Contraintes :  Encombrement (Poids, taille, forme)  Ressources limitées  Consommation d’énergie  Coût … 1. Introduction ❏ La programmation embarquée consiste à écrire des logiciels pour des dispositifs intégrés dans des équipements variés. Ces dispositifs doivent souvent répondre à des contraintes spécifiques telles que des limitations en ressources ou des exigences de performance en temps réel. ❏ Plusieurs langages sont utilisés dans le domaine de la programmation embarquée, chacun avec ses propres avantages et inconvénients :Langage Assembleur, C, C++, Python… ❏ Le langage C est largement utilisé dans la programmation embarquée pour plusieurs raisons : contrôle bas niveau, efficacité, portabilité... ❏ Le langage C n'est pas un nouveau né dans le monde informatique, il a été développé au début des années 70, en 1972 puis 1983 la création du langage C++ : un sur-ensemble du C ❏ Le "C pour l'embarqué" se réfère à l'utilisation du langage C dans le contexte des systèmes embarqués, où les exigences et les contraintes sont spécifiques à ces systèmes. ❏ Il convient parfaitement au développement des pilotes de périphériques spécialisés tels que les convertisseurs analogiques/numériques, les capteurs, etc. ❏ L’American National Standards Institute (ANSI) charge une commission de mettre au point une définition explicite et indépendante machine pour le langage C 5 1. Introduction Pourquoi du C pour l’embarqué ? Indépendant du Processeur & Portabile universel Extensible près de la machine rapide Ce qui est fondamentalement différent lors de la programmation en C embarqué c’est l’état d’esprit : pour les applications embarquées, nous avons besoin d’utiliser de façon optimale les ressources, de coder efficacement les programmes et de satisfaire les contraintes de temps réel. 6 1. Introduction Avantages: Efficacité : C est un langage de bas niveau qui permet un accès direct au matériel, ce qui est essentiel en programmation embarquée. Performance : Les programmes en C sont généralement très rapides et efficaces en termes de ressources. Portabilité : Le code C peut être porté sur différentes plateformes avec peu de modifications. Contrôle : Offre un contrôle détaillé sur les ressources système, la gestion de la mémoire, et les opérations matérielles. Indépendance du Processeur : Fonctionne sur diverses configurations matérielles sans nécessiter de matériel spécifique. Extensibilité : C peut être étendu et enrichi par l'utilisation de bibliothèque de fonctions achetées ou récupérées. Universel : C n'est pas orienté vers un domaine d'applications spéciales comme SQL par exemple Inconvénients: Complexité : La gestion manuelle de la mémoire peut être difficile et source d'erreurs (fuites de mémoire, accès illégaux), nécessite beaucoup d'expérience. Sécurité : Moins de sécurité intégrée par rapport aux langages plus modernes, ce qui peut mener à des vulnérabilités (par exemple, débordements de tampon). 7 1. Introduction Fonctions Standard ANSI-C Norme ANSI-C : La norme ANSI-C définit un ensemble de fonctions et de bibliothèques standardisées pour la programmation en C. Ces fonctions sont conçues pour être universelles et compatibles avec tous les environnements conformes à la norme. Fonctions d'E/S Standard : Les fonctions d'entrée/sortie (E/S) standard en C, comme printf, scanf, fopen, fread, et fwrite, sont définies dans la bibliothèque standard (). Elles sont conçues pour offrir une interface cohérente et portable pour les opérations de lecture et d'écriture. Limitations : La norme ANSI-C inclut un nombre limité de fonctions pour les opérations d'E/S, et certaines opérations spécifiques peuvent ne pas être couvertes par ces fonctions standard. Les fonctionnalités plus avancées ou spécifiques à certains matériels ne sont pas toujours disponibles via les fonctions standard. 8 1. Introduction Les bibliothèques ❏ Une bibliothèque est un ensemble de primitives et/ou de fonctions traitant des opérations homogènes. ❏ Ces bibliothèques sont disponibles dans leur forme précompilée (extension ".LIB"). ❏ Pour pouvoir les utiliser, il faut inclure des fichiers entête (header files d’extension ".H") dans les programmes. ❏ L'instruction #include insère les fichiers entête indiqués comme arguments dans le texte du programme au moment de la compilation: #include stdio.h (Standard Input/Output): Pour les opérations d'entrée et de sortie (I/O) stdlib.h (Standard Library):Pour la gestion de la mémoire, les conversions de types et la gestion des processus string.h (String Handling):Pour la manipulation et la gestion des chaînes de caractères. math.h (Mathematics):Pour les calculs mathématiques avancés time.h (Time and Date):Pour les opérations liées au temps et à la date. 9 2. Le processus de compilation 1 La compilation et la compilation croisée Lorsque nous compilons un projet, nous générons du code exécutable (.exo,.bin,.hex,.elf). Ce code exécutable peut être destiné à plusieurs cibles : Le même processeur que celui sur lequel nous avons réalisé la compilation : On parle de compilation. C'est le cas lorsque nous créons du code que nous exécutons directement sur notre PC. Un autre processeur que celui sur lequel nous avons réalisé la compilation. On parle de compilation croisée (Cross-Compilation). C'est le cas lorsque nous compilons une application à destination d'un Arduino, d'une RaspberryPI ou d'un STM32. 2 Les étapes de la compilation La compilation permet de générer un fichier qui sera exécutable sur un processeur. La compilation est un terme générique qui est en fait découpé en plusieurs étapes. 10 2. Le processus de compilation ❏ Fichier.c > [Preprocesseur] > Fichier.i (Fichier Source) ❏ Fichier.i > [Compilation] > Fichier.s (Fichier Assembleur) ❏ Fichier.s > [Assemblage] > Fichier.o (Fichier Objet) ❏ Fichier.o > [Edition de liens] > Fichier.out (Fichier Exécutable) 11 3. Éléments de base 1- Rappel: bonjour à tous la circonférence est 6.280000 m 12 3. Éléments de base 2- Les types de données élémentaires: ❏ Les deux types standard du langage C sont: Les nombres entiers: signed char, int, long Les nombres réels (flottants): float, double ❏ La déclaration se fait avec les mots clés char, short, int, long, float ou double en fonction de la taille de la variable souhaitée. (8, 16, 32 bits…). Seul l'intitulé "char" possède une taille définie et normalisée sur 8 bits ❏ Un autre type de donnée fondamental est le pointeur, qui représente l'adresse d'une variable. ❏ Toutes les autres structures de données sont dérivées de ces types fondamentaux. Par exemple: Les caractères, les constantes, les booléens… Expl: int a, m ; float b = 2.14 ; char c = “s” ; 13 3. Éléments de base ❏ Pour les variables entières, on peut différencier les nombres "unsigned" (Toujours positif) ou "signed" (positif ou négatif) : 14 3. Éléments de base Pourquoi il existe autant de types différents ? La réponse est toute simple : la taille des Type Taile mémoires était limitée signed char 8 bits Il fallait donc l’économiser au maximum en choisissant le type le plus petit possible. unsigned 8 bits char int 16 bits Si vous utilisez int pour stocker les âges, vous utilisez 4 unsigned int 16 bits octets par âge, ce qui est largement suffisant pour des valeurs allant de 0 à 120. long 32 bits Si vous utilisez char à la place, vous économiseriez de la unsigned 32 bits mémoire (1 octet par âge), ce qui peut être utile si vous avez long un très grand nombre d'entrées et que vous savez que les âges seront toujours entre 0 et 255 float 32 bits double 64 bits 15 3. Éléments de base Les variables n'ont pas de taille normalisées et dépendent complètement du processeur et du compilateur utilisé. Afin de connaître la taille d'une variable, il faut utiliser la fonction sizeof(). On exécute ce code sur trois architectures différentes : Un core i7 (64 bits), un int main(void){ printf("Size of char\t\t: %d octet\n",sizeof(char)); SMT32F446 (32 bits), et un PIC16F (8 bits). printf("Size of short\t\t: %d octets\n",sizeof(short)); printf("Size of int\t\t: %d octets\n",sizeof(int)); printf("Size of long int\t: %d octets\n",sizeof(long int)); printf("Size of long long int\t: %d octets\n",sizeof(long long int)); printf("Size of float\t\t: %d octets\n",sizeof(float)); printf("Size of double\t\t: %d octets\n",sizeof(double)); printf("Size of long double\t: %d octets\n",sizeof(long double)); } 16 3. Éléments de base ❏ Cette multitude de représentation est source de beaucoup d'erreur et empêche la portabilité d'un code. C'est pourquoi on utilise de préférence les types normalisés de la bibliothèque. uint8_t, int8_t, uint16_t, int16_t, uint32_t, int32_t, uint64_t, int64_t 17 3. Éléments de base ❖ Représentation des nombres signés (positifs et négatifs) ❏ On appelle bit de signe, le bit le plus élevé (bit de poids fort ou MSB Most Significant Bit) d'un nombre entier. ❏ Si l'on considère un nombre codé sur un octet, lorsque le bit de signe vaut 0, il s'agit d'un nombre positif. Inversement lorsque ce bit vaut 1, il s'agit d'un nombre négatif. Exemple sur 8 bits : (+5) En binaire, +5 est représenté comme 00000101 : Bit de signe : 0 (indique un nombre positif) (-5) Représentation binaire de 5 : 00000101 Complément à un (inverser les bits) : 11111010 Ajouter 1 : 11111010 + 1 = 11111011 Donc, -5 est représenté comme 11111011 en complément à deux. Bit de signe : 1 (indique un nombre négatif) Valeur : -5 18 Exercice : 1. Convertir des nombres décimaux en binaire a. Représentez le nombre décimal -23 en binaire en utilisant 8 bits (complément à deux ). b. Représentez le nombre décimal +37 en binaire en utilisant 8 bits. 2. Convertir des nombres binaires en décimal a. Convertissez le nombre binaire 10011010 en décimal, en supposant que c'est un nombre signé en complément à deux. b. Convertissez le nombre binaire 00110101 en décimal, en supposant que c'est un nombre signé en complément à deux. 3. On considère en C la déclaration suivante #include... int16_t mon_tableau 19 Combien d'octets sont réservés en mémoire pour mémoriser ce tableau 3. Éléments de base ❖ Notation binaire, décimale, hexadécimale, octal Voici une liste des bases habituellement utilisées en (micro)informatique : Exemple : Le nombre 70 (en notation décimale) est représenté par 1000110 en notation binaire, 0106 en notation octale, 0x46 en notation hexadécimale. 20 3. Éléments de base ❖ Les chaînes de caractères ❏ Les chaînes de caractères se note entre guillemets : "Bonjour!" ❏ Une chaîne de caractères est une suite de caractères (éventuellement vide) entre guillemets. ❏ En mémoire, une chaîne de caractères est une suite de caractères consécutifs et dont le dernier élément est le caractère nul '\0',(pour un texte de N caractères, nous devons prévoir N+1 octets), nous devons indiquer la taille de l'espace à réserver en mémoire pour son stockage. ❏ Une chaîne de caractères est traitée comme un tableau de caractères à une dimension. ❏ Si la taille est non specifiée, elle sera automatiquement déterminée par le compilateur en fonction de la chaîne. char Nom_chaine[taille]; 21 3. Éléments de base ❏ L’accès à une chaîne de caractères peut se faire par deux méthodes : Accès en bloc par le nom de la chaîne : La lecture ou l’écriture de la chaîne se fait en indiquant tout simplement le nom de la chaîne. char ch[]="Bonjour"; printf("le prof a dit: %s", ch ); Le prof a dit: Bonjour Accès caractère par caractère: L'accès à un caractère se fait de la même façon que celui à un élément d'un tableau. char ch[]="Bonjour"; printf("le prof a dit:\t"); for(int i=0;ch[i]!=’\0’;i++) printf("%c",ch[i]); Le prof a dit: Bonjour 22 3. Éléments de base ❖ Déclaration et Initialisation int age = 25; // Entier float temperature = 23.5; // Nombre réel (flottant) char name = "Alice"; // Chaîne de caractères ❖ Portée de variable La position de la déclaration ou de la définition d'une variable détermine sa portée c’est-à-dire sa durée de vie et sa visibilité. Les variables globales sont déclarées en dehors de toute fonction. Les variables locales sont déclarées à l'intérieur des fonctions et ne sont pas visibles à l'extérieur de la fonction dans laquelle elles sont définies. 23 3. Éléments de base Exemple: #include // Variable globale int globalVar = 10; void afficherVariables() { // Variable locale int localVar = 5; printf("Dans la fonction afficher Variables:\n"); printf("Variable globale: %d\n", globalVar); printf("Variable locale: %d\n", localVar); } int main() { // Erreur : printf("Dans la fonction main:\n"); localVar printf("Variable globale: %d\n", globalVar); non visible printf("Variable locale: %d\n", localVar); ici afficherVariables(); return 0; } 24 3. Éléments de base ❏ Pour afficher la valeur d'une variable avec la fonction printf on rajoute un symbole spécial à l'endroit où l'on veut afficher la valeur de la variable: int a = 2; printf("Il vous reste %d minutes", a); ❏ Il est possible d'afficher la valeur de plusieurs variables dans un seul printf printf(format, liste de valeurs) char a=10 ; float b=3.1412; printf(" décimal %d, hexa %x, reel %f " ,a,a,b) ; décimal 10, hexa A , reel 3.1412 25 3. Éléments de base ❖ Règles de nommage des variables Règles Exemples Pas de nombre en début de nom 7variable Pas de caractères spéciaux à l’exception de _ nom-de-variable Pas de mots réservés en C (exp type de variable) int Pas d’accent (à,é,è..) début Pas d’espace nom de variable Nom explicite(très important pour la lisibilité) NomDeVariable tout en minuscule avec _ pour séparer les mots nom_de_variable 26 3. Éléments de base ❖ Fonctions courantes sur les chaines de caractères printf : Affiche des données formatées scanf : Lit des données formatées depuis l'entrée standard (clavier). strlen() : Longueur de la chaîne. strcmp() : Compare deux chaînes. strcat : Concatène deux chaînes de caractères… #include #include #include int main() { int age; int main() { printf("Entrez votre âge: "); char str[] = "Hello, World!"; scanf("%d", &age); printf("Longueur de la chaîne: %lu\n", printf("Vous avez %d ans.\n", age); strlen(str)); return 0; return 0; } } 27 3. Éléments de base #include #include #include #include int main() { char chaine1[] = "Bonjour"; int main() { char chaine2[] = "Salut"; char str1[] = "Pink"; int result1 = strcmp(chaine1, chaine2); char str2[] = " Panther!"; if (result1 == 0) { strcat(str1, str2); printf("Les chaînes '%s' et '%s' sont printf("Chaîne concaténée: %s\n", str1); égales.\n", chaine1, chaine2); } return 0; else { printf("Les chaînes '%s' et '%s' ne sont } pas égales.\n", chaine1,chaine2); } return 0; } Exercice : Écrire un programme qui : 1- Demande à l'utilisateur de saisir deux chaînes de caractères. 2- Affiche la longueur de chaque chaîne. 3- Compare les deux chaînes et affiche si elles sont identiques ou non. 4- Concatène les deux chaînes et affiche le résultat. 28 3. Éléments de base #include #include int main() { char chaine1, chaine2, resultat; printf("Entrez la première chaîne : "); scanf("%99s", chaine1); // Limiter l'entrée à 99 caractères printf("Entrez la deuxième chaîne : "); scanf("%99s", chaine2); printf("Longueur de la première chaîne : %d\n", strlen(chaine1)); printf("Longueur de la deuxième chaîne : %d\n", strlen(chaine2)); // Comparer les deux chaînes if (strcmp(chaine1, chaine2) == 0) { printf("Les deux chaînes sont identiques.\n"); } else { printf("Les deux chaînes sont différentes.\n"); } strcpy(resultat, chaine1); // Copier la première chaîne dans le résultat strcat(resultat, chaine2); // Concaténer la deuxième chaîne printf("Chaîne concaténée : %s\n", resultat); return 0; } 29 4. Opérateurs et expressions int resultat = 0; resultat = 5 / 2; printf ("5 / 2 = %d", resultat); 5 / 2 = 2 float resultat = 0; resultat = 5.0 / 2.0; printf ("5 / 2 = %f", resultat); 5 / 2 = 2.5 30 4. Opérateurs et expressions Ne pas confondre == (test d'égalité) et = (affectation) Préfixe (y=++x) : Incrémente la valeur de x avant d'utiliser la valeur dans l'expression. (x = x + 1; y = x) Postfixe (y= x++) : Utilise la valeur actuelle de x dans l'expression avant d'incrémenter x. (y = x; x = x + 1;) 31 Exercice : Déterminer les valeurs de x et y après l'exécution de code suivant #include int main() { int x = 5; int y; y = x++; printf("x = %d\n", x); printf("y = %d\n", y); return 0; y reçoit 5, x est ensuite } incrémenté à 6 // x = 6 // y = 5 32 4. Opérateurs et expressions L’opérateur conditionnel: c ? X : Y Cette expression est une sorte de si alors sinon sous forme d'expression : si la condition C est vraie alors cette expression vaut x sinon elle vaut y. int age; printf("Entrez votre âge : "); scanf("%d", &age); printf("Statut : %s\n", (age >= 18) ? "Adulte" : "Mineur"); L’opérateur de conversion de type: (type) donnée int i = 10; float f; f = (float) i / 3; // Conversion de `int` à `float` 33 4. Opérateurs et expressions L’opérateur de dimension: Afin de connaître la taille (en octet) d’une variable, on utilise la fonction sizeof() : printf("Taille d'un int : %zu octets\n", sizeof(int)); #include int main() { int myInt; char myString[] = "Hello, World!"; // Taille d'un int printf("Taille d'un int : %zu octets\n", sizeof(myInt)); // Taille d'une chaîne de caractères printf("Taille de la chaîne de caractères myString : %zu octets\n", sizeof(myString)); return 0; } Taille d'un int : 4 octets Taille de la chaîne de caractères myString : 14 octets 34 4. Opérateurs et expressions Manipulation des bits: ❏ Les manipulations de bits sont beaucoup utilisé dans l’embarqué. ❏ Pour contrôler un périphérique matériel on retrouve des registres de 8,16 ou 32 bits qu’il faut modifier AND Bitwise (&): Effectue une opération ET logique sur chaque bit des deux opérandes a & b unsigned int a = 12; // 00001100 en binaire unsigned int b = 7; // 00000111 en binaire unsigned int result = a & b; // Résultat : 00000100 en binaire, soit 4 en décimal OR Bitwise ( | ): Effectue une opération OU logique sur chaque bit des deux opérandes a | b unsigned int a = 12; // 00001100 en binaire unsigned int b = 7; // 00000111 en binaire unsigned int result = a | b; // Résultat : 00001111 en binaire, soit 15 en décimal 35 5- Structures de données complexes: ❏ Parmi les structures de données complexes on trouve : Les tableaux Les structures ❖ Les tableaux Structures de données permettant de rassembler une suite de valeurs de meme type rangées en mémoire les unes à la suite des autres. Indice est le numéro d’une case dans le tableau, il commence par 0. type nomTableau[taille]; 36 5- Structures de données complexes: #include int main() { int T; // Déclaration d'un tableau d'entiers avec 100 éléments int i; // Initialisation du tableau avec des valeurs pour l'exemple for (i = 0; i < 100; i++) { T[i] = i; // Exemple : remplissage du tableau avec des valeurs de 0 à 99 } // Affichage des 10 premiers éléments du tableau printf("Les 10 premiers éléments du tableau T sont :\n"); for (i = 0; i < 10; i++) { printf("%d\t", T[i]); // Affichage de chaque élément suivi d'une tabulation } // Saut de ligne après l'affichage des éléments printf("\n"); return 0; } 37 5- Structures de données complexes: Les tableaux sont conçus pour stocker des éléments de même type. Cependant, il peut être nécessaire de regrouper des données de types et de natures différents. Pour ce faire, on peut utiliser des structures, qui permettent de rassembler ces données disparates sous un même nom de variable. ❖ Les structures Une structure est définie avec le mot-clé struct suivi d'un nom de structure et de la liste des membres de la structure, chacun avec son propre type. struct NomStructure { type1 membre1; type2 membre2; // autres membres }; 38 5- Structures de données complexes: #include #include // Définition de la structure struct Etudiant { char nom; int age; float moyenne; }; int main() { // Création et initialisation d'une variable de type struct Etudiant struct Etudiant etudiant1; // Affectation des valeurs aux membres de la structure strcpy(etudiant1.nom, "Alice Dupont"); // Utilisation de strcpy pour copier une chaîne etudiant1.age = 20; etudiant1.moyenne = 15.75; // Affichage des valeurs des membres de la structure printf("Nom de l'étudiant : %s\n", etudiant1.nom); printf(" ge de l'étudiant : %d\n", etudiant1.age); printf("Moyenne de l'étudiant : %.2f\n", etudiant1.moyenne); return 0; } 39 6. Les structures de controle ❖ Les structure de contrôle Les structures de contrôle permettent de diriger le flux d'exécution du programme en fonction de conditions, de boucles et de branchements.(if-else,switch, for, while, break..) 1. Structures de Contrôle Conditionnelles 2. Structures de Contrôle Iteratives if-else for #include #include int main() { int number = -5; int main() { if (number >= 0) { for (int i = 0; i < 5; i++) { printf("Le nombre est positif ou printf("i = %d\n", i); nul.\n"); } } else { printf("Le nombre est négatif.\n"); return 0; } } return 0; } 40 Exercice : Écrire un programme qui demande à l'utilisateur de saisir un nombre entier n. Le programme doit ensuite calculer et afficher la somme de tous les nombres pairs de 1 à n. #include int main() { int n, somme = 0; // Demande à l'utilisateur d'entrer un nombre printf("Entrez un nombre entier: "); scanf("%d", &n); // Vérifie si n est positif if (n < 1) { printf("Veuillez entrer un nombre entier positif.\n"); } else { // Boucle pour calculer la somme des nombres pairs for (int i = 1; i

Use Quizgecko on...
Browser
Browser