• Aucun résultat trouvé

[PDF] Programmation C pdf support de cours et travaux pratiques - Cours langage c

N/A
N/A
Protected

Academic year: 2021

Partager "[PDF] Programmation C pdf support de cours et travaux pratiques - Cours langage c"

Copied!
35
0
0

Texte intégral

(1)

GENIE ELECTRIQUE ET INFORMATIQUE INDUSTRIELLE 2004-2005

INFORMATIQUE INDUSTRIELLE

LANGAGE C

Compilateur HI-TECH PICL C compiler 117

Pour PIC16F84-16F62X

Compilateur gratuit et documentation constructeur picclite.pdf disponibles sur le

site :

http://www.htsoft.com/

Environnement de développement MPLAB gratuit et exemples disponibles sur le

site de Microchip : http://www.microchip.com/

(2)
(3)

SOMMAIRE

1. Spécification d’une base de numération pour une valeur numérique... 4

2. Affectation d’une valeur à une variable... 4

3. Les types des données du C et la déclaration des variables et constantes...5

3.1. Variables scalaires... 5

3.1.1. type booléen... 5

3.1.2. type octet... 5

3.1.3. type réel... 6

3.1.4. Pointeurs, signification des symboles * et & placés devant une variable... 8

3.2. Tableaux, chaînes de caractères...8

3.2.1. Tableaux, allocation statique en mémoire adresse ... 8

3.2.2. Chaînes de caractères... 9

3.2.3. Tableaux, allocation dynamique en mémoire... 10

3.3. Structures et Unions, énumérations... 10

3.3.1. Structures et unions... 10

3.3.2. Union... 11

3.3.3. Enumération... 11

3.4. Définition de noms de types par l’utilisateur : typedef... 11

3.5. Constantes... 12

3.6. Variables locales et variables globales...12

4. Expressions / opérateurs... 12

4.1. Règles d’évaluation de l’expression ... 12

4.2. Opérateurs arithmétiques +, -, *, /, %, ++, --...13

4.3. logique binaire sur mots (bits à bits de même rang) & , | , ~ ... 13

4.4. logique booléenne && , || , ! , comparaisons == , < , >, >= , <= ... 14

5. Structures de contrôle du déroulement en séquence... 15

5.1. Boucles while, do while, for...15

5.1.1. While (tant que)... 15

5.1.2. Do While (faire tant que)... 16

5.1.3. Boucle de répétition For ... 18

5.2. Branchements conditionnels if , else... 20

5.3. Switch - Case (faire - selon le cas)... 21

5.4. Branchements inconditionnels... 21

6. Fonctions... 23

6.1. Introduction... 23

6.2. Fonction non typée... 23

6.2.1. définition ou implémentation ou encore écriture de la fonction... 23

6.2.2. exemple de fonction sans paramètre :... 23

6.2.3. exemples de fonction avec paramètres :... 24

6.3. Fonction typée...25

6.4. Arguments passés par valeur, par adresse, ou par référence... 27

6.5. La fonction main...28

6.6. Fonction d’interruption... 28

7. Programme en langage C... 29

8. Exemple 1 de programme en langage C PIC 16F84... 31

(4)

1. Spécification d’une base de numération pour une valeur numérique

• Hexadecimal : 0xvaleur exemple : 0x2F

• Binaire : 0bvaleur exemple : 0b10011010

• Octal : 0valeur exemple : 0763

• Décimal : valeur exemple : 129

Code ASCII : ‘caractère’ exemple : ‘A’ pour le code ASCII de A

2. Affectation d’une valeur à une variable

En C, on utilise le symbole = comme symbole d’affectation. Exemple d’affectation : y = 27 ; // 27 → y

Ceci permet de donner la valeur 27 à la variable y. Prenons le cas d’une variable y de type octet.

L’octet est situé en mémoire des données à une adresse qui a été attribuée par le compilateur. Soit Ptr_y cette adresse. La séquence des instructions générées par le compilateur PIC sera :

movlw D’27’

movwf Ptr_y ; 27 en décimal est placée à l’adresse de la variable

Remarques :

x=y ; et y=x ; n’ont pas la même signification.

x=0x3F ; a un sens ( x prend la valeur 0x3F ) alors que 0x3F = x ; n’en a pas .

x=x+1;// x+1 → x a un sens : incrémenter x

x=x-10;// x-10→ x a un sens : enlever 10 à la valeur de x

Exemple de permutation lors d’un tri des éléments d’un tableau :

if(tab[j]<tab[i]) {

temp=tab[i];// tab[i] →temp tab[i]=tab[j];// tab[j]→ tab[i] tab[j]=temp; // temp → tab[j] }

Attention :

Il n’est pas possible d’affecter des grandeurs de type différents mais il existe des fonctions de changement de type.

Exemple :

char i ;

float x=12.35;

i=(char)x; // correct donne 12

mais

(5)

i=x ; est incorrect

Remarque : Il est possible de combiner affectation et opération. Exemple d’affectation précédée d’une addition :

unsigned char x; x est une variable octet x + = 6; //équivaut à : x = x + 6 ;

3. Les types des données du C et la déclaration des variables et constantes

3.1. Variables scalaires

3.1.1. type booléen

Tous les compilateurs C ne proposent pas ce type de déclaration. Dans le cas du compilateur PIC C LITE il est possible de déclarer des variables booléennes à l’aide du mot réservé bit.

Dans le cas le plus courant les compilateurs utilisent pour des valeurs booléennes un octet. Les états "vrai" et "faux" sont représentés respectivement par une valeur non nulle et nulle.

Exemples de déclaration de variables de type bit :

bit init_flag;

Le compilateur loge en mémoire vive disponible ce bit. On ne se préoccupe pas de son adresse d’implantation en mémoire des données.

On utilise alors le mot static et le symbole @ si l’on doit imposer l’adresse de la variable.

static bit RA3 @ 5*8+3;

RA3 est le bit situé au rang 3 de l’octet d’adresse 5. 3.1.2. type octet

Il est possible de déclarer des variables octets à l’aide du mot char ou des mots unsigned char.

• char : plage de variation : -128 , 127 pour 1 octet avec bit de signe.

• unsigned char : plage de variation : 0 , 255 pour 1 octet sans bit de signe.

Pourquoi ce mot réservé et non pas le mot byte qui semble plus approprié ? A cause de l’utilisation des octets pour coder les caractères mais il faut remarquer que ce n’est pas le seul cas d’utilisation.

Exemples de déclaration de variables de type char :

char NombreImpulsions; char compt0,compt1;

Le compilateur se charge de réserver une place à une adresse en mémoire vive pour les octets.

Dans les programmes nous ne nous préoccuperons généralement pas de l’adresse d’implantation de l’octet dans la mémoire des données.

Remarque : en langage C la valeur d’adresse est accessible en écrivant &compt0 par exemple qui se lit adresse de la valeur compt0.

(6)

static unsigned char PORTA @ 0x05;

Le compilateur doit implanter à l’adresse H’05’ en mémoire vive l’octet de nom

PORTA.type entier

Le mot int permet de déclarer des entiers sur plus d’un octet .

int : plage de variation sur 16 bits : -32768 , 32767 (

2

16

valeurs) unsigned int : plage de variation sur 16 bits : 0 , 65535 (

2

16

valeurs) Exemple de déclaration de variables de type int :

int x,y,z;

Le compilateur se charge de réserver une place à des adresses consécutives en mémoire vive pour ces doubles octets.

Dans les programmes nous ne nous préoccuperons généralement pas de l’adresse de début d’implantation des variables.

3.1.3. type réel

Dans le cas du compilateur PIC C LITE il est possible de déclarer des variables réelles sur 24 bits et 32 bits à l’aide des mots réservés float et double.

Un nombre réel est rangé en mémoire sous la forme :

2

*

mantisse

.

1

*

)

1

(

127) (EXPOSANT

+

Bitdesigne

avec 0 =< mantisse < 1

Variable Bit de signe Exposant+127 Mantisse

Float 1 bit 8 bits 15 bits

L’exposant est codé en excès de 127. Ainsi 0 est représenté par 127. Les bornes extrêmes d’un réel de type float sont ainsi :

10

*

9

,

2

2

-128

±

−39

±

( valeurs les plus proches de 0 )

et ±2128±3,4*1038 ( valeurs les plus éloignées de 0 )

On trouve sur 24 bits : le bit de signe suivi des 8 bits d’exposant +127 et enfin les 15 autres bits de la mantisse.

Exemples :

B F 8 0 0 0 représente la valeur –1 1011 1111 1000 0000 0000 0000

( bit de signe : 1 puis bits d’exposant : 011 1111 1 qui correspondent à l’exposant + 127 ici 0 + 127

et enfin la mantisse 000 0000 0000)

3F 80 00 représente la valeur 1 (seul le bit de signe change par rapport à -1)

40 00 00 représente la valeur 2 ( 100 0000 0 correspond à l’exposant + 128 ici 1 + 127) 3F 00 00 représente la valeur 0.5

(7)

3E 80 00 représente la valeur 0.25 etc.

Le compilateur se charge de réserver une place à une adresse en mémoire vive pour les variables de type float, double.

Dans les programmes nous ne nous préoccuperons généralement pas de l’adresse d’implantation de ces variables.

(8)

3.1.4. Pointeurs, signification des symboles * et & placés devant une variable

On appelle pointeur l’adresse de début d’implantation en mémoire d’une variable.

La déclaration d’un pointeur contient l’information du type de variable pointée afin de pouvoir tenir compte de règles d’incrémentation et de décrémentation des pointeurs.

Le nom du pointeur est précédé du symbole

*

Souvent, on fera précéder les noms de pointeurs de Ptr ou de la lettre p pour bien les différencier des noms de variables.

int *Ptrx; //Ptrx est un pointeur sur une variable de type int.

Attention, le symbole

*

est utilisé en C dans ce contexte ( déclaration ) pour indiquer que Ptrx est le nom d’une adresse alors que dans d’autres contextes il aura une autre signification ( cas d’une expression arithmétique : symbole de la multiplication ).

Remarque concernant l’arithmétique des pointeurs :

Ptrx++ ;

Incrémente la valeur de Ptrx de 2 dans ce cas d’un pointeur sur un entier car un entier occupe 2 places en mémoire (2 octets).

Si Ptrx est le nom de l’adresse d’une variable, son contenu est désigné par

*

Ptrx. Si x est le nom d’une variable, son adresse (pointeur sur le premier octet)

est désignée par &x.

Dans ce contexte, l' opérateur & est appelé opérateur d'adressage. Ainsi dans le cas d’un entier x sur 2 octets :

3.2. Tableaux, chaînes de caractères

3.2.1. Tableaux, allocation statique en mémoire adresse

//déclarations d'un tableau de 3 entiers,.

int tab1[3];

temp=tab1[i];// tab1[i] →temp

Remarques:

• Le premier élément du tableau est situé à l’indice 0.

• i doit être compris entre 0 et 2 inclus.

• Chaque entier occupe 2 emplacements en mémoire

• Le nom, ici tab1, du tableau est le pointeur constant sur le premier élément du tableau.

• Le nom du tableau est l’adresse du premier élément du tableau.

Cours Langage C PICL C Informatique Industrielle GE&II 1ère année 2004/2005 tab

1

tab1[0] tab1[1] tab1[2] Mémoire (octets) Mémoire (octets) X haut &x X bas

(9)

//déclarations d'un tableau de 6 octets avec initialisation, allocation statique en mémoire.

unsigned char tab_seg[]={0x3F,0x06,91,79,102,109};

3.2.2. Chaînes de caractères

Une chaîne de caractères est tout simplement un tableau de code ASCII de caractères terminé par la valeur 0.

Remarques:

Le message est encadré par

" "

Un code ASCII d’un seul caractère est noté entre ‘ ’

Exemple de déclaration avec initialisation :

char message1 [ ] = "bonjour";

tab_seg tab_seg[0] tab_seg[1] tab_seg[2] tab_seg[3] tab_seg[4] tab_seg[5] 0x3F mémoire 0x06 91 79 102 109 message1 message1[0] message1 [1] message1 [2] message1 [3] message1[4] message1 [5] ‘b’ mémoire ‘o’ ‘n’ ‘j’ ‘o’ ‘u’ ‘r’ 0x00 message1 [6] Valeur de fin de chaîne : 0

(10)

3.2.3. Tableaux, allocation dynamique en mémoire

Lorsque les programmes manipulent des données mobilisant beaucoup d’espace mémoire ( cas d’images par exemple), ces données ne sont placées en mémoire que lorsqu’on les utilise puis l’espace mémoire est libéré.

Le Compilateur PIC C LITE ne propose pas ce type d’allocation.

char *PtrImage ;

PtrImage =new char[1000000]; // allocation dynamique en mémoire de 1000 0000 d’ octets.

delete PtxImage ; // libère l’espace alloué

3.3. Structures et Unions, énumérations

3.3.1. Structures et unions

Le mots réservé struct permet de déclarer des variables composées de plusieurs champs placés en mémoire à des adresses consécutives.

Exemples : struct struct_complexe { double m_reel; double m_imaginaire; }im1,im2; struct struct_etudiant { char m_nom[10]; int m_note[5];

} etudiant1, etudiant2, etudiant3;

On accède au champ d’une variable structurée en faisant suivre le nom de la variable du nom du champ ( on dit aussi le membre de la variable ).

Exemples :

im1.m_reel=2.3; im1.m_imaginaire=5;

etudiant1.m_nom[]= "Toto";

Déclaration d’une structure composée de 8 bits à partir de l’adresse 0x6. Le champ B0 est le bit de rang 0 de PORTB et le champ B7 est le bit de rang 7 de PORTB :

struct {

unsigned B0 : 1; // bit de rang 0

unsigned : 6; // bits de rang 1 à 6 inutilisés unsigned B7 : 1; // bit de rang 7

} PORTB @0x6;

On pourra écrire : if ( PORTB.B0) pour tester l’état du bit de rang 0 de port B.

(11)

3.3.2. Union

Le mot réservé union permet de déclarer des variables de différents types et tailles, variables qui se recouvrent en mémoire.

union struct_16bits {

unsigned int DoubleOctet; unsigned char Octet[2]; } x1,x2,x3;

3.3.3. Enumération

Le mot réservé enum permet de déclarer des noms dont les états possibles sont définis par énumération. Exemple 1 :

enum {rouge,vert,orange} couleur_feu;

La variable de nom couleur_feu peut se voir affecter les valeurs rouge (0) , vert (1) , orange (2) .

Exemple 2 :

enum {PB ,OK} EtatMachine;

3.4. Définition de noms de types par l’utilisateur : typedef

Le mot réservé typedef permet de déclarer des noms de type par l’utilisateur. //exemple de définition du nouveau nom de type « byte » :

typedef unsigned char byte ; On pourra alors écrire :

byte x;

Souvent, on fera précéder les noms de type de t_ pour bien les différencier des noms de variables.

//définition de t_complexe

typedef struct stuct_complexe

{

double m_reelle; double m_imaginaire; }

t_complexe;

On pourra alors écrire :

t_complexe x; puis x. m_reelle=0.5 ; . m_imaginaire=2.5 ; //définition de t_booleen

typedef enum { faux ,vrai} t_booleen;

On pourra alors écrire :

t_booleen etat_moteur;

x1.DoubleOctet

x1.Octet[0] x1.Octet[1]

(12)

Déclaration d’un type d’une structure composée de 8 bits du rang 0 au rang 7d’un octet. typedef struct

{

unsigned pompe:1, evacuation:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1; } t_bitv;

On pourra alors écrire :

t_bitv actionneurs; actionneurs.pompe=1;

3.5. Constantes

Le mot réservé const permet de déclarer des noms de valeurs constantes par l’utilisateur. Exemple :

const unsigned char VERSION = 3;

On ne peut pas affecter une constante.

VERSION =5; provoque un message d’erreur lors de la compilation.

3.6. Variables locales et variables globales

En langage C tout nom de variable doit être déclaré.

Une variable est globale si elle est déclarée en début de programme. Elle est alors connue dans tout le programme.

Une variable est locale si elle est déclarée à l'intérieure d'une fonction. Elle est alors connue seulement dans le corps de la fonction.

4. Expressions / opérateurs

4.1. Règles d’évaluation de l’expression

Les calculs se font en tenant compte de l’ordre de priorité que peut modifier l’utilisation de parenthèses. Si les opérateurs sont de même ordre de priorité l' évaluation progresse de gauche à droite et s'arrête dès qu'on peut conclure.

(13)

4.2. Opérateurs arithmétiques +, -, *, /, %, ++,

--• Opérateurs portant sur deux opérandes + - * / %

o L'opérateur % donne le reste de la division entière (modulo).

o La division de deux entiers donne un quotient entier. Exemple d’instructions :

// variables de type int unite=x%10;

dizaine=(x/10)%10; centaine=x/100;

// variables de type double

module = sqrt (x*x+y*y) // sqrt fonction racine carré

• Dans l'ordre de priorité d’exécution, on aura : * et / , % puis + et

-• Opérateurs portant sur un seul opérande

i++ pour incrémentation de i ainsi i++ ; donne le même résultat que i = i+1 ; i - - pour décrémentation de i ainsi i - - ; donne le même résultat que i = i -1 ;

++ ou – placé devant le nom de la variable indique que l’incrémentation ou la décrémentation doit être faite de avant les autres opérations.

4.3. logique binaire sur mots (bits à bits de même rang) & , | , ~

• Ces opérateurs ne s'appliquent qu'aux types octets (en général naturel : unsigned ), agissent bit à bit sur la représentation interne en base 2.

• Dans l'ordre de priorité d’exécution, on aura :

~ Complément à 1 (permet de changer les états des bits) << Décalage à gauche (permet de multiplier par 2, 4, ...) >> Décalage à droite (permet de diviser par 2, 4, ...) & Et logique (permet de mettre des bits à 0) I Ou logique (permet de mettre des bits à 1) ^ Ou exclusif

(permet de changer les états des bits, de déceler des changements d’états des bits) Exemple 1 de décalage à droite:

unsigned char portb;

portb=portb>>2; après 2 décalages :

Exemple 2 de mise à 1 du bit de rang 2 de portb: ou bit à bit

1 0 1 0 1

1

0 0 0

0 0 0 0 0 1 0 0

1 1 1 0 1

1

0 0 1

1 1 1 0 1

1

0

0 0

(14)

Remarque : le compilateur PIC CLITE permet de manipuler des noms de bits. Ainsi on peut écrire : RB2=1 ;

Exemple 3 de mise à 1 du bit de rang 2 de portb:

portb | = 0x04;

Exemple 4 de mise à 0 du bit de rang 2 de portb: et bit à bit

portb & = 0xFB;

Remarque : le compilateur PIC CLITE permet de manipuler des noms de bits. Ainsi on peut écrire : RB2=0 ;

4.4. logique booléenne && , || , ! , comparaisons == , < , >, >= , <=

• Appliqués à des opérandes numériques, les opérateurs logiques produisent un résultat "booléen" : 1 (pour vrai) ou 0 (pour faux).

• Dans l'ordre de priorité d’exécution, on aura :

La négation !

Les comparaisons < <= >= >

Les comparaisons = = (identique) ! = (différent de)

Le et logique &&

Le ou logique II

• Toute valeur différente de 0 est considéré comme « vrai » en langage C.

Exemples d’utilisation des opérateurs logiques:

if( (PresenceVoiture == 1) && (NbreVoitures < NbreMax)) {

ouvrir_barriere(); NbreVoitures++; }

Autre exemple d’utilisation :

Cours Langage C PICL C Informatique Industrielle GE&II 1ère année 2004/2005

1 0 1 0 1 1 0 0

1 0 1 0 1

1

1 0 0

1

1

1 1 1 1 0 1 1

1 0 1 0 1 0 0 0

(15)

//t est-il le code ascii d’une lettre ?

if (((t>='a') && (t<='z')) || ((t>='A') && (t<='Z'))) {

//cas d’une lettre }

Cas particulier d’utilisation d’une expression toujours vrai : 1>0 .

//pour une boucle sans fin while(1>0)

{//debut de boucle sans fin

//instructions dans la boucle }//fin de boucle sans fin

Autre cas particulier d’utilisation d’une expression toujours vrai : 1 .

while(1) {} pour une boucle sans fin sans instructions dans la boucle

5. Structures de contrôle du déroulement en séquence

5.1. Boucles while, do while, for

5.1.1. While (tant que)

Tant qu’une condition est vrai faire s’écrit en langage C : while(expression)

{

instructions; } //while expression

Exemple de test de PORTB supposé en entrée dans une commande de machine à laver :

while(PORTB< 60 ) {

chauffage() ; }

Exemple d’attente que RB7 soit à 1 (RB7 supposé en entrée) dans le cas du test du LCD occupé (carte IUT2 + LCD).

(16)

while(RB7==1){} //remarquer == pour la comparaison

Exemple de test de fin de message :

while(*message!=0) //Note:la fin d’un message est indiquée par la valeur 0 {

LCD_car(*message); message++;

}

Exemple de boucle sans fin :

while(1) // faire toujours {

PORTA=etat1; // état 1 du port A

while(inter0==0){} //remarquer == pour la comparaison PORTA=etat2; // état 2 du port A

while(inter1==0){}

PORTA=etat3; // état 3 du port A while(inter2==0){}

}

5.1.2. Do While (faire tant que)

Faire tant qu’une condition est vrai s’écrit en langage C : do { instructions; } //do expression while (expression); Exemple : float milieu; float a=0.0; float b=7.0; do { milieu=(a+b)/2; if(f(a)*(f(milieu))<0) b=milieu; else a=milieu; } while((b-a)>0.001); a b f(x) ) x milieu

(17)

Dans le cas de la figure la solution devra être recherchée entre a et milieu. On aura alors un segment de recherche 2 fois plus petit que le segment

précédent. On fixe comme condition d’arrêt une précision sur la valeur de la racine donc sur la largeur b-a.

(18)

5.1.3. Boucle de répétition For

Pour répéter un bloc d’instructions on écrira :

for(état initial du compteur de boucles;condition d'arrêt;gestion du compteur de boucles) { instructions;

...; }//fin de la boucle

Exemple de calcul de la somme des 100 valeurs d’un tableau :

S=0 ; // 0→S

for(i = 0 ; i <100 ; i ++) {

S=S+tab[i];// tab[i]+S→S }

Exemple de création de 8 tops sur la broche RA3 :

for(i=0;i<8;i++) // 8 tops d' horloge {

RA3=1; // mise à 1

tempo(2); //temporisation qui doit être écrite par ailleurs RA3=0; //mise à 0 tempo(2); //temporisation } Exemple de temporisation : for(i = 0 ; i <500 ; i ++) {

//cas particulier ou on ne fait rien dans la boucle }

Equivalent à :

for(i = 0 ; i <500 ; i ++); //(surtout ne pas omettre le ;)

Exemple d’initialisation à 0 de toutes les valeurs d’un tableau à 2 dimensions:

for(i=0;i<16;i++) // 8 tops d' horloge { for(j=0;j<8;j++) { tab_x[i,j]=0; 0 → tab_x[i,j] } }

Remarque : on utilisera i, j, k, comme noms d’indices des boucles de répétition. Ces variables seront déclarées de façon locale.

(19)

Exemple particulier de boucle sans fin :

for(;;) {

//programme à mettre ici }

Exemple d’une fonction d’intégration par la méthode des rectangles :

typedef double (*pfct)(double);

//déclaration d'un pointeur sur une fonction qui renvoie une valeur de type //double et reçoit une valeur de type double

// fonction qui reçoit les bornes a et b et le nombre de pas d’intégration n ainsi que le nom de la fonction à //intégrer

// la fonction Integre retourne la valeur de l’intégrale de a à b de la fonction double Integre(double a,double b,double n,double(*pf)(double x))

{

double Ip=0.0 ; double x,dx ;

dx= abs(b-a)/n ;//largeur d’un rectangle

for(double x=a;i<=b;x=x+dx) // somme des f(a+ i*dx) {

Ip=pf(x)+Ip; }

Ip= dx*Ip //// somme des aires des rectangles return(Ip); } a b f(x) ) x dx

Exemple de fonction de tri selon les valeurs croissantes des valeurs d’un tableau:

Void tri(int iNbElement, typ *tab) {

float temp;

for(int i=0;i<=iNbElement-2;i++) {

for(int j=i+1;j<=iNbElement-1;j++)//tab[0] tab[i]tab[i+1] tab[n] {

if(tab[j]<tab[i]) {

temp=tab[i];// tab[i] →temp

(20)

tab[j]=temp; // temp → tab[j] permutation }

} }

}

5.2. Branchements conditionnels if , else

Dans le cas ou seulement si une condition est vrai il faut effectuer une ou plusieurs instructions on écrira :

if (expression)

instruction ou bloc d’instructions à effectuer si l’expression donne un résultat vrai Exemple d’un test de présence de voiture dans une gestion de parking :

if((PresenceVoiture == 1) && (NbreVoitures < NbreMax)) {

ouvrir_barriere(); NbreVoitures++; }

Exemple de permutation de deux éléments d’un tableau lors d’un tri des éléments d’un tableau :

if(tab[j]<tab[i]) //alors qu’on souhaite tab[j]>tab[i] {

temp=tab[i];// tab[i] →temp tab[i]=tab[j];// tab[j]→ tab[i] tab[j]=temp; // temp → tab[j] }

Cas de l’alternative double :si la condition est vrai alors effectuer l’instruction 1 ou le bloc d'instructions 1 autrement faire l’instruction 2 ou le bloc d'instructions 2.

if (expression) { instructions; }//if exp else { instructions; ...; }//else exp

Exemple de choix dans la recherche de la solution approchée de f(x)=0 . milieu=(a+b)/2 if(f(a)*(f(milieu))<0) { b=milieu; } else { a=milieu; } a b f(x) ) x milieu

(21)

Dans le cas de la figure la solution devra être cherchée entre milieu et b

5.3. Switch - Case (faire - selon le cas)

Faire selon la valeur d’une expression un blocs d’instructions s’écrit : switch (expression) { case val0:{instructions;break;} case val1:{instructions;break;} case val2:{instructions;break;} case val3:{instructions;break;} default :{instructions;}

}//fin de faire selon la valeur de expression

Il faut utiliser break sinon tous les cas qui suivent le premier cas vrai sont alors exécutés. Exemple de programme de test du port B et d’affectation du port A :

void main() {

while(1) //boucle sans fin car 1 est l’équivalent de toujours vrai {

TRISA=0; //PORT A en sortie

switch (PORTB) //selon la valeur du PORT B {

case 0: PORTA=0x01;break; // cas ou le PORT B vaut 0 case 1: PORTA=0x02;break; // si le PORT B vaut 1 case 3: PORTA=0x04;break; // si le PORT B vaut 3 case 6: PORTA=0x06;break; // si le PORT B vaut 6 default: PORTA=0x00; // autrement

} }

}

5.4. Branchements inconditionnels

Break (interrompre), Continue (continuer), Goto (aller à) Return (retourner)

Exit (sortir)

Exemple d’utilisation de break :

(22)

case 0: PORTA=0x01;break; case 1: PORTA=0x02;break; case 3: PORTA=0x04;break; case 6: PORTA=0x06;break; default: PORTA=0x00; }

Il faut utiliser break sinon tous les cas qui suivent le premier cas vrai sont alors exécutés.

(23)

6. Fonctions

6.1. Introduction

Une fonction est un sous-programme utilisé par le programme principal ou par d'autres fonctions.

• Si la fonction retourne un résultat, elle est dite typée, sinon elle est dite non typée.

Le programme principal est désigné par main()

6.2. Fonction non typée

6.2.1. définition ou implémentation ou encore écriture de la fonction

1. On définit ainsi une fonction de nom nom_de_fonction :

void nom ( type0 param0, type1 param1,..., typen paramn ) //ligne dite de prototypage { déclarations....

instructions.... }//nom

param0,param1, … paramn sont les paramètres de la fonction ou encore les arguments de la fonction.

2. On utilise ou encore on appelle ainsi une fonction de nom nom_de_fonction: nom_de_fonction(par1,par2,...,par3);

par1,par2,...,par3 sont les paramètres de la fonction. Les noms utilisés sont choisis independemment des noms choisis lors de la définition de la fonction.

6.2.2. exemple de fonction sans paramètre : void tempo1(void)

{

unsigned int i;

for(i=0;i<2000;i++) {}//on boucle sur un bloc d’instructions vide }

On utilise ainsi cette fonction de nom tempo (ne pas oublier les parenthèses et le point-virgule).

tempo1();

Autre exemple : génération d’un top d'horloge en RA2

void LCD_Clk() { RA2=1; asm("nop"); RA2=0; }

(24)

LCD_Clk();

6.2.3. exemples de fonction avec paramètres :

Cas d’un seul paramètre.

Exemple : temporisation de durée fonction dune variable de type int

void tempo2(int delai) { int i; for(i=0;i<delai;i++) { tempo1(); } }

On utilise ainsi cette fonction de nom tempo2

tempo2(5); tempo2(200); tempo2(temps);

//temps doit être connue comme de type int et affecté à une valeur. tempo2(5.6);// n’est pas valable

Autre exemple :

//choix de positionnement du caractère sur le LCD //ligne octet valant 1 ou 2

// position octet valant 0 à 15

void LCD_pos(char ligne, char position) {

LCD_busy(); // attendre que le lcd soit prêt RS=0; RW=0; // mode écriture d’instructions if(ligne==1) PORTB=0x80|position;

if(ligne==2) PORTB=(0x80|position)+64;

// +64 = adresse de la 2eme ligne LCD_Clk();

}

On utilise par exemple ainsi cette fonction de nom LCD_pos

LCD_pos(2, 10) ;//passage en ligne 2 en position 10

Autre exemple : sauvegarde la valeur de la variable compt en EEPROM à l’adresse adr

eeprom_write(adr,compt);

Cette fonction permet d’écrire dans l’EEPROM des données.

(25)

6.3. Fonction typée

- On définit ainsi une fonction de nom nom_de_fonction :

type retourné nom_de_fonction( type0 param0, type1 param1,..., typen paramn ) { déclarations....

instructions.... return (resultat); }//nom

- On utilise ainsi une fonction de nom nom_de_fonction : identificateur = nom_de_fonction(par1,par2,...,par3);

Exemple d’une fonction de nom factoriel qui retourne le factoriel de la valeur passée en paramètre:

// implémentation de la fonction factoriel // paramètre passé en entrée : n de type entier

// paramètre retourné : un réel, le factoriel du paramètre passé. float factoriel(int n)

{

//début de la fonction de calcul de factoriel int i; float produit; produit =1; for (i=1;i<=n;i++) { produit=produit*i; }//fin de for i return produit; }//Fin de factoriel

On pourra alors écrire dans un programme l’appel de cette fonction :

y=factoriel(x) ;

Autre exemple :

// implémentation de la fonction fmodule

// paramètres passés en entrée : x,y parties réel et imaginaire de type double // paramètre retourné : un double : le module

double fmodule(double x, double y) {

//début de la fonction de calcul du module double module;

module=sqrt(x*x+y*y); return module;

}//Fin de fmodule

On pourra alors écrire dans un programme l’appel de cette fonction :

ro=fmodule(x,y) ;

(26)
(27)

6.4. Arguments passés par valeur, par adresse, ou par référence

Trois cas sont possibles:

• type param correspond à un passage par valeur.

• type *param correspond à un passage par adresse.

• type &param correspond à un passage par référence.

Lors du passage par valeur d’un paramètre l’original de la valeur est préservé en faisant une copie pour la fonction.

La fonction ne touche pas à l’original mais manipule une copie. Exemple de mauvaise implémentation de la fonction

qui permute les valeurs de 2 variables :

void fpermute0(int arg1, int arg2) { int temp;

temp=arg1 ; arg1=arg2; arg2=temp ; }

Appel de la fonction fpermute0 si x et y sont les noms des 2 variables dont les valeurs sont à échanger :

fpermute0(x, y) ;

Lors du retour après exécution de la fonction les valeurs originales de x et y sont récupérées. La permutation de x et de y n’a pas été effectuées sur les valeurs originales de x et y

mais sur des copies.

Exemple de passage par adresse :

Implementation de la fonction qui permute 2 valeurs de 2 variables :

void fpermute1(int *ptr_arg1, int *ptr_arg2) { int temp;

temp= *ptr_arg1 ; // ( ptr_arg1 )→ temp

*ptr_arg1= *ptr_arg2; // ( ptr_arg2 )→ ( ptr_arg1 ) *ptr_arg2= temp ; // temp → ( ptr_arg2 )

}

Appel de la fonction fpermute1 si x et y sont les noms des 2 variables dont les valeurs sont à échanger :

fpermute1(&x, &y) ; //&x se lit adresse de x, &y se lit adresse de y

L’accès aux 2 variables a été possible en fournissant leurs adresses .

Exemple de passage par référence :

Implementation de la fonction qui permute 2 valeurs de 2 variables :

void fpermute2(int &arg1, int &arg2) { int temp; temp=arg1 ; arg1=arg2; x y temp ptr_arg1 ptr_arg2 x y arg1 arg2 temp mémoire dans la fonction et dans le programme d’appel : mémoire dans la fonction et dans le programme d’appel : originaux Copies de x et y

(28)

}

Appel de la fonction fpermute2 :

fpermute2(x, y) ;

6.5. La fonction main

La fonction main() est obligatoire dans un programme.

Elle est comme le chef d'orchestre. Sans elle aucun programme n'est exécuté. Dans le cas du PIC16F84, cette fonction est lancée lors de la mise sous tension.

Remarque : Il n’y aura qu’une fonction main() dans un programme.

6.6. Fonction d’interruption

Une fonction d’interruption correspond à un programme d’interruption.

Exemple d’incrémentation d’une variable lors d’une interruption externe RB0 à tester sur la carte IUT1

char g_nbre_interrupt_RB0; //variable globale void interrupt int_RB0(void)

{

g_nbre_interrupt_RB0++;

INTF = 0;//autorisation à nouveau de it externe de RB0 }

void main() {

__CONFIG(XT&WDTDIS&PWRTEN); //oscillateur XT Watch Dog Timer DISable g_nbre_interrupt_RB0=0;

TRISA=0; //PORT A en sortie PORTA=0; //Sorties à 0

INTCON=0b10010000;//validation it externe de RB0 while(1)

{

//boucle sans fin du programme principal ici if(g_nbre_interrupt_RB0<16)

{

PORTA= g_nbre_interrupt_RB0|0b10000; //affichage }

else {

PORTA=0x0 ;//diode verte allumée }

} }

(29)

7. Programme en langage C Un programme C sera constitué de:

1. une entête

2. l'appel des bibliothèques

3. les définitions de types, les assignations

4. la déclaration des constantes et des variables globales (le moins possible) 5. la déclaration et l'écriture des fonctions (presque tout).

6. le programme principal. 1. une entête

/* fichier xx.c dans xx.pjt

auteur, date, version, cible, informations utiles

fonction : compteur sur PORT B avec bouton de RAZ en RA1 et mémorisation de la valeur du compteur en EEPROM

*/

2. l'appel des bibliothèques

#include <pic.h>

3. les définitions de types, les assignations

typedef unsigned char byte;

4. la déclaration des constantes et des variables globales

#define PORTBIT(adr,bit) ((unsigned)(&adr)*8+(bit)) static bit g_boutonRAZ @ PORTBIT(PORTA,1);

5. la déclaration et l'écriture des fonctions

// temporisation void tempo(void) { unsigned int i; for(i=0;i<2;i++);//temporisation } 6. programme principal void main() {

__CONFIG(RC&WDTDIS&PWRTEN); //oscillateur RC Watch Dog Timer DISable byte compt;

TRISB=0;

compt=eeprom_read(5);Recuperation EEPROM du compteur en 5 PORTB=0;

while(1) {

compt++;

if (g_boutonRAZ==1) compt=0;//remise à zero PORTB=compt;

tempo();//temporisation

(30)

}//fin de while(1) }//fin de main

(31)

8. Exemple 1 de programme en langage C PIC 16F84

/* fichier xx.c dans xx.pjt auteur :

titre : programme de gestion de la carte IUT PIC CAN 2001 cible : pic16F84, compilateur C:\PICLITE\BIN\PICL.EXE */

#include <pic.h>

#define AFFICHEUR PORTB // vers l'afficheur 7 segements

#define DIZAINE RA1 // validation de l'afficheur des dizaines #define UNITE RA0 // validation de l'afficheur des unités

#define CS RA2 // CS du convertisseur TLC548 ou 549 #define H RA3 // Horloge du convertisseur TLC548 ou 549

#define OUT RB7 // Sortie (série) du convertisseur TLC548 ou 549

//transcodage binaire 4 bits 7 segments

unsigned char tab_seg[]={63,6,91,79,102,109,125,7,

127,111,119,124,57,94,121,113};

/*initialisation : PORT B rang 0 à rang 6 en sortie, rang 7 en entrée, PORT A en sortie, CS à 0 et H à 0 */ void init() { TRISB=0x80; TRISA=0x00; CS=1; H=0; }

//temporisation environ 10 microsecondes x delai void tempo(int delai)

{

int i;

for(i=0;i<delai;i++); //boucles }

//lecture du convertisseur analogique-numérique unsigned char lire_convertisseur()

{

unsigned char octet; unsigned char j; octet=0;

CS=0;

tempo(2); //temporisation

for(j=0;j<8;j++) // 8 tops d' horloge { H=1; octet=octet<<1; if (OUT==1) octet=octet|0x01; tempo(2); //temporisation H=0; tempo(2); //temporisation

(32)

CS=1;

return octet; }

//affichage hexadécimal d’un octet void affiche_octet(unsigned char octet) {

UNITE= 1; DIZAINE=0;

AFFICHEUR=tab_seg[octet>>4];

tempo(500); //attendre environ 5 ms DIZAINE=1;

UNITE= 0;

AFFICHEUR=tab_seg[octet&0x0F];

tempo(500); // attendre environ 5 ms }

//programme principal d’affichage de la valeur lue sur le convertisseur void main()

{

unsigned char octet;

__CONFIG(XT&WDTDIS&PWRTEN); //oscillateur XT Watch Dog Timer DISable //__CONFIG(0xF29);// si 16F628 oscillator XT Watch Dog Timer disable //CMCON=7; //si 16F628 PORT B utilisé comme port parallèle

init(); while(1) { octet=lire_convertisseur(); affiche_octet(octet); } }

9. Exemple 2 de programme en langage C PIC 16F84

/* Programme pour la carte IUT2 TP12 fonctions de gestion du LCD

pour essais en pas à pas NBRE_PLACES=5 et tempo2(2) et i<5 dans tempo1 */ #include <pic.h> #define RS RA0 #define RW RA1 #define E RA2 #define BUSY RB7 #define LCD PORTB const NBRE_PLACES=120; char message1[]="120 Places"; char message2[]="Reste ";

//temporisation d'environ 1 milliseconde avec un quartz à 4 MHz

(33)

void tempo1() {

int i;

for(i=0;i<50;i++); }

//temporisation d'environ x millisecondes avec un quartz à 4 MHz void tempo2(int delai)

{ int i; for(i=0;i<delai;i++) { tempo1(); } } //demande d'écriture LCD_clk void LCD_clk() {//debut de la fonction LCD_clk E=1; asm("nop"); //attendre 1µs E=0; }//fin de LCD_clk //fonction d'initialisation du LCD void LCD_init() { TRISA=0x18; TRISB=0;

PORTA=0; //avant la temporisation pour stabiliser les lignes du LCD tempo2(20); LCD=0x3F; RS=0; //mode instruction du LCD RW=0; //écriture dans le LCD LCD_clk(); tempo2(20); LCD=0x0F; RS=0; RW=0; LCD_clk(); tempo2(20); LCD=0x01; RS=0; RW=0; LCD_clk(); tempo2(20); }

//attendre que le LCD soit prêt void LCD_busy()

{

TRISB=0x80; //passe la ligne RB7 en entrée E=1;

RS=0; RW=1;

while(RB7==1); E=0;

TRISB=0x00; //passe la ligne RB7 en sortie }

(34)

//fonction envoi d'un caractère au LCD void LCD_car(char c) { LCD_busy(); RS=1; RW=0; LCD=c; LCD_clk(); }

//écriture d'un message au LCD

void LCD_string(char *message) //*message signifie le contenu de message { while(*message!=0) { LCD_car(*message); message++; } }

//choix de ligne 1 ou 2 et de position du curseur 1 à 16 void LCD_pos(char ligne, char position)

{ char adresse; if(ligne==1) adresse=position-1; if(ligne==2) adresse=position-1+64; LCD_busy(); RS=0; RW=0; LCD=(adresse)|0x80; LCD_clk(); }

//initialisation des ports void PORT_init()

{

TRISA=0x18;//RA3 et RA4 en entrées RA2, RA1, RA0 en sorties TRISB=0x00;// port B en sortie

tempo2(20); } //initialisation du compteur TMR0 void TIMER0_init() { T0SE=0; T0CS=1; PSA=1; TMR0=0; }

//fonction principale d'affichage du nombre de voitures void main()

{

char voitures_disponible;

__CONFIG(XT&WDTDIS&PWRTEN); //si 16F84 osc. XT Watch Dog Timer DISable //__CONFIG(0xF29);// si 16F628 oscillator XT Watch Dog Timer disable //CMCON=7; //si 16F628 PORT B utilisé comme port parallèle

PORT_init();//initialisation des ports

TIMER0_init();//initialisation du compteur TMR0

(35)

LCD_init();//initialisation du LCD

LCD_string(message1);//message premiere ligne LCD_pos(2,1);

LCD_string(message2);//message seconde ligne while(1) { voitures_disponible=NBRE_PLACES-TMR0; LCD_pos(2,14);//ligne 2 position 14 du LCD LCD_car(voitures_disponible/100+0x30);//affichage des centaines LCD_car((voitures_disponible%100)/10+0x30);//des dizaines LCD_car(voitures_disponible%10+0x30);//des unites tempo2(50); } }

Figure

Tableau trié Tableau restant à trier

Références

Documents relatifs

Tous les éléments culturels liés à la langue sont peut-être aussi nombreux que ceux de la culture codifiée et la culture quotidienne, mais les professeurs ne semblent pas

Au centre du monument apparaît une nouvelle couronne de 2 m de diamètre, constituée de blocs aux dimensions sensiblement identiques à ceux de la couronne

Indeed the non-verbal signals sequences contained in these segments will be distributed for different types of attitude variations, and therefore will not be very frequent before

Specifically, given a series of observations x 1:T , which can be noisy, partially and irregularly sam- pled of a dynamical system, DAODEN supposes that the generation process of x

L’archive ouverte pluridisciplinaire HAL, est destinée au dépôt et à la diffusion de documents scientifiques de niveau recherche, publiés ou non, émanant des

Le coût des incendies de résidences lié au tabac est obtenu directement selon les chiffres publiés dans le rapport des coûts de l’abus de substance au Canada (2006) et qui sont

Jean-Luc Godard, Une histoire seule (1b), in Histoire(s) du cinéma, 1998.. tout le projet politique et poétique de Godard et Gorin. En écho aux échecs de Vertov et

O presente trabalho foi concebido graças aos depoimentos de maricultores da AMA (Associação de Maricultores de Anchieta), visando à geração de subsídios que estimulem a criação