Aller au contenu


Information tutoriel

  • Ajouté le: mars 19 2018 10:41
  • Date Updated: mars 27 2018 10:44
  • Lectures: 2514
 


* * * * *
0 Notes

Les bases du C avec des instructions en Français

Arduino aide à connecter du matériel et donne des programmes exemples. Mais je suis sûr que le "while" vous trouble encore et que le "for" paraît compliqué avec ses deux point-virgules.
Alors voilà comment j'explique à des jeunes et parfois à des moins jeunes, qui comprennent mieux si on parle leur langue. C'est aussi l'idée de l'apprentissage d'une langue étrangère: les mots sont en phonétique au début.

Posté par jdn on mars 19 2018 10:41

Introduction
Pour apprendre la physique à l'Ecole, on étudie les lois, les formules, et ensuite on expérimente et on peut construire et calculer. C'est un peu notre approche ici. On explique au mieux les instructions de base, on teste et modifie des exemples simples, et on est prêt pour des petites applications (dans les tutos suivantes), avant de crééer les siennes.
 
Pour tester les programmes
 
Vous avez une carte Arduino, une carte à trous et des composants? Il vous faut câbler le schéma ci-dessous.
 LcClear.gif
Le buzzer est une option, on peut beaucoup s'amuser à faire des sons, mais on n'apprend que peu à programmer. Attention, si vous en câblez un, sa résistance doit être supérieure à 30 Ohm avec 30 Ohm en plus. Le mieux est de le piloter avec un transistor, comme sur la carte LcBot.
LcLedPous.jpg
Vous avez une carte LCbot ? C'est mieux, ce sera fiable et vous pourrez continuer à vous perfectionner en suivant le MOOC EPFL, qui propose cette carte pour les exercices complétant le cours.
LcLcClair.jpg
On va faire nos exercies avec seulement 2 poussoirs et 2 Leds, vous serez surpris de voir tout ce que l'on apprend et comprend avec si peu.
 

Oublions le câblage avec une librairie
Le fichier inclus LcClair.h permet de nommer l'état des poussoirs appelés P1 et P2 et l'action sur les Leds   L1On, L1Off,  etc.
Ecrire ce fichier de définitions ne nous intéresse pas maintenant, mais on l'expliquera en annexe (on vous a expliqué une fois les fonctions pinMode, digitalWrite, etc. ? ).
 
Notre librairie LcClair.h doit être incluse avec un #include "LcClair.h" Le setup est la fonction SetupLcClair(); On verra toujours ces deux lignes en haut de nos programmes. De même, le void loop() { } qui est une contrainte de l'environnement Arduino.
 
Les programmes sont court, mais ils ont besoin de la librairie que l'on pourrait cacher avec les librairies Arduino. Chargeons tous les programmes dans un dossier LcClair facilement accessible : Fichier joint  LcClair.zip   625,87 Ko   566 téléchargement(s) aussi disponible en suivant ce lien:  LcClair.zip ( ou tapez www.didel.com/educ/LcClair.zip).
 

Exemple: Clignoter
C'est le premier programme traditionnel. Le delay(); d'Arduino comme toutes les fonctions qu'Arduino a ajouté au C sont utilisables. Nous, on a ajouté L1On; L1Off; etc.  qui nous évite de traîner des digitalWrite.
Voila le premier programme Lc0Cli.ino à charger depuis votre dossier LcClair.
Avant d'exécuter la première fois, vérifiez les choix dans "Outils".
Rappel: vous ne pouvez pas faire un copier-coller de ce programme, il lui faut aussi LcClair.h
//Lc0Cli.ino
#include "LcClair.h"
void setup() {SetupLcClair();}
 
void  loop() {
 L1On; delay(200);
 L1Off; delay(200);
}
On va évidemment modifier les paramètres dans delay();
Mettons delay(10) pour L1On;, On voit que c'est moins intense. Donnons  du mouvement à la carte, on voit les trainées lumineuses qui durent 10ms. On a 5% de PWM, mais notre œil voit plus d'intensité, notre vision est logarithmique.
La fonction L1Tog; (de toggle, basculer, inverser en anglais) économise des instructions et on la verra fréquemment.
 void  loop() {
 L1Tog; delay(200);
}
fait la même chose qu'avant, en 50% quel que soit le délai.
 
Instruction   Si(){}
On va définir 5 fonctions en français. Si vous être débutant, vous allez voir que ce la simplifie la compréhension. Et on reste 100% C, comme avec les digitalWrite dont il faut vous débarasser.
On se débarassera aussi de nos équivalences quand on sera à l'aise. Pour le if() du C, c'est clair que l'appeler Si() ne semble pas clarifier. Mais soyons cohérent avec les définitions suivantes.
Comme programme, copions le poussoir P1 sur la Led L1. Si c'est pressé, on allume; si c'est relâché, on éteint. P1 nomme un état pressé, En C, le ! permet de nommer l'état inverse, relâché. On écrit Si(P1) pour faire qqchose (mis entre accolades) si P1 est vrai, donc pressé.
On écrit Si(!P1) pour faire qqchose si P1 est faux, donc relâché.
Le programme est donc:

//Lc1Copie.ino
#include "LcClair.h" 
void setup() { SetupLcClair();}
void  loop() {
 Si(P1) { L1On; } 
 Si(!P1){ L1Off;} 
}

Le programme passe à travers les instructions du loop à la même vitesse qu'avant.S'il y a des rebonds de contact, ils sont recopiés sur la Led, mais on ne les voit pas.
 
Exercice.
Compléter le programme Copie pour copier simultanément P2 sur L2.

Instruction   Autrement{}
C'est le "else" que vous connaissez déjà et que l'on utilisera assez rarement.
Autrement{} doit suivre immédiatement un Si(){}.
Par exemple, "si on presse, on allume L1, relâché on allume L2" se programme:

//Lc2Autrement.ino
#include "LcClair.h" 
void setup() { SetupLcClair();}
void  loop() {
 Si(P1)    {L1On;  L2Off;}
 Autrement {L1Off; L2On; }
}

Passer au C
 Si(){} est exactement le if(){}
 Autrement{}  est le  else{} La structure if() else if() else  est à éviter (voir switch-case).
Instruction   AttendreQue();
On a vu que le Si(){} teste et passe plus loin instantanément. Pour attendre que l'on presse ou ait fini de presser sur un poussoir, il faut une nouvelle instruction C (le while()), qui s'utilise de 4 façons différentes que l'on va nommer séparément.
 
Exemple: Poussoir On/Off
Par exemple on veut allumer/éteindre la Led comme on le fait avec un interrupteur à poussoir domestique qui a un élément basculant interne.
   Tant que l'on ne presse pas, il ne se passe rien.
   Si on presse on change l'état allumé/éteint.
   Tant que l'on presse, il ne se passe rien.
   Si on relâche, il ne se passe rien.
On peut dire plus simplement:
   On attend que P1 soit pressé
   On change
   On attend que P1 soit relâché, et on recommence.
 
Ce qui se programme

//Lc3Bascule.ino
#include "LcClair.h" 
void setup() { SetupLcClair();}
void  loop() {
  AttendreQue(P1); 
  L1Tog; 
  AttendreQue(!P1);
}

Remarque: AttendreQue() va être utilisé pour attendre sur les poussoirs. Vous savez qu'il y a des rebonds de contact. Un délai est ajouté dans la librairie pour "passer par-dessus".
 
Instruction   RepeterSi (){}
On veut que P1 soit copié sur L1 seulement si P2 est pressé. Donc tant que P2 est pressé, on doit exécuter le groupe d'instructions que l'on a vu en Lc1Copie.ino

//Lc4CopieQuandPermis.ino
#include "LcClair.h" 
void setup() { SetupLcClair();}
void  loop() {
   RepeterSi (P2);
   if(P1) { L1On; }
   if(!P1){ L1Off;} 
}

On voit que si on relâche P2 avant P1, L1 reste allumé. C'est bien l'intention de celui qui a commandé le programme? Pensez à une application industrielle.
Si le but est de ne pouvoir enclencher/déclencher qu'avec l'autorisation, alors c'est le bon programme.
Si le but de P2 est d'autoriser le On seulement si P2 est pressé (double sécurité), alors il faut mettre P1Off quand on relâche P2 et la fonction AttendreQue() n'est pas prévue pour cela, elle ne fait qu'une chose. Il faudra programmer  "tant que P2 est unactif (!P2), L1 est Off; tant que P2 est actif, P1 est copié sur L1". 2 lignes de plus.
 
Voila l'instruction qu'il nous faut pour le probléme de double sécurité. On répète l'action de copie si P2 est pressé. Si non, on force L1 Off.

//Lc5CopieSiPermis.ino
#include "LcClair.h"
void setup() { SetupLcClair();}
void  loop() {
  RepeterSi(P2) { 
    if(P1) { L1On; }
    if(!P1){ L1Off;} 
  }
  L1Off;
} 

Note: TantQue() vous serait plus clair que RepeterSi () ? On a hésité. C'est facile à changer dans le fichier de définition que l'on abandonnera dans 2 heures quand on aura bien compris les subtilités du C.
 


Instruction   Boucler {}
On veut au début du programme décider si c'est L1 ou L2 qui va clignotee. La fonction "ou" existe évidemment, et se note avec 2 fois la barre verticale || (en ctrl-7). Attention, il y a une autre barre verticale vers le 1 qui ne convient pas. Pour le "et" logique, le code est &&.

//Lc6CliL1OuL2.ino
#include "LcClair.h"
void setup() { SetupLcClair();}
void  loop() {
  AttendreQue (P1||P2);
  Si(P1) { 
    Boucler {L1Tog; delay(200);}
  }
  Si(P2) { 
    Boucler {L2Tog; delay(200);}
  }
}

Instruction   Stop;
On ne peut pas arrêter le processeur! Il tourne toujours à exécuter l'instruction suivante. Si on veut qu'il ne fasse plus des instructions que l'on a préparées, il faut lui dire de refaire sans cesse l'instruction ou il boucle sur lui-même. C'est l'instruction Stop; que l'on utilisera plus loin.


 

En C
RepeterSi(v){} est exactement le  while(v){faire si vrai }
Boucler{}      est exactement le  while(1){faire}
Stop;          est exactement le  while(1); ne plus rien faire
AttendreQue(); est  comme   while(!v); DelMs(20);  (supprime les rebonds)    
Rappel important
L'instruction Si(vrai){xx;}  est dite traversante. On teste, si la condition est vraie, on exécute xx et on passe plus loin.
RepeterSi(vrai){xx;} est dit bloquant: on teste la condition et on fait et refait xx tant que la condition est vraie.
AttendreQue(vrai); est bloquant: on attend que la condition soit vraie (on quitte quant elle est vraie, contrairement à RepeterSi).

Instruction  Iterer(n);
Répéter un certain nombre de fois est fréquent. La fonction Iterer(n); a besoin d'un paramètre n qui est un nombre ou une variable de 8 bits
Si c'est pour clignoter, il y a alors tout avantage à utiliser le "Toggle" qui inverse l'état. On a 2 fois moins d'instructions qu'il faut répéter 2 fois plus.

//Lc7Cli3fois.ino
#include "LcClair.h"
void setup() { SetupLcClair();}
void  loop() {
  Iterer (3*2) {
    L1Tog; delay(200);
  }
  delay (1000);
}

Au lieu du delay(1000); ou pourrait mettre le Stop; que l'on vient de voir, pour ne faire qu'une fois. Il faut alors presser sur le bouton reset pour redémarrer le programme, et l'environnement Arduino exécute des milliers d'instructions avant votre programme (avec beaucoup de tests et de boucles d'attente).
Plutôt que le Stop;, pourquoi par utiliser le AttendQue(P1); déjà vu. On recommence le programme instantanément dès que P1 est activé.
Petite question: vous avez compris pourquoi c'est important de noter 3*2 et pas 6 pour dire combien de "Toggle"?
 
SOS
En passant, on pourrait envoyer un SOS   . . .  - - -  . . .

//Lc8SOS.ino On envoie 2 fois le SOS et on stoppe
#include "Clair.h" 
void setup() { SetupClair();}
void  loop() {
  Iterer (2) {
    Iterer (3*2) { LedGToggle; DelMs(200); }
    DelMs(500);
    Iterer (3*2) { LedGToggle; DelMs(600); }
    DelMs(500);
    Iterer (3*2) { LedGToggle; DelMs(200); }
  }
  AttendQue(P1);
}

Humm! Je n'aime pas voir des nombres dans un programme, surtout s'il y a 2 fois le même. Si on change la durée, il faut changer à trois endroits en respectant la proportion entre le trait et le point. Bien documenter, ce n'est pas mettre un commentaire à chaque ligne, c'est définir!

#define Point 200
#define Trait Point*3
#define Espace (Point*5)/2

Dans la boucle on a alors:

  Iterer (2) {
    Iterer (3*2) { LedGToggle; DelMs(Point); }
    DelMs(Espace);
    Iterer (3*2) { LedGToggle; DelMs(Trait); }
    DelMs(Espace);
    Iterer (3*2) { LedGToggle; DelMs(Point); }
  }
  AttendQue(P1);

En C
Iterer(n){} est exactement le   for (byte i=0; i<n; i++) {faire tant que i<n;}
Note: l'instruction  for() est très riche, mais on l'utilise surtout pour répéter.
 
Instruction Echapper
Imaginons que l'on est dans un programme qui clignote sans cesse. Pour en sortir si on presse sur PousG, il y a l'instruction Echapper; , qui permet de s'échapper de ce qui se passe dans l'accolade associée à un RepeterSi, Iterer ou Boucler. Cela sera très utile pour des jeux: il se passe des choses sur les Leds, sur l'écran et il faut réagir. Avec Echapper; on sort "en catastrophe" de cet ensemble d'activité qui modifiait des variables, des  compteurs, et on décide dans le module suivant si c'est bien joué.
Comme exemple simple, on clignote en permanence LedG. PousD interrompt le clignotement; il éteint LedG, allume LedD et stoppe.

//Lc9EchappeCli.ino
#include "LcClair.h" 
void setup() { SetupLcClair();}
void  loop() {
  Boucler {
    L1Tog; DelMs(200);
    Si(P1) {L1Off; Echapper;}
  }
  L2On;
  AttendreQue(P2);
  L2Off;
}

En C
Echapper; est exactement le   break;
 C'est une instruction qui a plusieurs rôles, délicate à bien utiliser.
 
Résumé
Dans une application simple, ou on ne fait qu'une chose à la fois, on attend sur une action de l'utilisateur, on répète une action tant qu'une condition est vraie ou fausse, on itère une action, on doit s'échapper d'une boucle suite à une conditions particulière. Le C a encore une instruction importante, qui permet de choisir parmi des actions numérotées, à découvrir par la suite.
 
La 2e partie parlera des fonctions et tableaux, et traitera quelques exemples en montrant comment faire plusieurs actions simultanées sans s'embarrasser avec des interruptions.