Développement logiciel sur micro-contrôleurs PIC en C Langage C Développement logiciel sur micro-contrôleurs PIC en C D’après Christian Dupaty, Académie d'Aix-Marseille
FLUX DE DONNEES D’UN COMPILATEUR C Bibliothèques pré compilées (fichiers objet) #include <stdio.h> main() { puts(" Bonjour à tous "); } Bibliothèques en C (texte) *.c Fichiers header *.h Editeur de lien LINKER Lie (donne des adresses aux fonctions) tous les fichiers objets et crée un fichier exécutable Préprocesseur Remplace les #define et effectue les #include Compilateur C Transforme le fichier C en un fichier objet (code machine), les fonctions pré compilées sont déclarées dans les fichiers *.h Fichier source C contenant la fonction main Fichier de symboles pour debug Programme exécutable FLUX DE DONNEES D’UN COMPILATEUR C
Syntaxe du C #include <stdio.h> #define pi 3.14 float d,c; Header de la bibliothèque standard in/out. (pour printf) #include <stdio.h> #define pi 3.14 float d,c; int main() { d=2.0 ; c=pi*d ; puts("bonjour à tous\n"); printf("la circonférence est %f m\n",c); } Equivalence : Le pré-processeur remplacera tous les pi par 3.14 Déclaration de deux variables réelles globales En tête du programme principal Début de la fonction main Calculs Appel de la fonction puts (envoie une chaîne de caractères sur le périphérique de sortie) appel de la printf (affiche des chaînes formatés, ici c est affiché sous format réel) Fin de la fonction main
La syntaxe du C – allumer une led Librairies : les fichiers « header » *.h contiennent en général des équivalences ou les prototypes des fonctions pré-complilées ou non : ici essai.h contient les configurations des fusibles du µC. #include "essai.h" void init_micro(); void main() { init_micro(); output_low(PIN_A0); } void init_micro() setup_adc_ports(NO_ANALOGS); setup_adc(ADC_OFF); setup_psp(PSP_DISABLED); setup_spi(FALSE); setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); setup_timer_1(T1_DISABLED); setup_timer_2(T2_DISABLED,0,1); setup_comparator(NC_NC_NC_NC); setup_vref(VREF_LOW|-2); Prototype : c’est la déclaration d’une fonction, il indique au compilateur le type de la fonction et ses paramètres de passage. En tête de la fonction principale (main) Appel de la fonction init_micro. (pas de paramètre d’entrée) Appel de la fonction output_low. (permet de mettre un bit à 0, le paramètre d’entrée est l’adresse du bit) christian.dupaty@ac-aix-marseille.fr
Les types de données standard Longueur Domaine de valeurs signed char ou char 8 bits -128 à 127 unsigned char 0 à 255 signed int ou int 16 bits -32768 à 32767 unsigned int 0 à 65535 long int 32 bits -2 147 483 648 à 2 147 483 647 unsigned long int 0 à 4 294 967 295 float ±3.4 * (10-38) à ± 3.4 * (10+38) double 64 bits ± 1.7 * (10-308) à ± 1.7 * (10+308) void - vide christian.dupaty@ac-aix-marseille.fr
Les types de données propres à PICC Par défaut, les types entiers (int, char) de base sont non signés! Ils peuvent être précédés de signed pour forcer le type signé. Type Longueur Domaine de valeurs int1 ou short 1 bit 0 ou 1 char 8 bits 0 à 255 int ou int8 int16 ou long 16 bits 0 à 65535 int32 32 bits 0 à 4 294 967 295 float ± 3.4 * (10-38) à ± 3.4 * (10+38) void - vide
Exemples de déclaration char tata,blabla,alea ; int table[100] ; char tableau[ ]={10,0x1c,’A’,55,4} char *p ; trois caractères tableau de 100 entiers le symbole * désigne un pointeur sur un type défini p est un pointeur sur des caractères Remarque: un nombre entier en hexadécimal est précédé de 0x ou 0X, (0x1FB9) un nombre entier en décimal n'a pas besoin de préfixe un nombre réel se note 13.145 ou 1.3145e+1. Dans les compilateurs pour µC: notation binaire 0b11010001
Equivalences directive #define Les équivalences sont remplacées par leur valeur par le pré-processeur #define pi 3.14 #define fruit pomme
Constantes elles sont rangées dans la ROM et ne sont donc pas modifiables. const int i=16569, char c=0x4c ; const float pi=3.14; Le mot réservé « const » définit une constante
VARIABLES LOCALES ET GLOBALES Les variables sont stockées en RAM afin d’être modifiables au cours du programme. Elles peuvent être à une adresse fixe (static) ou dans une pile (volatile). GLOBLALES LOCALES soit à une adresse fixe (statique) soit dans une pile LIFO (automatique) Déclarées en dehors d’une fonction toujours statiques Déclarées dans une fonction static char toto; char tata; ou auto char tata;
Branchement : if - else Condition du test : ==, <,>,<=,>=, !=,&&,|| … if (A>B) printf(“ A est supérieur à B”); else printf(“A est inférieur ou égal à B”); … si (A>B) alors afficher(“ A est supérieur à B”) sinon afficher(“A est inférieur ou égal à B”)
Boucle WHILE i 0 i=0; tant que (i<100) while (i<100) faire: { a=a+i; i++ ; } i 0 tant que (i<100) faire: a a+i i i+1 Si la condition de boucle est fausse au départ la boucle n’est jamais effectuée
Boucle DO WHILE do { faire: a=a+i; a a+i i++ ; i i+1 } while (i<100) faire: a a+i i i+1 tant que (i<100) Même si la condition de boucle est fausse au départ la boucle est effectuée au moins une fois
Branchement switch-case { case '+' : resultat=a+b;break; case '-' : resultat=a-b;break; case '*' : resultat=a*b;break; case '/' : resultat=a/b;break; default : resultat=a+b; } suivant la valeur de (c ) début suivant si '+' : resultat a+b si '-' : resultat a-b si '*' : resultat a*b si '/' : resultat a/b par default : fin suivant Cette structure est une extension de la structure alternative si..alors..sinon et permet une meilleur compacité du code.
Boucle FOR for (i=0 ;i<100 ;i++) { a=a+i; printf("%d\n",a); } Action(s) de départ Condition pour rester dans la boucle Action(s) à effectuer en dernier dans la boucle for (i=0 ;i<100 ;i++) { a=a+i; printf("%d\n",a); } Action(s) à effectuer dans la boucle peut se traduire par: i 0 tant que (i<100)) faire a a+i afficher_valeur(a) i i+1 Cette structure est une extension de la structure répétitive tant que … faire et permet une meilleure compacité du code.
Contrôle des boucles break permet de sortir de la boucle en cours (for, while, do while, switch) continue permet de sauter directement à l’itération suivante d’une boucle for(i=0 ;i<100 ;i++) { if (i<50) continue else a=a+i; } exit permet de quitter directement le programme (inutile sur micro contrôleur) christian.dupaty@ac-aix-marseille.fr
POINTEURS char *toto ; déclare un pointeur toto sur un caractère Ce sont des variables qui contiennent l’adresse d’une autre variable. Sur micro-contrôleur un pointeur est une valeur sur 16bits. Un pointeur est déclaré par une * précédée du type de donnée pointée Le signe & devant une donnée indique l’adresse de celle ci et sa valeur. char *toto ; déclare un pointeur toto sur un caractère float *tata ; déclare une pointeur tata sur un réel. Au sein d'un programme *toto désigne la valeur pointée par toto, alors que toto désigne l'adresse à laquelle est stockée cette valeur. L'intérêt des pointeurs est de manipuler des adresses donc des zones entières de données comme par exemple une chaîne de caractères.
manipulation de pointeurs On pourra se servir des pointeurs pour accéder directement à un port du µC: // Une led est câblée sur PB4, allumée sur un état bas char *portB; //portB est un pointeur sur un octet. portB = 0x06; //on définit l'adresse du pointeur ici le portb à l'adresse $06 while(true) { *portB=0b11111111; //on fait clignoter la led. delay_ms(300); *portB=0b11101111; delay_ms(600); } Sous PICC, il existe plusieurs autres possibilités pour accéder aux ports ou aux registres du µC. Celle-ci est plus générale et plus transposable à d'autres compilateurs et d'autres marques de µC.
TABLEAUX int chiffres[ ]={1,2,4,8,16,32,64}; Un tableau est un regroupement de variables de même type C'est une façon plus commode, dans certains cas, d'utiliser les pointeurs. int chiffres[ ]={1,2,4,8,16,32,64}; int TAB[20]={1,12,13,-100}; float toto[10]; char TATA[2][3]={{1,2,3},{4,5,6}} le tableau est affecté avec les valeurs entre { } la taille du tableau est automatiquement ajustée à 7 entiers. TAB est un tableau de 20 entiers dont seuls les 4 premiers sont affectés TAB représente l'adresse de début du tableau, pour accéder aux différentes valeurs du tableau, on utilise un indice qui démarre à 0, ici TAB[0] vaut 1, TAB[1] vaut 12, TAB[2] vaut 13 etc … toto est tableau de 10 réels sans affectation. TATA est un tableau à 2 dimensions, on utilise 2 indices.
Chaînes de caractères Ce sont des tableaux de caractères codés en ASCII finissant par la valeur $00, une chaîne est entourée de " char message[ ]= "bonjour"; char message[ ]={‘b’,’o’,’n’,’j’,’o’,’u’,’r’,0x00} ; deux façons différentes de déclarer et d'affecter une chaîne de caractères
Présentation de PIC C PIC C : un environnement de développement en C complet pour PIC. (éditeur, compilateur, débugger, moniteur rs232 …) un nombre assez important de fonctions intégrées et de bibliothèques. prise en main rapide Ses inconvénients: On notera surtout un non respect de la norme C ANSI (comme on l'a déjà vu pour les types), des fonctions parfois mal documentées
L'utilisation de PIC C PIC C comprend un "wizard" (assistant) qui permet de se passer de connaître parfaitement les registres et les bits de configuration. On choisit: le µC les ports de communication (RS232, SPI, I²C) les timers les entrées analogiques et le format (8 bits ou 10 bits) les interruptions utilisées les composants connectés Cet assistant crée automatiquement le bout de programme nécessaire qu'il serait fastidieux d'écrire à la main.
L'utilisation de PIC C (suite) On se retrouve avec un texte de ce type: #include "C:\Program Files\PICC\my examples\test.h" void main() { setup_adc_ports(NO_ANALOGS); setup_adc(ADC_OFF); setup_psp(PSP_DISABLED); setup_spi(SPI_MASTER|SPI_L_TO_H|SPI_CLK_DIV_4); setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1); setup_timer_1(T1_DISABLED); setup_timer_2(T2_DISABLED,0,1); setup_comparator(NC_NC_NC_NC); setup_vref(FALSE); } l'assistant a créé un fichier .h dans lequel se trouve les configurations l'assistant a placé au début du programme principal toutes les initialisations nécessaires
Voir texte du TP et notice de CCS Pratique de PIC C TP1 Voir texte du TP et notice de CCS
Entrées/sorties caractères Les deux fonctions d’E/S sur caractère Elle sont définies pour le matériel support des communications char getchar(void) int putchar(char) Lit un caractère en entrée (CLAVIER par exemple) Envoie un caractère (LCD par exemple)
Entrées/sorties Chaînes A partir de getchar et putchar void puts(char *chaîne) ; char *gets(char *chaîne) ; affiche une chaîne de caractères saisie une chaîne de caractère finie par un RC et retourne un pointeur sur le premier caractère de cette chaîne
PRINTF printf(format, liste de valeurs) affichera : char a=10 ; float b=3.1412 printf(" décimal %d, hexa %x, reel %f " ,a,a,b) ; affichera : décimal 10, hexa A, reel 3,1412 sprintf(chaîne, format, liste de valeurs) écrit dans chaîne
Formats sur printf \ n nouvelle ligne %c (char) %s (chaîne de caractères, jusqu'au \0) %d (int) %u (entier non signé) %x ou X (entier affiché en hexadécimal) %f (réel en virgule fixe) %p (pointeur) % (pour afficher le signe %) \ n nouvelle ligne \ t tabulation \ b backspace \ r retour chariot \ f form feed \ ' apostrophe \ \ antislash \ " double quote \ 0 nul christian.dupaty@ac-aix-marseille.fr
Bibliothèques standards C ANSI ctype.h trouver les types ex: isdigit (chiffre) ou islower limits.h indique les limites des types string.h traitement sur les chaînes math.h fonctions mathématiques stdlib.h conversion de chaines (atoi atof) génération d’un nombre aléatoire (rand, srand) allocation dynamique de mémoire (malloc, calloc), tri (qsort) time.h fonctions liée à l’heure et à la génération de nombre aléatoires christian.dupaty@ac-aix-marseille.fr
Opérateurs unaires () Appel de fonction [] Indice de tableau tableau[3]=5; ! Négation logique (NOT) ~ Complément binaire bit à bit b=~a - Moins unaire b=-a; + Plus unaire b=+a; ++ Pré ou postincrément b=a++; -- Pré ou postdécrément b=a--; & Adresse de b=&a; * Indirection b=*a;
Opérateurs binaires * Multiplication c=a*b; / Division c=a/b; + Plus binaire c=a+b; - Moins binaire c=a-b; << Décalage à gauche c=a<<b; >> Décalage à droite c=a>>b; & ET entre bits c= a & b; ^ OU exclusif entre bits c= a ^b; | OU entre bits c= a|b;
TESTS < Strictement inférieur if (a < b) <= Inférieur ou égal if (a >= b) > Strictement supérieur if (a > b) >= Supérieur ou égal if (a >= b) == Egal if (a ==b) != Différent if (a != b) && ET logique if ((a==5) && (b==2)) || OU logique if ((a==5) ||(b==2)) ?: Condition z=(a>b)?a:b (Si a>b a z=a sinon z=b)
Affectations et Auto-affectations = Affectation simple a=b; *= Affectation produit a*=2 (a=a*2) /= Affectation quotient a/=2 (a= a/2) %= Affectation reste a%=2 (a= le reste de a/2) += Affectation somme a+=2 (a=a+2) -= Affectation différence a-=2 (a=a-2) &= Affectation ET entre bits a&=5 (a=a&5) ^= Affectation OU EX entre bits a^=5 (a=a^5) |= Affectation OU entre bits a|==5 (a=a|=5) <<= Affectation décalage gauche a<<=5 (a=a<<5) >>= Affectation décalage droite a>>=5 (a=a>>5)
Merci de votre attention Exercez vous, un langage s’apprend par la pratique Compilateur C/C++ gratuits : DOS : TURBO C/C++ V1.01 www.borland.fr WINDOWS : DEV-C++ www.bloodshed.net très performant, orienté C++ mais on peut faire du C, utilisé par beaucoup de programmeurs chevronnés; certaines fonctions de TurboC++ ne sont pas supportées Pour PIC: CC5x http://www.bknd.com/cc5x/ (C'est un bon compilateur limité à 1k de code compilé par module, à intégrer à MPLAB. Très peu de fonctions intégrées : impossible de faire tourner des programmes écrits pour PICC avec CC5x, il faut reécrire ses librairies)