LANGAGE C avec AVR
Transcription
LANGAGE C avec AVR
1. PRESENTATION. ............................................................................................................................................1 2. STRUCTURE D’UN PROGRAMME EN LANGAGE C. ................................................................................1 2.1 Première approche d’un programme en langage C.............................................................................. 2 2.1.1 Directives de compilation................................................................................................................. 2 2.1.2 Déclaration d’une fonction. ............................................................................................................. 2 2.1.3 Déclaration des variables globales, des variables locales. ....................................................... 3 2.1.4 Point d’entrée du programme.......................................................................................................... 3 2.2 Définitions des types les plus couramment employés...................................................................... 3 2.2.1 Les types simples : ............................................................................................................................ 3 2.2.2 Le type pointeur : ............................................................................................................................. 3 2.3 Compilation d’un programme C avec CodeVisionAVR. ....................................................................... 5 2.3.1 Organisation de la mémoire SRAM................................................................................................ 5 2.3.2 Configuration du compilateur C. .................................................................................................... 6 3. LES OPERATEURS DE BASES.................................................................................................................... 7 3.1 L’opérateur d’affectation. ...................................................................................................................... 7 3.2 Les opérateurs arithmétiques. .............................................................................................................. 7 3.3 Les opérateurs de comparaison. ........................................................................................................... 7 3.4 Les opérateurs logiques. ......................................................................................................................... 7 3.5 Les opérateurs logiques de bits et de décalage................................................................................ 7 3.6 Les opérateurs d’incrémentation et d’affectation combinée......................................................... 8 4. LES STRUCTURES DE CONTROLES. ....................................................................................................... 8 4.1 Les structures alternatives (test). ..................................................................................................... 8 4.1.1 Structure IF … ELSE (SI … ALORS … SINON)....................................................................... 8 4.1.2 Structure SWITCH … CASE (CHOIX MULTIPLES). ............................................................... 9 4.2 Les structures ITERATIVES (Repetitives)....................................................................................... 9 4.2.1 La structure WHILE (TANT QUE … FAIRE). ............................................................................ 9 4.2.2 La structure DO … WHILE (FAIRE …JUSQU'À) ................................................................... 10 4.2.3 La structure FOR (POUR …FAIRE) ............................................................................................ 10 5. LES FONCTIONS. ........................................................................................................................................ 11 5.1 ROle d’une fonction. ................................................................................................................................ 11 5.2 Déclaration d’une fonction. .................................................................................................................. 12 5.3 Passage de paramètres. ........................................................................................................................ 12 1. PRESENTATION. La majorité des microcontrôleurs sur le marché actuel disposent parmi leurs outils de développement d’un compilateur C. Ces compilateurs utilisent le langage « small C » qui reprend un large sous-ensemble des fonctionnalités du langage C issu de la norme ANSI. Le guide de programmation que vous tenez entre vos mains vous permettra de vous initier à l’aide d’exemples concrets aux concepts de base du langage C adapté au microcontrôleur. Pour plus de détails sur le langage C veuillez consulter les nombreux ouvrages proposés sur ce sujet. Contrairement à ce que l’on pourrait croire, l’utilisation du langage C ne vous dispense pas de consulter la documentation technique du micro ATMEL AVR que vous avez choisie ! 2. STRUCTURE D’UN PROGRAMME EN LANGAGE C. #include <90s8515.h> // directive de compilation permettant d’inclure la bibliothèque // de définition des registres internes du microcontrôleur choisi void Tempo (unsigned long valeur); // Déclaration de la fonction Tempo, point virgule ! int i; // Déclaration d’une variable globale void main(void) { DDRA=0xff; PORTA=0x01; // Fonction principale while (1) { for (i=0; i<8; i++) { PORTA= PORTA<<1; Tempo(100000); } } } void Tempo (unsigned long valeur) { unsigned long j; for (j=0; j<valeur; j++) {} } // Boucle inconditionnelle // Initialisation // Structure FOR pour i=0 à i=8 avec un incrément de 1 // On décale d’un bit vers la gauche // appel fonction Tempo, passage du paramètre 100000 à l’argument // valeur // défnition de la fonction, pas de point virgule ! // Déclaration d’une variable locale // on ne fait rien 1 2.1 PREMIERE APPROCHE D’UN PROGRAMME EN LANGAGE C. 2.1.1 Directives de compilation. Les directives de compilation permettent de définir au pré-processeur les informations nécessaires lors de la compilation du programme, le symbole # indique que le texte est une directive. Le fichier « include » du microcontrôleur cible doit être obligatoirement précisé en début de programme. Exemples : La directive #include permet d’insérer un autre fichier dans votre fichier source. La directive #define peut être utilisée pour définir une macro ou une constante. 2.1.2 Déclaration d’une fonction. Exemple : void Tempo (unsigned long valeur); La fonction Tempo ne renvoie aucune valeur, elle possède un argument valeur de type unsigned long. #include <90s8535.h> void Tempo (unsigned long valeur) { unsigned long j; for (j=0; j<valeur; j++) {} } void main(void) { short int i; DDRA=0xff; PORTA=0x01; { for (i=0; i<8; i++) { PORTA= PORTA<<1; Tempo(100000); } } } // Aucune erreur à la compilation, la fonction tempo est appelée après sa définition. #include <90s8535.h> void main(void) { short int i; DDRA=0xff; PORTA=0x01; { for (i=0; i<8; i++) { PORTA= PORTA<<1; Tempo(100000); } } } void Tempo (unsigned long valeur) { unsigned long j; for (j=0; j<valeur; j++) {} } //Erreur "undefined symbol tempo" à la compilation, la fonction tempo est appelée avant d'être définie. #include <90s8535.h> void Tempo (unsigned long valeur); void main(void) { short int i; DDRA=0xff; PORTA=0x01; { for (i=0; i<8; i++) { PORTA= PORTA<<1; Tempo(100000); } } } void Tempo (unsigned long valeur) { unsigned long j; for (j=0; j<valeur; j++) {} } // Aucune erreur à la compilation, le compilateur connaît la fonction tempo grâce à la déclaration. 2 Les fonctions doivent être déclarées en dehors de la fonction main. La déclaration permet d'appeler une fonction avant qu'elle ne soit définit. Les fonctions ne retournant pas de résultat utilisent le mot clé void en début de déclaration. 2.1.3 Déclaration des variables globales, des variables locales. Les variables globales sont déclarées en en-tête du programme et sont accessibles à n’importe quel instant de l’exécution du programme, ce sont des variables permanentes, elles font l’objet d’une réservation en mémoire. Les variables locales sont définies à l’intérieur d’une fonction, leur durée de vie est limitée à l’exécution de cette fonction, ce sont des variables temporaires. Si on désire conserver la valeur d’une variable locale celle-ci doit être déclarée avec le mot clé static. 2.1.4 Point d’entrée du programme. Chaque programme C se compose au minimum de la fonction main, c’est le point d’entrée de notre programme. C’est à partir de la fonction main que seront appelées les autres fonctions (main est écrit volontairement en minuscules, le compilateur C distinguant les majuscules des minuscules). 2.2 DEFINITIONS DES TYPES LES PLUS COURAMMENT EMPLOYES. 2.2.1 Les types simples : Type Bit Char Int Taille (bits) 1 8 16 Domaine non signé 0,1 0 à 255 0 à 65535 Long int 32 0 à 4294967295 Domaine signé -128 à 127 -32768 à 32767 -2147483648 à 2147483647 Le mot clé unsigned placé devant la déclaration du type permet de préciser que le type est non signé. Pour les autres types voir la documentation de CodeVision AVR. 2.2.2 Le type pointeur : Le pointeur est une variable contenant une adresse. Il doit toujours être initialisé à une adresse avant son utilisation, il est comparable aux registres d’index des microcontrôleurs. Exemple : int *ptr //on déclare un pointeur se nommant ptr de type int. Ptr = 0x0100 //on définit une adresse au pointeur. PORTB = *ptr //le contenu de l’adresse pointée est transmis en sortie sur le PORTB. 3 Spécificités du compilateur CodeVision AVR : L’architecture Harvard des microcontrôleurs AVR impose trois espaces d’adresses différents : L’espace des données (SRAM) L’espace programme (FLASH) L’espace mémoire EEPROM Le compilateur gère donc trois types de pointeurs : Les variables situées en SRAM sont accessibles avec des pointeurs classiques. Les constantes placées en mémoire FLASH sont accessibles avec des pointeurs déclarés avec le mot clé flash ou const. Les variables situées en EEPROM sont accessibles avec des pointeurs déclarés avec le mot clé eeprom. Bien que les pointeurs permettent d’accéder aux différents espaces mémoires, ceux-ci sont toujours rangés en mémoire SRAM. Exemples : Char *résultat //Déclaration du pointeur résultat, le pointeur est localisé en SRAM. Char flash *message [2] ={”message 1”,”message 2”} //message 1 et message2 sont placés-en //mémoire flash, le pointeur message est localisé en //SRAM Char eeprom *pointeur_mémoire =”Ce texte est placé en EEPROM” //Le chaîne de caractère est // placée en EEPROM, le //pointeur pointeur_mémoire //est localisé en SRAM 4 2.3 COMPILATION D’UN PROGRAMME C AVEC CODEVISIONAVR. 2.3.1 Organisation de la mémoire SRAM. Un programme compilé avec CodeVisionAVR à l’organisation suivante : 0 Registres de travail 20h 12 registres utilisés par le compilateur (R0, R1, R22 à R31). R2 à R15 peuvent être alloués aux variables de type bit ( LSB de R2 = Premier bit déclaré, MSB de R15 = 112eme bit déclaré, les registres inutilisés peuvent être alloués au var. globale de type int ou char ). Les registres R16 à R21 sont réservés aux variables locales de type int ou char. Registres d’entrées sorties Espace de 64 adresses réservé aux fonctions périphériques du microcontrôleur ( Ports, timer ….). « Data stack » Espace pointeur de pile Cet espace permet de sauvegarder les registres utilisés par le compilateur (R0, R1, R22 à R31), le passage des paramètres et le registre SREG lors de l’utilisation des interruptions. Au départ la pile pointe 5F + taille Data stack. L’adresse est décrémentée durant une sauvegarde, incrémentée durant une restitution. 60h 60h + Data stack Variables globales 60h + Data stack + var. globales « Hardware stack » Cet espace permet de ranger les variables globales du programme pendant son exécution. Cet espace est utilisé pour ranger l’adresse de retour des fonctions SRAM End 5 2.3.2 Configuration du compilateur C. Une configuration optimisée du Project|Configure|Compiler permet de mieux maîtriser le code généré par le compilateur Valeurs par défaut selon le choix du micro choisi, vous pouvez optimiser l’espace data stack size si nécessaire ou déclarer de la SRAM externe. Valide la transformation char en type int. Voir exemple n°7 en fin de cours. A cocher si vous utilisez la liaison série Déclaration du nombre de variable de type bit, les registres inutilisés sont alloués aux variables globales. Le modèle TINY génère des pointeurs 8 bits, on a accès aux 256 premiers octets de la SRAM. Le modèle SMALL génère des pointeurs 16 bits, on a accès aux 64K octets de la SRAM. Pour améliorer la taille du programme et la vitesse d’exécution, vous devez toujours essayer d’utiliser le modèle TINY. Valide par défaut le type char comme non signé. Optimise l’allocation des registres R2 à R15 non utilisés par les variables de type bit. Permet d’optimiser la taille du code généré (option size) ou la vitesse d’exécution (option speed). Permet de générer automatiquement une séquence d’initialisation après un reset du microcontrôleur. Validation de l’utilisation de la fenêtre du terminal d’AVR studio pour la simulation de la liaison UART. Cette option est utile lors du débuggage sous AVR studio, elle permet de vérifier l’intégrité de la taille de l’espace data stack size, pour plus de détails voir la page 85 de la doc CodeVisionAVR. 6 3. LES OPERATEURS DE BASES. 3.1 L’OPERATEUR D’AFFECTATION. Cet opérateur fondamental a pour symbole le signe égale “=”, sa syntaxe est left value = expression. 3.2 LES OPERATEURS ARITHMETIQUES. Ces opérateurs procèdent à des opérations arithmétiques sur leurs opérandes. Opérateur + * / % Opération Addition Soustraction Multiplication Division Modulo Exemple a+b a-b a*b a/b a%b 3.3 LES OPERATEURS DE COMPARAISON. Ce sont des opérateurs binaires qui comparent la valeur de leurs opérandes. Opérateur == != <= >= < > Fonction Égale à ? Différent de ? Inférieur ou égal à ? Supérieur ou égal à ? Inférieur à ? Supérieur à ? Exemple a == b a != b a <= b a >= b a<b a>b 3.4 LES OPERATEURS LOGIQUES. Ces opérateurs permettent de relier logiquement des instructions. Opérateur && || ! Fonction ET logique OU logique NON logique Exemple a && b a || b !b 3.5 LES OPERATEURS LOGIQUES DE BITS ET DE DECALAGE. Ces opérateurs réalisent des opérations logiques sur les bits de même rang. Opérateur & | ^ ~ >> << Fonction ET OU OU exclusif NON ( complément ) Décalage de n bits vers la droite Décalage de n bits vers la gauche Exemple a&b a|b a^b ~a a >> n a << n 7 3.6 LES OPERATEURS D’INCREMENTATION ET D’AFFECTATION COMBINEE. Opérateur ++ -+= -= *= /= %= >>= <<= &= |= ^= Fonction Incrément de 1 Décrément de 1 Addition, résultat dans l’opérande de gauche Soustraction, résultat dans l’opérande de gauche Multiplication, résultat dans l’opérande de gauche Division, résultat dans l’opérande de gauche Modulo, résultat dans l’opérande de gauche Décalage à droite, résultat dans l’opérande de gauche Décalage à gauche, résultat dans l’opérande de gauche ET, résultat dans l’opérande de gauche OU, résultat dans l’opérande de gauche OU exclusif, résultat dans l’opérande de gauche Exemple a ++ a -- Equivalence a=a+1 a = a -1 a += b a=a+b a -= b a=a-b a *= b a=a*b a /= b a=a/b a %= b a=a%b a >>= n a = a >> n a <<= n a = a << n a &= b a=a&b a |= b a=a|b a ^= b a=a^b 4. LES STRUCTURES DE CONTROLES. 4.1 LES STRUCTURES ALTERNATIVES (TEST). Ces structures permettent de ne pas exécuter systématiquement certaines instructions. 4.1.1 Structure IF … ELSE (SI … ALORS … SINON). if (<condition>) <séquence A> ; else < séquence B >; ou if (<condition>) { <séquence(s)>; } else { <séquence(s)>; } condition fausse vrai Séquence A Exemple : if (test) allume(); else éteint(); Séquence B //on allume si test different de 0 8 4.1.2 Structure SWITCH … CASE (CHOIX MULTIPLES). Cette structure permet de choisir entre plusieurs alternatives. Lorsque l’expression située après le SWITCH coïncide avec une des constantes, le programme exécute la séquence ainsi que les séquences suivantes. Pour éviter ce désagrément l’instruction break doit être placée à la fin de chaque séquence. switch (<expression>) { case c1 : <séquence A>; case c2 : <séquence B>; case c3 : <séquence C>; case c4 : <séquence D>; default : < séquence par défaut >; } vrai Séquence A Expression == c2 vrai Séquence B vrai Séquence C vrai Séquence D Expression == c3 Exemple : Switch (numéro_de_touche) { case 1 : lcd_putsf (“Touche n°1”); break; case 2 : lcd_putsf (“Touche n°2”); break; case 3 : lcd_putsf (“Touche n°3”); break; default : lcd_putsf (“Touche erroné”); } Expression == c1 Expression == c4 fausse Séquence par défaut //lcd_putsf permet d’envoyer une chaîne de // caractère vers un afficheur LCD (bibliothèque LCD.h) 4.2 LES STRUCTURES ITERATIVES (REPETITIVES). 4.2.1 La structure WHILE (TANT QUE … FAIRE). La structure WHILE permet de répéter la séquence tant que l’expression est vraie. while (<expression>) <séquence>; ou while (<expression>) { <séquence(s)>; } Expression fausse vraie Séquence Exemple : while (BUSY==0) { PORTA =0xaa ; PORTB = 0X25; } 9 4.2.2 La structure DO … WHILE (FAIRE …JUSQU'À) Avec la structure DO … WHILE la séquence est exécutée au moins une fois, elle est répétée tant que l’expression est vraie. Séquence do <séquence>; while (<expression>); Expression ou fausse vraie do { <sequence(s)>; } while (<expression>); Exemple : do { PORTA+=1 ; //incrément de 1 de PORTA PORTB=PORTB+1 ; //incrément de 1 de PORTB } while (PINC.2==0); 4.2.3 La structure FOR (POUR …FAIRE) La structure FOR permet de répéter une séquence tant que l’expression2 est vraie. Elle opère souvent sur l’expression. Initialisation For (<expression1>; <expression2>; <expression3>) <séquence>; ou Expression For (<expression1>; <expression2>; <expression3>) { <séquence>; } fausse vraie Séquence Equivalent à : Opération <expression1> While (<expression2>) { <séquence>; <expression3>; } Remarque : For (;;) //Boucle infinie Exemples : For (i=1; i<9 ;i++) { PORTA<<=1; } 10 5. LES FONCTIONS. 5.1 ROLE D’UNE FONCTION. Le corps d’une fonction est délimité par des accolades { ….. }. Un programme C doit se composer de plusieurs fonctions pour permettre une meilleure lisibilité et maintenance du programme. La fonction main () est exécutée en premier, elle gère le bon déroulement du programme et l'échange des données entres les autres fonctions. Exemple : Lecture de l'état de huit inters dils branchés sur la port A et affichage du résultat sur huit leds branchés sur le port C. #include <90s8515.h> char valeur; void init (void); void lecture (void); void affiche (void); void main(void) { init(); lecture(); affiche (); } #include <90s8515.h> char valeur; void main(void) { DDRA=0x00; PORTA=0x00; DDRC=0x00; PORTC=0xff; valeur=PINA; PORTC=valeur; } void init(void) { DDRA=0x00; PORTA=0x00; DDRC=0x00; PORTC=0xff; } void lecture (void) { valeur=PINA; } void affiche (void) { PORTC=valeur; } Le programme est plus long à écrire, le code généré est plus important (89 mots au lieu de 83 pour l'exemple droite), mais la fonction main est structurée et gère les appels des fonctions nécessaires à la réalisation de notre programme. La tache réalisée par ce programme est plus lisible et compréhensible par une tierce personne, ceci facilite et améliore les opérations de maintenance. L'écriture est simplifiée, mais la tache réalisé par le programme est plus difficile à déterminer. Pour une tache plus compliquée la lecture du programme par une tierce personne peut devenir rapidement très difficile voire impossible. L'écriture de ce type de programme est donc à proscrire. 11 5.2 DECLARATION D’UNE FONCTION. Pour améliorer la lisibilité des programmes toutes les fonctions doivent être déclarées et « typées ». Si la déclaration est omise le type de la fonction sera de type int. Chaque fonction peut recevoir ou non des arguments en paramètres, attention à respecter les types lors des passages d'arguments. Le mot clé void permet de déclarer une fonction ne renvoie pas de paramètres, il permet aussi de déclarer qu’une fonction ne reçoit pas d’arguments en paramètres. 5.3 PASSAGE DE PARAMETRES. Le passage des paramètres peut s’effectuer par valeur ou par adresse. Lors du passage par valeur, la fonction ayant reçu les arguments en paramètres travaille avec des copies de ces variables, lors de la sortie de la fonction les variables originelles restent inchangées. Lorsque le passage s’effectue par adresse, la fonction travaille directement avec la variable ( la fonction connaît son adresse). 12