Fonctions en C

De Enseignement secondaire.
Aller à : Navigation, rechercher

Retourner à la page principale

Les fonctions en C, aussi appelées procédures, correspondent aux routines de l’assembleur et elle sont tout aussi indispensables pour écrire un code lisible.

Comme dans tous les langages, les noms doivent être bien choisis, et rappelons l’usage :

Chercher sous Google "règles d'écriture en C".

Sommaire

Routines en assembleur

Les routines en assembleur n’ont pas de règles particulières. Le routine lit et modifie les variables. Le programmeur doit bien documenter les "in-out-mod".

#define et fonctions

Un programmation claire utilise des noms clairs, qui évoquent les fonctions et pas comment elles doivent être réalisées au niveau du processeur.

Le #define donne à un objet, à une instruction d’une ligne un nom choisi avec soin pour être explicite et non ambigü. Par exemple, #define Led0 LATBbits.LATB0 permet ensuite d’écrire Led6 = Allume ;

Si on veut de la même façon faire plusieurs instructions, par exemple dire au robot d’avancer, c’est à dire activer un bit et désactiver l’autre, in faut créer une fonction

void  Avancer () {
  Mot0Pos  = On ;
  Mot0Neg  = Off ;
}

et l’appeler par l’instruction Avancer ;.

Cette fonction (procédure) a la forme la plus simple.

Paramètres dans une fonction

L’instruction delay (val) ; est une fonction avec un paramètre et il faut savoir que ce paramètre est une variable ou une constante 16 bits de type int. Une définition correcte des variables est importante, et pas toujours évidente. Rappelons que l’on utilise ici u8 s8 u16 s16 plutôt que char (u8) et int u16 (ou s16 selon les compilateurs).

Quelques exemples pour clarifier

En "Hello World C" on lit le clavier et affiche des caractères Ascii.

getchar (code) ;   // le code de la touche pressée va dans la variable déclarée  u8 code ; 
   putchar (‘’A’’) ;  // putchar (code) ;  imprime la constante ou la variable.

Pour avoir l’echo à l’écran de ce que l’on tape,

u8 code ;
code = getchar () ;                   
putchar (code) ;

ou

putchar (getchar()) ;


Si on a un robot, une procédure doit calculer une valeur selon le capteur et on écrit distanceGauche = getDistanceGauche (); on a déclaré avant u16 distanceGauche ;

Cette valeur va modifier par exemple la variable s8 pwmG ; (valeurs positives et négatives) qui va être traîtée dans la routine d’interruption par une fonction setVitesseMoteurGauche (pwmG);.

Les instructions qui calculent le pfmG à partir de distanceGauche, une fois au point, seront converties dans une fonction que l’on apellera CalculeVitesse ();.

On remarque que cette fonction est plus complexe, puisqu’elle a un paramètre en entrée nommé distanceGauche et un paramètre en sortie, nommé pfmG.

On programmera en écrivant

distanceGauche = getDistanceGauche () ; 
pfmG = CalculeVitesse (distanceGauche) ; 
setVitesseMoteurGauche (pfmG) ;

Fonction avec des paramètres en entrée

Le void signifie qu’il n’y a pas de paramètre en sortie.

On donne la liste des variables utilisées (paramètres formels), qui n'ont de signification qu'à l'intérieur de la fonction. Le fonction peut aussi agir sur des variables globales, déclarées au début du programme.

Ces variables vont agir avec les entrées sur les sorties (moteur, écran). Des variables temporaires peuvent être déclarées à l’intérieur de la fonction.

void AgirSur (int var1, int var2)
{
   u8 i ;  //variable temporaire 
   // les instructions de la procédure qui utilisent var1 var2 et des variables globales;
}

AgirSur (3,toto) ;

Des variables ne peuvent pas être déclarées entre le void et l’accolade qui suit.

Flash: durée en paramètre

void Flash (u8 duree)  //duree en dixième de secondes
{
   Led = Allume ;
   delai (duree*100);  //att. au dép. de capacité év.
   Led = Eteint ;
   delai (200) ;
}

L’appel se fait avec l’instruction Flash (10) ; // 1 seconde.

Fonction sans paramètres en sortie

void  AllumePhares  (void)
{
  PhareGauche = Allume;
  PhareDroite  = Allume;
}

Cette fonction peut être beaucoup plus complexe, si on allume les phares progressivement.

Dans le programme, on écrit AllumePhares () ;.

Pour éviter de définir AllumePhares et EteintPhares, on pourrait mettre un paramètre qui vaudrait 0 ou 1 et avoir l’instruction SetPhares (Eteint);.

Exemples de programmes pour comparer les façons d’écrire (dans KiCar.zip) KiCarWaitPous.pde --direct KiCarWaitPousF.pde – fonction KiCarWaitPousLib.pde – fonction en librairie

Fonction avec un paramètre en sortie

u8  LirePot  (void)
{
   u8  pot ;
   //les instructions de la procédure ;
   return pot ;
}

u8 dit qu’il que le paramètre en sortie sera de type u8, mais il faut redéclarer ce paramètre au début et dire à la fin, après l’avoir calculé, dire que c’est la valeur de sortie.

La parenthèse vide dit qu’il n’y a pas de paramètres en entrée.

La ligne return peut dire comment obtenir la variable : return (PORTA & 0x0F).

(u8)  LirePortAlow (void)
{
  return (PORTA & 0x0F) ;
}

Utilisation: 4Leds = LirePortAlow () ;.

Un define serait possible dans ce cas #define PortALow (PORTA & 0x0F).

Utilisation: 4Led = PortAlow ;.

Exemple utile: void GetPous (void) test avec KiCarCntPous.pde dans KiCar.zip.

Fonction avec des paramètres en entrée et un seul paramètre en sortie

Les fonctions mathématiques sont les seules expliquées dans les cours sur le C.

On ne peut avoir qu’un seul paramètre en sortie, mais ce paramètre peut être un pointeur qui donne accès à une structure.

u16 Mult (u16 nb1, u16 nb2)
{
  u16 result ;
  result= nb1 * nb2 ;
  return  result ; 
}

Exemple : calcul = Mult (2,3) ; // donc calcul prend la valeur 12

Les multiplications se font en 16 bits seulement.

s8 Asservir (int position, int consigneVitesse)
{
  int pfm ; 
  int i ;  //variable temporaire supplémentaire
  . . .    // les instructions de la procédure ;
  return pfm ;
}

pfmMot1 = Asservir (distance,30) ;

Il faut passer du temps pour choisir les noms, et ne pas hésiter à changer les noms qui deviennent ambigus. Un nom bien choisi évite une tartine d’explications.

Résumé

Fonction.png

Exemple qui montre aussi comment manipuler des mots binaires

La carte Kidule2550 a un port complet à droite (PortB) et un port mélangé à gauche.

Un exercice simple est d’écrire 8 bits d’un côté et des les afficher dans le même ordre de l’autre côté. Avec deux microdules, la vérification est facile.

Le microdule PoToD8 génère des valeurs 8 bits sur le port gauche, qui sont transmises au port B à droite, sur lequel l’ordre des bits correspond à l’ordre des pins.

Kid2550.jpg

Si le port à droite n’était pas mélangé, on écrirait simplement l’instruction PortGauche = PortDroite ;.

Le connecteur gauche rassemble deux ports. Pour former une variable dont les bits sont dans l’ordre des pins, il faut lire RA, garder les bits 0 1 2 3 qui sont à la place qui nous intéresse, puis décaler RA5 pour le mettre en position 4, puis lire RC et décaler les bits 0 1 2 en position 5 6 7, soit décaler de 5 position.

Kid2550Schema.jpg

temp  = PORTA & 0b00011111 ;
temp  = temp | PORTA>>1 & 0b00010000 ;
temp  = temp | PORTC<<5 ;
PORTB = temp ;                                                            

//pour éviter de réfléchir chaque fois, on va faire une fonction GetPortAC (ci contre) qui permet d’écrire 
PORTB = GetPortAC () ;

u8  GetPortAC (void)
{
   int  temp ;
   temp  = PORTA & 0b00011111 ;
   temp  = PORTA<<1 & 0b00010000 ;
   return  temp | (PORTC>>5) ;
}

Pour aller dans l’autre sens il faut une fonction PutPortAC.

// Le programme est (u8 temp déclaré avant)
temp = PORTB ; 
PORTA  = temp&0b00001111 | (temp&0b00010000)<<1 ; 
PORTC  = temp>>5 ;                            

// pour éviter de réfléchir chaque fois, on va faire une fonction (ci-dessous) qui permet d’écrire 
PutPortAC ( PORTB) ;

void PutPortAC (u8 temp)
{
  PORTA  = temp&0b00001111 | (temp&0b00010000)<<1 ;
  PORTC  = temp>>5 ; 
}

La carte PicStar a un processeur différent, ce sont les ports C et E qui sont mélangés.

PicStar.jpg

A vous d’écrire et tester les fonctions GetPortCE et PutPortCE.

Outils personnels
Espaces de noms
Variantes
Actions
Navigation
Boîte à outils