{"id":2941,"date":"2025-02-19T12:51:10","date_gmt":"2025-02-19T17:51:10","guid":{"rendered":"https:\/\/ve2cuy.com\/420-1c4\/?page_id=2941"},"modified":"2025-02-19T18:38:42","modified_gmt":"2025-02-19T23:38:42","slug":"operations-non-bloquantes","status":"publish","type":"page","link":"https:\/\/ve2cuy.com\/420-1c4\/index.php\/operations-non-bloquantes\/","title":{"rendered":"Op\u00e9rations non bloquantes"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">1 &#8211; Utilisation de la fonction millis() pour clignoter une DEL<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;Arduino.h>\n\n\/*\n  Blink sans delay()\n  Auteur: Alain Boudreault\n  Date:   2025.02.19\n  Pour:   420-1C4, Objets connect\u00e9s \n*\/\n\nconst int ledPin    = 2;    \/\/ Broche de la DEL\nconst long interval = 500;  \/\/ Intervale de clignotement de la DEL (milliseconds)\nint ledState        = LOW;  \/\/ \u00c9tat de d\u00e9part de la DEL\n\nvoid setup() {\n  pinMode(ledPin, OUTPUT);\n}\n\nvoid loop() {\n  static unsigned long previousMillis = 0;\n  unsigned long currentMillis = millis();\n\n  \/\/ Ex\u00e9cution de code non bloquant pour le clignotement de la LED\n  if (currentMillis - previousMillis >= interval) {\n    \/\/ Enregistrer le temps du dernier clignotement \n    previousMillis = currentMillis;\n\n    ledState = !ledState;             \/\/ Permuter l'\u00e9tat de la DEL\n    digitalWrite(ledPin, ledState);   \/\/ Appliquer de changement\n  }\n} \/\/ loop()<\/pre>\n\n\n\n<p>L&rsquo;avantage de cette approche est que le programme principal (loop()) n&rsquo;est pas bloqu\u00e9 par le d\u00e9lai de contr\u00f4le ON\/OFF de la DEL.  Par contre, le test if() sera ex\u00e9cut\u00e9 \u00e0 chaque it\u00e9ration d&rsquo;appel de la fonction loop().<\/p>\n\n\n\n<p>Dans certain cas, il pourrait \u00eatre plus avantageux d&rsquo;utiliser une interruption mat\u00e9riel ou de compteur.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">2 &#8211; <strong>Interruption<\/strong>s<\/h2>\n\n\n\n<p>Les interruptions permettent de traiter des \u00e9v\u00e9nements asynchrones.  Elles permettent de sortir temporairement du programme principale, pour y ex\u00e9cuter une fonction, puis y retourner.<\/p>\n\n\n\n<p>Les interruptions sont utiles avec les processeurs et les microcontr\u00f4leurs car elles permettent de r\u00e9soudre des probl\u00e8mes de synchronisation. Une bonne application d&rsquo;une interruption est la lecture d&rsquo;un encodeur rotatif ou l&rsquo;observation d&rsquo;une entr\u00e9e utilisateur, par exemple, utilisation d&rsquo;un bouton poussoir. En g\u00e9n\u00e9ral, une ISR (routine de service d&rsquo;interruption) doit \u00eatre aussi courte et rapide que possible. Si un programme utilise plusieurs ISRs, une seule peut \u00eatre ex\u00e9cut\u00e9e \u00e0 la fois. Les autres interruptions seront ex\u00e9cut\u00e9es apr\u00e8s que la routine en cours soit termin\u00e9e, dans un ordre d\u00e9termin\u00e9 par la priorit\u00e9.<\/p>\n\n\n\n<p>Typiquement, des variables globales sont utilis\u00e9es pour transmettre des donn\u00e9es entre une ISR et le programme principal. Pour s&rsquo;assurer que les variables partag\u00e9es entre une ISR et le programme principal sont mises \u00e0 jour correctement, il est recommand\u00e9 de les d\u00e9clarer comme&nbsp;<code><a href=\"https:\/\/en.wikipedia.org\/wiki\/Volatile_(computer_programming)\">volatile<\/a><\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">2.1 &#8211; Quelques caract\u00e9ristiques importantes des interruptions :<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li>Les interruptions peuvent provenir de diverses sources. Dans ce cas, il s&rsquo;agit d&rsquo;une interruption mat\u00e9rielle d\u00e9clench\u00e9e par un changement d&rsquo;\u00e9tat sur l&rsquo;un des pins num\u00e9riques.<\/li>\n\n\n\n<li>L&rsquo;<strong>Arduino  UNO<\/strong> poss\u00e8dent deux interruptions mat\u00e9rielles (appel\u00e9es \u00ab\u00a0interrupt0\u00a0\u00bb et \u00ab\u00a0interrupt1\u00a0\u00bb) c\u00e2bl\u00e9es respectivement sur les pins num\u00e9riques<strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\"> 2 et 3<\/mark><\/strong>.<\/li>\n\n\n\n<li>L&rsquo;<strong>Arduino Mega<\/strong> dispose de six interruptions mat\u00e9rielles, y compris les interruptions suppl\u00e9mentaires (\u00ab\u00a0interrupt2\u00a0\u00bb \u00e0 \u00ab\u00a0interrupt5\u00a0\u00bb) sur les pins <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">21, 20, 19 et 18<\/mark><\/strong>.<\/li>\n\n\n\n<li>Il est possible de d\u00e9finir une routine en utilisant une fonction sp\u00e9ciale appel\u00e9e \u00ab\u00a0Routine de Service d&rsquo;Interruption\u00a0\u00bb (g\u00e9n\u00e9ralement appel\u00e9e ISR).<\/li>\n\n\n\n<li>Il est possible de d\u00e9finir la routine et sp\u00e9cifier les conditions sur le front montant, le front descendant ou les deux. Dans ces conditions sp\u00e9cifiques, l&rsquo;interruption sera trait\u00e9e.<\/li>\n\n\n\n<li>Il est possible d&rsquo;ex\u00e9cuter cette fonction automatiquement chaque fois qu&rsquo;un \u00e9v\u00e9nement se produit sur une broche d&rsquo;entr\u00e9e.<\/li>\n<\/ul>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">3 &#8211; <strong>Types d&rsquo;interruptions<\/strong><\/h2>\n\n\n\n<p>Il existe deux types d&rsquo;interruptions :<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Interruptions mat\u00e9rielles<\/strong>&nbsp;&#8211; Elles se produisent en r\u00e9ponse \u00e0 un \u00e9v\u00e9nement externe, comme un changement de niveau (haut ou bas) sur une broche d&rsquo;interruption externe.<\/li>\n\n\n\n<li><strong>Interruptions logicielles<\/strong>&nbsp;&#8211; Elles se produisent en r\u00e9ponse \u00e0 une instruction envoy\u00e9e par le logiciel.<\/li>\n<\/ol>\n\n\n\n<p><\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">4 &#8211; Exemple &#8211; Traitement d&rsquo;une interruption mat\u00e9rielle.<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;Arduino.h>\n\nvoid blink();\nconst int pin = 2;              \/\/ d\u00e9finir la broche d'interruption \u00e0 2\nconst int ledPin = 4;           \/\/ d\u00e9finir la broche de la LED \u00e0 4\n\nvolatile int state = LOW;      \/\/ Pour garantir que les variables partag\u00e9es entre une ISR et le programme principal \n                               \/\/ soient mises \u00e0 jour correctement, il faut les d\u00e9clarer comme volatile.\n\nvoid setup() {\n   pinMode(ledPin, OUTPUT); \/\/ d\u00e9finir la broche 13 comme sortie\n   attachInterrupt(digitalPinToInterrupt(pin), blink, CHANGE);\n   \/\/ interruption \u00e0 la broche 2, ex\u00e9cute l'ISR blink lorsque la broche change de valeur\n} \n\nvoid loop() { \n  \/\/ digitalWrite(ledPin, state); \/\/ la broche 13 prend la valeur de 'state'\n} \n\nvoid blink() { \n  \/\/ fonction ISR\n  state = !state; \/\/ inverser l'\u00e9tat lorsque l'interruption se produit\n  digitalWrite(ledPin, state); \/\/ la broche 13 prend la valeur de 'state'\n}<\/pre>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">5 &#8211; Interruption &lsquo;Timer&rsquo; pour clignoter une DEL<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">\/*\n    Timer1 est un timer 16 bits. Il est possible de d\u00e9clencher une interruption \n    \u00e0 chaque fois que le compteur atteint une valeur donn\u00e9e.\n\n    Pour ce faire, il faut:\n    1. Renseigner le 'prescaler' du timer\n    2. Renseigner la valeur de comparaison\n    3. Activer l'interruption sur comparaison\n\n   Le prescaler est une division de la fr\u00e9quence d'horloge du microcontr\u00f4leur.\n   Il se peut que le prescaler soit de 1, 8, 64, 256 ou 1024.\n\n   Pour le timer1, les valeurs de bits possibles sont:\n    - CS10: pas de prescaler\n    - CS11: prescaler de 8\n    - CS12: prescaler de 64\n    - CS13: prescaler de 256\n    - CS10 | CS12: prescaler de 1024  \n   \n   Ces bits sont \u00e0 renseigner dans le registre TCCR1B.\n\n   Par exemple, pour un prescaler de 1024, il faut renseigner les bits CS10 et CS11 avec l'instruction suivante:\n    TCCR1B = bit(CS10) | bit(CS11);\n\n    Pour une fr\u00e9quence de 16 MHz, le calcul est le suivant:\n    1 tick = 1\/16 000 000 = 62.5 ns\n    1 ms = 1\/0.0625 = 16 000 ticks\n    1 s = 16 000 * 1000 = 16 000 000 ticks\n*\/\n\n\/\/ Calcule pour le timer1 avec une p\u00e9riode de 2000ms\n\/\/ 2000ms correspond \u00e0 une fr\u00e9quence CTC de 0.5 Hz\n\/\/ Pour une valeur de prescaler de 1024, le registre de comparaison, \n\/\/ OCR1A = 16000000\/(2*1024*0.5) - 1 = 15624\n\n#include &lt;Arduino.h>\n#define DECLENCHEUR_TEMPS   15624 \/\/ Donne une p\u00e9riode d'environ une seconde\n\nbool led_state = false;\n#define LED 4\nvoid setup() {\n  pinMode(LED, OUTPUT);  \n  digitalWrite(LED, 1);\n\n\n  \/\/ D\u00e9sactiver les interruptions globales\n  cli();\n\n  TCCR1A = 0;                                 \/\/\n  TCCR1B = 0;                                 \/\/\n  TCCR1B = bit(CS10) | bit(CS12);             \/\/ Renseigne le 'prescaler' de timer1 \u00e0 1024  \n  TIMSK1 = bit(OCIE1A);                       \/\/ Active le d\u00e9clenchement sur comparaison A avec timer1\n  OCR1A = DECLENCHEUR_TEMPS;                  \/\/ Renseigne la valeur de comparaison pour timer1\n  sei();  \/\/ Activer les interruptions.\n}\n\nvoid loop() {\n  \/\/ Rien \u00e0 faire ici ...\n}\n\n\/\/ Avec les param\u00e8tres d\u00e9finis plus haut, ce vecteur d'interruption (ISR) sera d\u00e9clench\u00e9, environ, \u00e0 chaque 1000ms.\n\/\/ ISR = Interrupt Service Routine\nISR(TIMER1_COMPA_vect) {\n  TCNT1 = 0;  \/\/ Remettre le compteur \u00e0 0\n  led_state = !led_state;\n  digitalWrite(LED,led_state);                \/\/ Allumer ou \u00e9teindre la DEL\n  \/\/ Version alternative\n  \/\/ digitalWrite(LED,!digitalRead(LED));     \/\/ Allumer ou \u00e9teindre la DEL\n}<\/pre>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"528\" src=\"https:\/\/ve2cuy.com\/420-1c4\/wp-content\/uploads\/2025\/02\/timer0-1024x528.png\" alt=\"\" class=\"wp-image-2965\" style=\"width:687px;height:auto\" srcset=\"https:\/\/ve2cuy.com\/420-1c4\/wp-content\/uploads\/2025\/02\/timer0-1024x528.png 1024w, https:\/\/ve2cuy.com\/420-1c4\/wp-content\/uploads\/2025\/02\/timer0-300x155.png 300w, https:\/\/ve2cuy.com\/420-1c4\/wp-content\/uploads\/2025\/02\/timer0-768x396.png 768w, https:\/\/ve2cuy.com\/420-1c4\/wp-content\/uploads\/2025\/02\/timer0.png 1042w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n<p><strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-red-color\">NOTE<\/mark><\/strong>: ISR() est une syntaxe universelle AVR.  Sous Arduino, il est possible d&rsquo;utiliser la fonction d&rsquo;abstraction, attachInterrupt() pour les interruptions mat\u00e9riels.  Par exemple, lorsqu&rsquo;un bouton poussoir est appuy\u00e9.<\/p>\n\n\n\n<p>La programmation des &lsquo;timers&rsquo; d&rsquo;un microcontr\u00f4leurs pose un d\u00e9fi plus grand que le traitement d&rsquo;une interruption mat\u00e9rielle.  Une documentation technique (anglaise) est disponible sur le site de <a href=\"https:\/\/ww1.microchip.com\/downloads\/en\/Appnotes\/Atmel-2505-Setup-and-Use-of-AVR-Timers_ApplicationNote_AVR130.pdf\">MicroChip<\/a>. <\/p>\n\n\n\n<p>Arduino.cc propose aussi une <a href=\"https:\/\/docs.arduino.cc\/tutorials\/generic\/secrets-of-arduino-pwm\/\">introduction aux &lsquo;Timers&rsquo;<\/a> pour la production de signaux de type PWM.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<h2 class=\"wp-block-heading\">Exemple de trace programme avec un Timer.<\/h2>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">#include &lt;Arduino.h>\n\n#define DECLENCHEUR_TEMPS   15624          \/\/ Donne une p\u00e9riode d'environ une seconde\nvoid setTimerINT();\n\nvolatile int etatD1 = LOW;\nvolatile int etatD2 = LOW;\nvolatile int etatD3 = LOW;\nvolatile int etatD4 = LOW;\nvolatile unsigned long tempsActuel = 0;\nchar message[] = \"Hello World!\";\n\n\nvoid setup() {\n  Serial.begin(9600);\n  setTimerINT(); \n}\n\nvoid loop() {\n  tempsActuel++;\n  delay(1000);\n}\n\nvoid setTimerINT(){\n  TCCR1A = 0;                                 \/\/\n  TCCR1B = 0;                                 \/\/\n  TCCR1B = bit(CS12) | bit(CS10);             \/\/ Renseigne le 'prescaler' de timer1 \u00e0 1024  \n  TIMSK1 = bit(OCIE1A);                       \/\/ Active le d\u00e9clenchement sur comparaison A avec timer1\n  OCR1A = DECLENCHEUR_TEMPS;                  \/\/\n  sei();  \/\/ Activer les interruptions.\n}\n\n\/\/ Avec les param\u00e8tres d\u00e9finis dans setTimerINT(), ce vecteur d'interruption (ISR)\n\/\/ sera d\u00e9clench\u00e9, environ, \u00e0 chaque 1000ms.\n\/\/ ISR = Interrupt Service Routine\nISR(TIMER1_COMPA_vect) {\n  TCNT1 = 0;  \/\/ Remettre le compteur \u00e0 0\n  if (tempsActuel % 5 == 0) { \/\/ afficher aux 5 secondes\n    Serial.println(message);\n    Serial.println(etatD1);\n    Serial.println(etatD2);\n    Serial.println(etatD3);\n    Serial.println(tempsActuel);\n  }\n}<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>1 &#8211; Utilisation de la fonction millis() pour clignoter une DEL L&rsquo;avantage de cette approche est que le programme principal (loop()) n&rsquo;est pas bloqu\u00e9 par le d\u00e9lai de contr\u00f4le ON\/OFF de la DEL. Par contre, le test if() sera ex\u00e9cut\u00e9 \u00e0 chaque it\u00e9ration d&rsquo;appel de la fonction loop(). Dans certain cas, il pourrait \u00eatre plus [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"ub_ctt_via":"","footnotes":""},"class_list":["post-2941","page","type-page","status-publish","hentry"],"featured_image_src":null,"_links":{"self":[{"href":"https:\/\/ve2cuy.com\/420-1c4\/index.php\/wp-json\/wp\/v2\/pages\/2941","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ve2cuy.com\/420-1c4\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ve2cuy.com\/420-1c4\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ve2cuy.com\/420-1c4\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/ve2cuy.com\/420-1c4\/index.php\/wp-json\/wp\/v2\/comments?post=2941"}],"version-history":[{"count":20,"href":"https:\/\/ve2cuy.com\/420-1c4\/index.php\/wp-json\/wp\/v2\/pages\/2941\/revisions"}],"predecessor-version":[{"id":2967,"href":"https:\/\/ve2cuy.com\/420-1c4\/index.php\/wp-json\/wp\/v2\/pages\/2941\/revisions\/2967"}],"wp:attachment":[{"href":"https:\/\/ve2cuy.com\/420-1c4\/index.php\/wp-json\/wp\/v2\/media?parent=2941"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}