• Li chevron_right

      TapTempo pour Arduino Uno

      xulops · pubsub.eckmul.net / linuxfr_news · Wednesday, 23 December, 2020 - 11:01 · 25 minutes

    <div><p>Puisqu’elle n’existe pas encore, voici une version de TapTempo pour Arduino Uno, utilisant Arduino IDE sous Linux.</p> <p>Arduino est une marque italienne proposant des cartes de développement open-source basées sur des micro-contrôleurs AVR, ARM et Cortex-A3.</p> <p>L’Arduino Uno est la carte la plus connue et la plus accessible : compter environ deux euros en Chine pour des copies d’Arduino, et moins de dix euros en France. Elle est équipée d’un micro-contrôleur Atmel ATmega328P, dont les caractéristiques techniques sont : architecture Atmel AVR, 16MHz, 8bit, 32ko Flash, 1ko EEPROM, 2ko de SRAM. On est donc loin des PC avec CPU en GHz et RAM en Go.</p> </div><ul><li>lien nᵒ 1 : <a title="https://linuxfr.org/wiki/taptempo" hreflang="fr" href="https://linuxfr.org/redirect/107546">Le projet TapTempo</a></li><li>lien nᵒ 2 : <a title="https://linuxfr.org/news/taptempo-en-verilog" hreflang="fr" href="https://linuxfr.org/redirect/107547">TapTempo en Verilog</a></li><li>lien nᵒ 3 : <a title="https://linuxfr.org/news/portage-de-taptempo-en-vhdl" hreflang="fr" href="https://linuxfr.org/redirect/107548">Portage de TapTempo en VHDL</a></li><li>lien nᵒ 4 : <a title="https://fr.wikipedia.org/wiki/Arduino" hreflang="fr" href="https://linuxfr.org/redirect/107569">Page wikipédia Arduino</a></li><li>lien nᵒ 5 : <a title="https://www.arduino.cc/" hreflang="fr" href="https://linuxfr.org/redirect/107570">Site officiel Arduino</a></li><li>lien nᵒ 6 : <a title="https://www.arduino.cc/en/guide/linux" hreflang="en" href="https://linuxfr.org/redirect/107571">Installation d’Arduino IDE sous Linux</a></li><li>lien nᵒ 7 : <a title="https://randomnerdtutorials.com/" hreflang="en" href="https://linuxfr.org/redirect/107572">Site sur les IoT à base d’Arduino, ESP8266, ESP32 et leurs capteurs/accessoires</a></li></ul><div><h2 class="sommaire">Sommaire</h2> <ul class="toc"> <li><a href="#toc-les-avantages-de-la-carte">Les avantages de la carte</a></li> <li><a href="#toc-le-programme">Le programme</a></li> <li><a href="#toc-les-fonctions-setup-et-loop">Les fonctions setup et loop</a></li> <li><a href="#toc-usage-m%C3%A9moire">Usage mémoire</a></li> <li><a href="#toc-avec-dautres-micro-contr%C3%B4leurs">Avec d’autres micro-contrôleurs</a></li> </ul> <h2 id="toc-les-avantages-de-la-carte">Les avantages de la carte</h2> <p>Les avantages de cette carte sont :</p> <ul> <li>14 entrées/sorties numériques, dont 6 PWM ;</li> <li>6 entrées analogiques ;</li> <li>port série, bus I2C et SPI ;</li> <li>consommation électrique autour de 50mA sous 5V ;</li> <li>un nombre phénoménal de capteurs et accessoires en tous genres et pas chers (shield moteur, capteurs ultrason, température, pression, humidité, vibration…) ;</li> <li>un port USB pour transférer le programme dans le micro-contrôleur, et retourner des infos au PC via le port série de la carte ;</li> <li>un IDE (Arduino IDE sous GPL 2.0) qui fonctionne sous Linux et prend en charge toute la partie transfert du code. Il fait également office de moniteur série, et plotter/grapheur bien pratique pour suivre l’évolution de valeurs de capteurs dans le temps.</li> </ul> <p>C’est donc une carte simple et idéale pour apprendre à faire des robots, automatiser sa serre de jardin ou son aquarium, faire une serrure à carte sans contact, etc.</p> <p>Pour l’exemple TapTempo, j’utilise une « Funduino UNO », copie chinoise à bas prix, un écran LCD de deux lignes de 16 caractères avec interface I2C, et un bouton poussoir câblé entre l’entrée numérique n°2 et la masse.</p> <p><img src="//img.linuxfr.org/img/68747470733a2f2f78756c6f70732e6e65742f696d6167652f61757472652f61726475696e6f5f756e6f5f636f6d70617469626c652e6a7067/arduino_uno_compatible.jpg" alt="Copie chinoise d’Arduino Uno" title="Source : https://xulops.net/image/autre/arduino_uno_compatible.jpg"></p> <p>Comme je n’aime pas les câbles Dupont mâles, j’utilise ici une carte supplémentaire qui vient se poser sur l’Arduino Uno, qui ne fait que rendre plus accessible les pins de connexion (un sensor shield). C’est facultatif et ça marche très bien sans. Le câblage est d’ailleurs simple à réaliser.</p> <p><img src="//img.linuxfr.org/img/68747470733a2f2f78756c6f70732e6e65742f696d6167652f61757472652f736368656d615f6361626c6167652e706e67/schema_cablage.png" alt="Câblage du TapTempo sur Arduino Uno" title="Source : https://xulops.net/image/autre/schema_cablage.png"></p> <h2 id="toc-le-programme">Le programme</h2> <p>Le programme est écrit dans Arduino IDE qui permet de faire du C et C++. On peut utiliser d’autres IDE et d’autres langages (LUA, microPython). Voici le TapTempo basique :</p> <pre><code class="c"> <span class="cp">#include</span> <span class="cpf">&lt;LiquidCrystal_I2C.h&gt;</span><span class="cp"></span> <span class="cp">#include</span> <span class="cpf">&lt;Wire.h&gt;</span><span class="cp"></span> <span class="n">LiquidCrystal_I2C</span> <span class="nf">lcd</span><span class="p">(</span><span class="mh">0x27</span><span class="p">,</span><span class="mi">16</span><span class="p">,</span><span class="mi">2</span><span class="p">);</span> <span class="c1">// parametres de l'ecran à cristaux liquides</span> <span class="c1">// quelques constantes et variables globales</span> <span class="k">const</span> <span class="n">byte</span> <span class="n">TAP_PIN</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span> <span class="c1">// bouton poussoir connecté sur l'entrée 2</span> <span class="kt">bool</span> <span class="n">bouton_status</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">t</span><span class="p">[</span><span class="mi">6</span><span class="p">];</span> <span class="c1">// stocke 6 taps pour avoir 5 intervalles</span> <span class="n">byte</span> <span class="n">i</span><span class="p">;</span> <span class="n">byte</span> <span class="n">n</span><span class="p">;</span> <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">tempo</span><span class="p">;</span> <span class="kt">void</span> <span class="nf">setup</span><span class="p">()</span> <span class="p">{</span> <span class="n">lcd</span><span class="p">.</span><span class="n">init</span><span class="p">();</span> <span class="n">lcd</span><span class="p">.</span><span class="n">backlight</span><span class="p">();</span> <span class="n">lcd</span><span class="p">.</span><span class="n">setCursor</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">0</span><span class="p">);</span> <span class="n">lcd</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"TapTempo Arduino"</span><span class="p">);</span> <span class="n">lcd</span><span class="p">.</span><span class="n">setCursor</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="mi">1</span><span class="p">);</span> <span class="n">lcd</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"Tempo : ...."</span><span class="p">);</span> <span class="n">pinMode</span><span class="p">(</span><span class="n">TAP_PIN</span><span class="p">,</span> <span class="n">INPUT_PULLUP</span><span class="p">);</span> <span class="c1">// on s'évite une résistance</span> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">6</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="kt">void</span> <span class="nf">loop</span><span class="p">()</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">bouton_status</span><span class="p">)</span> <span class="p">{</span> <span class="n">bouton_status</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">TAP_PIN</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="n">bouton_status</span> <span class="o">=</span> <span class="n">digitalRead</span><span class="p">(</span><span class="n">TAP_PIN</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">bouton_status</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// ok, un appui est detecté</span> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">5</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">+</span> <span class="mi">1</span><span class="p">];</span> <span class="n">t</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">=</span> <span class="n">millis</span><span class="p">();</span> <span class="k">if</span> <span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">-</span> <span class="n">t</span><span class="p">[</span><span class="mi">4</span><span class="p">]</span> <span class="o">&lt;</span> <span class="mi">3000</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// calcul de la moyenne des 5 derniers taps</span> <span class="n">tempo</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">n</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">6</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="n">tempo</span> <span class="o">+=</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">-</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span> <span class="o">-</span> <span class="mi">1</span><span class="p">];</span> <span class="n">n</span><span class="o">++</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="n">tempo</span> <span class="o">=</span> <span class="mi">60000</span> <span class="o">/</span> <span class="p">(</span><span class="n">tempo</span> <span class="o">/</span> <span class="n">n</span><span class="p">);</span> <span class="c1">// affichage du resultat</span> <span class="n">lcd</span><span class="p">.</span><span class="n">setCursor</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="n">lcd</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="n">tempo</span><span class="p">);</span> <span class="n">lcd</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">" "</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="c1">// premier tap, on attend le suivant</span> <span class="p">}</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="k">if</span> <span class="p">(</span><span class="n">millis</span><span class="p">()</span> <span class="o">-</span> <span class="n">t</span><span class="p">[</span><span class="mi">5</span><span class="p">]</span> <span class="o">&gt;</span> <span class="mi">3000</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// rien depuis 3s (tempo &lt; 20), on reinitialise</span> <span class="n">lcd</span><span class="p">.</span><span class="n">setCursor</span><span class="p">(</span><span class="mi">8</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="n">lcd</span><span class="p">.</span><span class="n">print</span><span class="p">(</span><span class="s">"...."</span><span class="p">);</span> <span class="k">for</span> <span class="p">(</span><span class="n">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="mi">6</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span> <span class="n">t</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="n">delay</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span> <span class="c1">// pour ne pas se taper le rebond du bouton</span> <span class="p">}</span></code></pre> <h2 id="toc-les-fonctions-setup-et-loop">Les fonctions setup et loop</h2> <p>Arduino IDE impose la présence de deux fonctions : <em>setup</em> et <em>loop</em>.</p> <p>La fonction <em>setup</em> ne s’exécute qu’une seule fois, lorsque l’Arduino Uno est mis sous tension ou après un <em>reset</em> (le tranfert d’un nouveau code dans le micro-contrôleur est toujours automatiquement suivi d’un <em>reset</em>).</p> <p>Elle est assez facile à comprendre, elle initialise l’écran (facultatif), les entrées/sorties utilisées (ici uniquement le pin 2 pour le bouton poussoir), et le tableau des taps. On peut juste s’appesantir un peu sur le INPUT_PULLUP qui indique au micro-contrôleur qu’il doit activer la résistance interne de pullup de cette entrée. Si cette entrée est déclarée en INPUT seulement, il faut alors ajouter une résistance (10kOhm par exemple) entre l’entrée 2 et le 5V, afin de ramener l’entrée proche de 5 volts (HIGH, true) lorsque le bouton n’est pas pressé. Sinon l’entrée ne serait connectée à rien, donc avec un potentiel électrique indéterminé. Lorque le bouton est pressé, l’entrée est en connexion directe avec la masse, donc quasiment à 0V (LOW, false).</p> <p>La fonction <em>loop</em>, comme son nom l’indique, s’exécute en boucle.</p> <p>On commence par regarder si le bouton était pressé à la fin de la boucle précédente (bouton_status à false), si oui, on lit l’état du bouton jusqu’à relâchement. Sinon, le bouton était relâché, on peut donc regarder si maintenant il est pressé ou pas.</p> <p>Suit le classique calcul du tempo basé sur les 5 dernières mesures et l’affichage. L’affichage et le tableau se réinitialisent si pas de tap pendant plus de 3 secondes.</p> <p>La fonction <em>loop</em> se termine par un mystérieux délai de 10 ms, dont l’unique but est de ne pas capter le rebond du bouton. En effet, un bouton poussoir ne passe pas toujours franchement d’un état ouvert à l’état fermé, il rebondit, pouvant donner des séries d’ouvertures-fermetures perturbantes pendant quelques millisecondes. Sur ce bouton, la transition est normale (avec légère surtension pendant 2ms) au moins 9 fois sur 10, mais des rebonds sont présents sur environ un dixième des taps. Ces rebonds ne dépassent toutefois jamais les 3ms.</p> <p><img src="//img.linuxfr.org/img/68747470733a2f2f78756c6f70732e6e65742f696d6167652f61757472652f7265626f6e64732e6a7067/rebonds.jpg" alt="Rebonds du bouton" title="Source : https://xulops.net/image/autre/rebonds.jpg"></p> <p>Avec un délai de 10 ms, il n’y a donc pas de risques que les rebonds viennent perturber le programme.<br> Patienter un centième de seconde ne gêne pas à l’usage, j’ai mesuré avec précision (à l’unité près, je ne pense pas que descendre sous la virgule soit d’un grand intérêt musical) entre 20 BPM et 240 BPM, l’erreur la plus grande vient de mon doigt qui appuie sur le bouton (et du cerveau qui commande le doigt), bref je n’arrive pas à suivre, faudrait faire un robot (à base d’Arduino Uno ?) qui appuie sur le bouton à ma place.</p> <p><img src="//img.linuxfr.org/img/68747470733a2f2f78756c6f70732e6e65742f696d6167652f61757472652f74617074656d706f5f6d6f6e746167652e6a7067/taptempo_montage.jpg" alt="Montage en fonctionnement" title="Source : https://xulops.net/image/autre/taptempo_montage.jpg"></p> <h2 id="toc-usage-mémoire">Usage mémoire</h2> <p>En incluant les bibliothèques I2C (wire.h) et LiquidCrystal pour l’écran LCD, la compilation donne : </p> <ul> <li>4092 octets de FLASH utilisés sur les 32ko disponibles ;</li> <li>323 octets de SRAM utilisés sur les 2ko disponibles.</li> </ul> <p>En n’utilisant pas l’écran LCD et en envoyant le tempo mesuré sur le port série :</p> <ul> <li>2454 octets de FLASH utilisés ;</li> <li>218 octets de SRAM utilisés.</li> </ul> <p>Pour comparaison, pour un programme vide (juste les deux fonctions sans autre ligne de code), la compilation donne respectivement 444 octets de FLASH et 9 octets de SRAM utilisés. Ça peut sembler bizarre, mais le compilateur ajoute toujours un appel pour surveiller les événements sur le port série.<br> Pas de drame, tout cela reste léger.</p> <h2 id="toc-avec-dautres-micro-contrôleurs">Avec d’autres micro-contrôleurs</h2> <p>Les ESP8266 et ESP32, qui sont des micro-contrôleurs wifi de la société Expressif, ont aussi la cote en ce moment, principalement pour les remontées de mesures à distance, alertes par courriel… Pour ces micro-contrôleurs bien mieux équipés (160 MHz, 4 Mo RAM) qu’un Arduino Uno, le programme serait le même, Arduino IDE se chargeant de compiler et transférer le programme au micro-contrôleur. Il faudra penser cependant à ajouter une résistance de pullup suivant les modèles, tous les micro-contrôleurs ne sont pas pourvus de ces résistances internes. L’ESP32 est pourvu d’entrées tactiles (capacitive touch sensor), il serait intéressant de remplacer le bouton poussoir par une simple plaque métallique et regarder s’il est possible de s’affranchir des problèmes de rebonds.</p> </div><div><a href="https://linuxfr.org/news/taptempo-pour-arduino-uno.epub">Télécharger ce contenu au format EPUB</a></div> <p> <strong>Commentaires :</strong> <a href="//linuxfr.org/nodes/122644/comments.atom">voir le flux Atom</a> <a href="https://linuxfr.org/news/taptempo-pour-arduino-uno#comments">ouvrir dans le navigateur</a> </p>