[ Arduino 202] Introduire le temps

C’est bien beau d’allumer une LED, mais si elle ne fait rien d’autre, ce n’est pas très utile. Autant la brancher directement sur une pile (avec une résistance tout de même ! 😛 ). Alors voyons comment rendre intéressante cette LED en la faisant clignoter ! Ce que ne sait pas faire une pile… Pour cela il va nous falloir introduire la notion de temps. Et bien devinez quoi ? Il existe une fonction toute prête là encore ! Je ne vous en dis pas plus, passons à la pratique !

Comment faire ?

Trouver la commande…

Je vous laisse cherche un peu par vous même, cela vous entrainera ! :Pirate: … Pour ceux qui ont fait l’effort de chercher et n’ont pas trouvé (à cause de l’anglais ?), je vous donne la fonction qui va bien : On va utiliser : delay() Petite description de la fonction, elle va servir à mettre en pause le programme pendant un temps prédéterminé.

Utiliser la commande

La fonction admet un paramètre qui est le temps pendant lequel on veut mettre en pause le programme. Ce temps doit être donné en millisecondes. C’est-à-dire que si vous voulez arrêter le programme pendant 1 seconde, il va falloir donner à la fonction ce même temps, écrit en millisecondes, soit 1000ms. Le code est simple à utiliser, il est le suivant :

Rien de plus simple donc. Pour 20 secondes de pause, il aurait fallu écrire :

Mettre en pratique : faire clignoter une LED

Du coup, si on veut faire clignoter notre LED, il va falloir utiliser cette fonction. Voyons un peu le schéma de principe du clignotement d’une LED :

Vous le voyez, la LED s’allume. Puis, on fait intervenir la fonction delay(), qui va mettre le programme en pause pendant un certain temps. Ensuite, on éteint la LED. On met en pause le programme. Puis on revient au début du programme. On recommence et ainsi de suite. C’est cette somme de commande, qui forme le processus qui fait clignoter la LED.

Dorénavant, prenez l’habitude de faire ce genre de schéma lorsque vous faites un programme. Cela aide grandement la réflexion, croyez moi ! 😉 C’est le principe de perdre du temps pour en gagner. Autrement dit : l’organisation !

Maintenant, il faut que l’on traduise ce schéma, portant le nom d’organigramme, en code. Il suffit pour cela de remplacer les phrases dans chaque cadre par une ligne de code. Par exemple, « on allume la LED », va être traduis par l’instruction que l’on a vue dans le chapitre précédent :

Ensuite, on traduit le cadre suivant, ce qui donne :

Puis, on traduit la ligne suivante :

Enfin, la dernière ligne est identique à la deuxième, soit :

On se retrouve avec le code suivant :

La fonction qui va boucler à l’infini le code précédent est la fonction loop(). On inscrit donc le code précédent dans cette fonction :

Et on n’oublie pas de définir la broche utilisée par la LED, ainsi que d’initialiser cette broche en tant que sortie. Cette fois, le code est terminé !

Vous n’avez plus qu’à charger le code dans la carte et admirer mon votre travail ! La LED clignote ! Libre à vous de changer le temps de clignotement : vous pouvez par exemple éteindre la LED pendant 40ms et l’allumer pendant 600ms :

Et Hop, une petite vidéo d’illustration !

Faire clignoter un groupe de LED

Vous avouerez facilement que ce n’était pas bien difficile d’arriver jusque-là. Alors, à présent, accentuons la difficulté. Notre but : faire clignoter un groupe de LED.

Le matériel et les schémas

Ce groupe de LED sera composé de six LED, nommées L1, L2, L3, L4, L5 et L6. Vous aurez par conséquent besoin d’un nombre semblable de résistances. Le schéma de la réalisation :

Schéma avec 6 leds

La photo de la réalisation :

Montage avec 6 leds

Le programme

Le programme est un peu plus long que le précédent, car il ne s’agit plus d’allumer 1 seule LED, mais 6 ! Voilà l’organigramme que va suivre notre programme :

Cet organigramme n’est pas très beau, mais il a le mérite d’être assez lisible. Nous allons essayer de le suivre pour créer notre programme. Traduction des six premières instructions :

Ensuite, on attend 1,5 seconde :

Puis on traduis les six autres instructions :

Enfin, la dernière ligne de code, disons que nous attendrons 4,32 secondes :

Tous ces bouts de code sont à mettre à la suite et dans la fonction loop() pour qu’ils se répètent.

Je l’ai mentionné dans un de mes commentaires entre les lignes du programme, les noms attribués aux broches sont à changer. En effet, car si on définit des noms de variables identiques, le compilateur n’aimera pas ça et vous affichera une erreur. En plus, le micro-contrôleur ne pourrait pas exécuter le programme car il ne saurait pas quelle broche mettre à l’état HAUT ou BAS. Pour définir les broches, on fait la même chose qu’à notre premier programme :

Maintenant que les broches utilisées sont définies, il faut dire si ce sont des entrées ou des sorties :

Le programme final

Il n’est certes pas très beau, mais il fonctionne :

Voilà, vous avez en votre possession un magnifique clignotant, que vous pouvez attacher à votre vélo ! 😛

Une question me chiffonne. Doit-on toujours écrire l’état d’une sortie, ou peut-on faire plus simple ?

Tu soulèves un point intéressant. Si je comprends bien, tu te demandes comment faire pour remplacer l’intérieur de la fonction loop()? C’est vrai que c’est très lourd à écrire et à lire ! Il faut en effet s’occuper de définir l’état de chaque LED. C’est rébarbatif, surtout si vous en aviez mis autant qu’il y a de broches disponibles sur la carte ! Il y a une solution pour faire ce que tu dis. Nous allons la voir dans quelques chapitres, ne sois pas impatient ! 😉 En attendant, voici une vidéo d’illustration du clignotement :

Réaliser un chenillard

Le but du programme

Le but du programme que nous allons créer va consister à réaliser un chenillard. Pour ceux qui ne savent pas ce qu’est un chenillard, je vous ai préparé une petite image .gif animée :

Comme on dit souvent, une image vaut mieux qu’un long discours ! 😛 Voilà donc ce qu’est un chenillard. Chaque LED s’allume alternativement et dans l’ordre chronologique. De la gauche vers la droite ou l’inverse, c’est au choix.

Organigramme

Comme j’en ai marre de faire des dessins avec paint.net, je vous laisse réfléchir tout seul comme des grands à l’organigramme du programme. … Bon, aller, le voilà cet organigramme ! Attention, il n’est pas complet, mais si vous avez compris le principe, le compléter ne vous posera pas de problèmes :

Secret: Réponse SelectionnerAfficher
A vous de jouer !

Le programme

Normalement, sa conception ne devrait pas vous poser de problèmes. Il suffit en effet de récupérer le code du programme précédent (« allumer un groupe de LED ») et de le modifier en fonction de notre besoin. Ce code, je vous le donne, avec les commentaires qui vont bien :

Vous le voyez, ce code est très lourd et n’est pas pratique. Nous verrons plus loin comment faire en sorte de l’alléger. Mais avant cela, un TP arrive… Au fait, voici un exemple de ce que vous pouvez obtenir !

Fonction millis()

Nous allons terminer ce chapitre par un point qui peutêtre utile, notamment dans certaines situations où l’on ne veut pas arrêter le programme. En effet, si on veut faire clignoter une LED sans arrêter l’exécution du programme, on ne peut pas utiliser la fonction delay() qui met en pause le programme durant le temps défini.

Les limites de la fonction delay()

Vous avez probablement remarqué, lorsque vous utilisez la fonction « delay() » tout notre programme s’arrête le temps d’attendre. Dans certains cas ce n’est pas un problème mais dans certains cas ça peut être plus gênant. Imaginons, vous êtes en train de faire avancer un robot. Vous mettez vos moteurs à une vitesse moyenne, tranquille, jusqu’à ce qu’un petit bouton sur l’avant soit appuyé (il clic lorsqu’on touche un mur par exemple). Pendant ce temps-là, vous décidez de faire des signaux en faisant clignoter vos LED. Pour faire un joli clignotement, vous allumez une LED rouge pendant une seconde puis l’éteignez pendant une autre seconde. Voilà par exemple ce qu’on pourrait faire comme code

Attention ce code n’est pas du tout rigoureux voire faux dans son écriture, il sert juste à comprendre le principe !

Maintenant imaginez. Vous roulez, tester que le bouton n’est pas appuyé, donc faites clignoter les LED (cas du else). Le temps que vous fassiez l’affichage en entier s’écoule 2 longues secondes ! Le robot a pu pendant cette éternité se prendre le mur en pleine poire et les moteurs continuent à avancer tête baissée jusqu’à fumer ! Ce n’est pas bon du tout ! Voici pourquoi la fonction millis() peut nous sauver.

Découvrons et utilisons millis()

Tout d’abord, quelques précisions à son sujet, avant d’aller s’en servir. A l’intérieur du cœur de la carte Arduino se trouve un chronomètre. Ce chrono mesure l’écoulement du temps depuis le lancement de l’application. Sa granularité (la précision de son temps) est la milliseconde. La fonction millis() nous sert à savoir quelle est la valeur courante de ce compteur. Attention, comme ce compteur est capable de mesurer une durée allant jusqu’à 50 jours, la valeur retournée doit être stockée dans une variable de type « long ».

C’est bien gentil mais concrètement on l’utilise comment ?

Et bien c’est très simple. On sait maintenant « lire l’heure ». Maintenant, au lieu de dire « allume-toi pendant une seconde et ne fais surtout rien pendant ce temps », on va faire un truc du genre « Allume-toi, fais tes petites affaires, vérifie l’heure de temps en temps et si une seconde est écoulée, alors réagis ! ». Voici le code précédent transformé selon la nouvelle philosophie :

Et voilà, grâce à cette astuce plus de fonction bloquante. L’état du bouton est vérifié très fréquemment ce qui permet de s’assurer que si jamais on rentre dans un mur, on coupe les moteurs très vite. Dans ce code, tout s’effectue de manière fréquente. En effet, on ne reste jamais bloqué à attendre que le temps passe. A la place, on avance dans le programme et test souvent la valeur du chronomètre. Si cette valeur est de 1000 itérations supérieures à la dernière valeur mesurée, alors cela signifie qu’une seconde est passée.

Attention, au « if » de la ligne 25 ne faites surtout pas « millis() – temp == 1000 ». Cela signifierait que vous voulez vérifier que 1000 millisecondes EXACTEMENT se sont écoulées, ce qui est très peu probable (vous pourrez plus probablement mesurer plus ou moins mais rarement exactement)

Maintenant que vous savez maîtriser le temps, vos programmes/animations vont pouvoir posséder un peu plus de « vie » en faisant des pauses, des motifs, etc. Impressionnez-moi !

61 commentaires

    • Tout a fait !! J’ai du faire une betise au moment de l’import depuis le SdZ vu que la version en ligne la bas est bonne (tout mes symboles inferieur et superieur c’était transformé en entité HTML, il a fallu faire des révisions à la main).
      Merci de la remarque, c’est corrigé !

  1. Bonjour,

    Peut être vous l’a t’on déjà signalé mais il y aurait une erreur sur le schéma de câblage du chenillard dans la version pdf du livre… L’arrivé du 5v dans la 1ère LED (la première en partant du bas) est une case trop basse !

    Merci pour votre travail ! Bon courage !

  2. Salut,
    Ne faut-il pas initialiser la variable temps dans ton dernier code ? sinon je ne comprends pas trop comment il compare millis() – temps au premier passage…
    en tout cas merci pour ton cours 😉

    • Effectivement voila qui est corrige, c’est plus propre ! Cependant, la variable se serait vu initialise a 0 automatiquement par le compilateur, donc il y aurais juste eu la première boucle qui n’aurais pas forcement le temps escompté.

  3. Bonjour, Bravo et merci pour ce cours très sympa à étudier. J’ai une question, bête surement, mais ça me chagrine: Pourquoi mettre une résistance à chaque led au gnd alors que 1 suffirait au 5v, puisquu’il n’y en a qu’une qui s’éclaire à la fois ?

    • Ce serait vrai dans ce cas là, mais ne l’est plus dès que deux leds sont allumées en même temps ou que l’on utilise des couleurs différentes (qui sont censé avoir des chutes de tensions différentes). Du coup « Oui sur le principe » mais autant prendre de bons réflexes pour la suite 😉

  4. Merci pour votre réponse ! J’ai déjà une autre question : puisqu’on a plusieurs LED en dérivation dans notre circuit, les intensités sont donc logiquement inférieures à 20mA, peut-on utiliser des résistances de 10ohm (1.2/6*0.02) ?

    • Comment ca ? Chaque LED veut 20 mA et 1.2V (admettons). Donc chaque branche verra passer 20mA et chaque résistance devra s’occuper des 5-1.2 = 3.8V restant. Chaque branche est bien indépendante. D’où ma question sur ta question : Pourquoi les intensités seraient inférieur a 20mA ? 😉

      • Et bien je pensais que les 20mA seraient divisés en 6 à cause des 6 LED (je n’ai pas acquis toute la logique en électronique) ! Par contre si on met des résistances trop élevées par rapport à 190ohm dans notre exemple, l’intensité des LED sera cette fois-ci réellement inférieure à 20mA, non ?

  5. merci pour ce beau tuto mais moi je veux par exemple incrémenter et décrémenter un compteur (qui s’affiche) selon que l’on appui sur un bouton ou sur l’autre. Comment la fonction millis aide-t-elle dans ce cas? Merci

    • Dans ce cas la fonction millis n’est pas forcement utile, d’ailleurs tu n’auras pas besoin de delay ou de pause en générale non plus. Tu auras surtout besoin de faire une détection de front (changement d’etat) pour être sur qu’un appui ne sera pas détecté plusieurs fois.

  6. bonjour merci infiniment pour ce cour ,, alors moi j’étudie le microcontrôleur 80C535 , et j’arrive pas a faire des programmes en langage assembleur de ce type ( allumage et extinction des diodes , alarme …) 🙁 j ‘ai cherché sur internet des exercices avec correction pour bien assimiler ça mais j’ai rien trouvé ,, maintenant j’ai tombé sur votre blog intéressant,, si vous pouvez m’aider svp :))

  7. Bonsoir , petite correction ( je pense).
    « notamment dans certaines situations où l’on veut ne pas arrêter le programme. »
    notamment dans certaines situations où l’on ne veut pas arrêter le programme?
    Détail à la con, car vos articles sont très bien écrits et très clairs. je tiens d’ailleurs à vous remercier pour ce partage .
    Bonne continuation à vous

  8. Bonjour, j’apprécie énormément votre tutoriel. Je me demandais si il était possible de mettre l’ensemble des LEDs en série avec une seule résistance (qui se trouverait en amont sur le schéma), et si c’est à éviter, y a-t-il une raison particulière à ça ?
    Merci d’avance

    • Pour un schema particulier ou c’est une question d’ordre plus général ? Si on considère que les leds ont une tension a leur borne d’environ 1.6V, avec 5V on peut en alimenter 3 en série, ce qui produira une chute de tension de 4.8V. Il restera alors 0.2V a utiliser avec la resistance de limitation de courant pour limiter a 20mA. R=U/I = 0.2/0.02 = 10 ohm.

      Par exemple.

  9. bonjour,
    j’utilise 3 leds et un bouton je souhaiterai allumer 2 leds avec le bouton jusque là pas de problème ensuite j’aimerai allumer la 3eme led environ 5 seconde après l’appui du bouton avec la fonction millis et ensuite l’éteindre 5 seconde après pouvez vous m’expliquer se qui ne va pas dans mon code merci

    Secret SelectionnerAfficher
    • Salut !

      Je te propose de créer un sujet sur le forum de Zeste de Savoir (rubrique « Systèmes et Matériel ») pour debugguer ensemble ton programme (et garder cette zone de commentaire pour parler du tutoriel lui-même). Il faudra cependant être un peu plus précis sur le « ca ne marche pas » et expliquer ce qui se passe.

  10. Bonjour !
    Très beau boulot 😉
    Pourquoi dans mon chenillard, au départ seulement, toutes les diodes s’allument ensembles, avant de s’éteindre une par une, puis suivre correctement le programme ? Cela a-t-il à voir avec un état haut par défaut des sorties utilisées ?

    Merci !

      • Voilà ce que j’ai écrit :
        #include
        #include
        #define RELAY1 5

        RTC_DS1307 RTC;

        void setup()
        {
        Serial.begin(57600);
        Wire.begin();
        RTC.begin();

        pinmode(8,output);

        }

        void loop()
        {
        DateTime now = RTC.now();

        if (now.hour() == 07 && now.minute() < 01) // Led off
        {
        digitalWrite(RELAY1,1); // Turns off Relays 1
        }

        if (now.hour() == 19 && now.minute() < 01 ) // Led on
        {
        digitalWrite(RELAY1,0); // Turns ON Relays 1

        ************************
        la sortie 1 du relais commande le tube fluo
        je n'est pas de quoi testé le programme

  11. Bonjour,

    L’initialisation n’est (sauf erreur de ma part) pas présente dans la version pdf du tuto.

    En tout cas, gros merci ! Ce tuto est telllemmeeennttt pedagogique ! 🙂

  12. Bonjour Eskimon

    Je vais pas être très original par rapport aux autres commentaires mais grand merci pour ce blog et le tuto.
    Au départ : un projet de créer l’ouverture et la fermeture d’un poulailler et me voilà à dévorer ton tuto alors que je n’ai aucune base en électronique… Encore MERCI.

    Même remarque que Basile Longchamp pour le chenillard, les LEDs sont toutes allumées lors du début de la boucle. Ma solution (avant de tomber sur les commentaires lol) a bien été de placer toutes les LEDs sur HIGH

    Ceci dit, je ne comprends pas la logique qui veut que par défaut les LEDS sont allumées avant d’avoir donné la première instruction… Est-ce ainsi de tous les OUTPUT ?

  13. bonjour,
    je trouve que ce tuto est super, ça fait un bon bout de temps déjà que je le lis. Seulement, j’ai un petit problème avec la fonction « millis() ». J’ai écrit un code plutôt cour pour comprendre son fonctionnement. Le code devrait juste allumer une LED et puis l’eteindre à intervalle de 2 secondes. Mais après compilation et après avoir téléversé les le code, la LED ne réagit pas comme prévu. Est ce que vous pouvez m’aider à comprendre mon erreur? Merci d’avance.
    voici le code utilisé:

    char led=4;
    long time;
    void setup() {
    pinMode(led, OUTPUT);

    }
    void loop(){
    time=millis();
    digitalWrite(led, HIGH);
    if((millis()-time)>2000) {
    digitalWrite(led, LOW);
    }
    time=millis();
    if((millis()-time)>2000) {
    digitalWrite(led, HIGH);
    }
    }

    • salut !
      Pourais je savoir pourquoi le code est exécuté différemment lorsque j’affecte le temps en cours à la variable « time » à l’intérieur des conditions (le code est le suivant)?
      char led=4;
      long time;
      void setup() {
      pinMode(led, OUTPUT);

      }
      void loop(){
      digitalWrite(led, HIGH);
      if((millis()-time)>2000) {
      time=millis();
      digitalWrite(led, LOW);
      }
      if((millis()-time)>2000) {
      time=millis();
      digitalWrite(led, HIGH);
      }
      }
      j’ai dû effectuer certaines transformations dans le code en essayant de comprendre la fonction « millis() » et me suis rendu compte qu’en utilisant le code ci-dessus la lampe s’allume puis s’éteint, seulement l’intervalle de temps entre les deux états est plus grand que prévu. Au lieu de 2 secondes la lampe change d’état après environ 10 secondes et en plus la durée de repos est irréguliére. et en changeant le signe de comparaison de supériorité « > » en un « >= » l’intervalle de temps est plus réduit.
      Est qu’une personne sait à quoi c’est dû?

      • Le souci est que c’est toujours le premier if qui sera vrai, et jamais le second (car la variable time aura été remis à millis() dès le premier cas). Il faut rajouter l’observation de l’état de la led dans les conditions.

  14. Pingback: Arduino | Pearltrees

  15. Bonjour dans if((millis() – temps) > 1000) je comprends que la LED vas clignoter toute les 1,001 secondes. Si l’on veux être plus précis serai t’il pas plus juste de mettre if((millis() – temps) = /*ou*/ >= 1000) ?

  16. Pingback: Arduino | Pearltrees

  17. Bonsoir, je débute avec arduino et j’ai une carte mère funduino uno. j’ai essayé le programme du chenillard j’ai fait mon montage et le code, mais probleme lors du téléversement, pas de messages d’erreur, c’est sur ma carte mère que des LED clignotent (TX ,RX et L) et pas sur mon montage.
    Si quelqu’un pouvait m’aider s’il vous plaît,
    Merci d’avance

  18. Bonjour,

    Nous sommes en 1ère et dans le cadre de notre TPE nous avons besoin de créer un programme arduino qui en fonction d’une valeur obtenue avec un capteur FSR03 nous permettrait de déclencher un chronomètre à partir d’une certaine valeur et de l’arrêter à partir d’une autre valeur. Nous avons déjà un programme arduino qui nous permet d’obtenir la valeur du capteur et nous avons besoin d’un programme qui nous permettrait de déclencher et d’arrêter le chronomètre ainsi que d’afficher la valeur finale du chronomètre sur un écran LCD arduino. Nous ne savons pas du tout comment créer ce programme et nous aurions besoin d’aide.
    Merci d’avance.

    • Afin de garder cette section de commentaire pour les questions sur le tuto en lui-même, pourriez-vous aller créer un sujet dans le forum « Systèmes et matériel » des forums de zeste de savoir ? J’y passe régulièrement et il y a plein de gens compétents là bas qui pourront aussi vous aider 🙂

  19. bonjour monsieur le cerf … j’ai un question plutot urgente qui conserne arduino, au debut de mon code je veut que le programe ne commence que si j’appuie sur un bouton-poussoir préci mais je ne veut pas utiliser if(machinmachin == turc) est-ce-que c’est possible ? merci d’avance

  20. Bonjour Eskimon,
    Vous avez fait un tuto formidable.
    J’ai appris a programmer sur ATARI 130XE il y a 30 ans et j’ai 70 balais aujourd’hui. Je remonte un train électrique pour mes petits enfants, et pour moi aussi. J’ai donc décidé d’être moderne et d’essayer de le moderniser.

    Je reprends tout à zéro avec ARDUINO? J’ai fais les frais de tout ce que vous avez préconisé et j’ai fais mes deux premiers programmes. Enfin, je les ai recopier.
    Ca ne marche pas!, il y a une ligne qui m’embarrasse. La ligne 10 ou 19 suivant le programme copier. C’est une ligne en l’air. (c’est moi qui a mis les astérisques)

    1long temps; //variable qui stocke la mesure du temps
    2boolean etat_led;
    3
    4void setup()
    5{
    6 pinMode(moteur, OUTPUT);
    7 pinMode(led, OUTPUT);
    8 pinMode(bouton, INPUT);
    9 //on met le moteur en marche
    10 digitalWrite(moteur, HIGH);
    11 //par défaut la LED sera éteinte
    12 etat_led = 0;
    13 //on éteint la LED
    14 digitalWrite(led, etat_led);
    15
    16 //on initialise le temps
    17 temps = millis();
    18}
    19 ***************
    20void loop()
    21{
    22 //si le bouton est cliqué (on rentre dans un mur)
    23 if(digitalRead(bouton)==HIGH)
    24 {
    25 //on arrête le moteur
    26 digitalWrite(moteur, LOW);
    27 }
    28 else //sinon on clignote
    29 {
    30 //on compare l’ancienne valeur du temps et la valeur sauvée
    31 //si la comparaison (l’un moins l’autre) dépasse 1000…
    32 //…cela signifie qu’au moins une seconde s’est écoulée
    33 if((millis() – temps) > 1000)
    34 {
    35 etat_led = !etat_led; //on inverse l’état de la LED
    36 digitalWrite(led, etat_led); //on allume ou éteint
    37 temps = millis(); //on stocke la nouvelle heure
    38 }
    39 }
    40}
    Cette ligne interpelle l’erreur <>

    Pourriez-vous me renseigner sur quoi faire?

    Merci à vous

    BFC

Laisser un commentaire