<?xml 
version="1.0" encoding="utf-8"?><?xml-stylesheet title="XSL formatting" type="text/xsl" href="https://modelleisenbahn.triskell.org/spip.php?page=backend.xslt" ?>
<rss version="2.0" 
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:atom="http://www.w3.org/2005/Atom"
>

<channel xml:lang="fr">
	<title>ModelleisenbahN</title>
	<link>https://modelleisenbahn.triskell.org/</link>
	<description>Modelleisenbahn traite de la construction de mon r&#233;seau &#171; Messingrohrstadt &#187;, r&#233;seau allemand de l'&#233;poque II. Des documents sur le th&#232;me de la SNCF et &#233;labor&#233;s par R&#233;my Fauvet sont &#233;galement h&#233;berg&#233;s.</description>
	<language>fr</language>
	<generator>SPIP - www.spip.net</generator>
	<atom:link href="https://modelleisenbahn.triskell.org/spip.php?id_rubrique=21&amp;page=backend" rel="self" type="application/rss+xml" />

	<image>
		<title>ModelleisenbahN</title>
		<url>https://modelleisenbahn.triskell.org/local/cache-vignettes/L144xH144/siteon0-d64b7.png?1692197123</url>
		<link>https://modelleisenbahn.triskell.org/</link>
		<height>144</height>
		<width>144</width>
	</image>



<item xml:lang="fr">
		<title>T&#233;moins de positions : la mise en &#339;uvre</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article66</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article66</guid>
		<dc:date>2013-12-03T19:28:33Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>LED</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Nous avons vu la technique du Charlieplexing dans &#171; T&#233;moins de positions : le Charlieplexing &#187;, nous allons maintenant l'appliquer &#224; un syst&#232;me &#224; 5 broches de pilotage et 16 LED puis l'int&#233;grer dans notre application. Charlieplexing des 16 LED t&#233;moins [1] &lt;br class='autobr' /&gt;
Le sch&#233;ma pour allumer 16 LED est le suivant. &lt;br class='autobr' /&gt;
On peut noter que le sch&#233;ma est incomplet. En effet, avec 5 broches, il est possible de piloter 20 LED. Ici les couples de broches 0-3 et 1-4 sont manquants et nous n'allons donc pas les (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot9" rel="tag"&gt;LED&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Nous avons vu la technique du Charlieplexing dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article64' class=&#034;spip_in&#034;&gt;T&#233;moins de positions : le Charlieplexing&lt;/a&gt; &#187;, nous allons maintenant l'appliquer &#224; un syst&#232;me &#224; 5 broches de pilotage et 16 LED puis l'int&#233;grer dans notre application.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Charlieplexing des 16 LED t&#233;moins&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb2-1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;On peut noter que plus le nombre de LED est important, plus le temps (&#8230;)&#034; id=&#034;nh2-1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;Le sch&#233;ma pour allumer 16 LED est le suivant.&lt;/p&gt;
&lt;div class='spip_document_329 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;41&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH328/charlie5-6e473.png?1692224382' width='500' height='328' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-329 '&gt;&lt;strong&gt;Charlieplexing avec 5 broches et 16 LED
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;On peut noter que le sch&#233;ma est incomplet. En effet, avec 5 broches, il est possible de piloter 20 LED. Ici les couples de broches 0-3 et 1-4 sont manquants et nous n'allons donc pas les placer dans notre table d'&#233;tat des broches.&lt;/p&gt;
&lt;p&gt;Voici donc la table d'&#233;tat des broches pour chaque LED&lt;/p&gt;
&lt;table class=&#034;table spip&#034;&gt;
&lt;tbody&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt; &lt;/td&gt;
&lt;td&gt;&lt;strong&gt;broche 0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;broche 1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;broche 2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;broche 3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;broche 4&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D6&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D7&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D8&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D9&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D10&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D11&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D12&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D13&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D14&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D15&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Nous allons donc construire cette table en C comme nous l'avons fait pour la Charlieplexing avec 3 broches de commande.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const byte etatSortiePourLED[16][5] = { { OUT0, OUT1, INZ, INZ, INZ }, /* D0 */ { OUT1, OUT0, INZ, INZ, INZ }, /* D1 */ { INZ, OUT0, OUT1, INZ, INZ }, /* D2 */ { INZ, OUT1, OUT0, INZ, INZ }, /* D3 */ { INZ, INZ, OUT0, OUT1, INZ }, /* D4 */ { INZ, INZ, OUT1, OUT0, INZ }, /* D5 */ { INZ, INZ, INZ, OUT0, OUT1 }, /* D6 */ { INZ, INZ, INZ, OUT1, OUT0 }, /* D7 */ { OUT0, INZ, OUT1, INZ, INZ }, /* D8 */ { OUT1, INZ, OUT0, INZ, INZ }, /* D9 */ { INZ, INZ, OUT0, INZ, OUT1 }, /* D10 */ { INZ, INZ, OUT1, INZ, OUT0 }, /* D11 */ { INZ, OUT0, INZ, OUT1, INZ }, /* D12 */ { INZ, OUT1, INZ, OUT0, INZ }, /* D13 */ { OUT0, INZ, INZ, INZ, OUT1 }, /* D14 */ { OUT1, INZ, INZ, INZ, OUT0 } /* D15 */ };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;La fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;programmeBroche(...)&lt;/code&gt; reste la m&#234;me par contre la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereLED(...)&lt;/code&gt; doit &#234;tre modifi&#233;e puisque l'on passe de 3 &#224; 5 broches de commande.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void gereLED(int num) { if (etatLED[num] == ALLUME) { programmeBroche(8,etatSortiePourLED[num][0]); programmeBroche(9,etatSortiePourLED[num][1]); programmeBroche(10,etatSortiePourLED[num][2]); programmeBroche(11,etatSortiePourLED[num][3]); programmeBroche(12,etatSortiePourLED[num][4]); } else { programmeBroche(8,INZ); programmeBroche(9,INZ); programmeBroche(10,INZ); programmeBroche(11,INZ); programmeBroche(12,INZ); } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Et le tableau &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatLED&lt;/code&gt; doit &#234;tre agrandi pour contenir 16 &#233;l&#233;ments.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Int&#233;gration dans l'application&lt;/h2&gt;
&lt;p&gt;Pour int&#233;grer l'allumage des t&#233;moins dans l'application il faut tout d'abord ins&#233;rer l'appel &#224; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereLED()&lt;/code&gt; dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;. Nous faisons face &#224; un premier probl&#232;me. Pour que les servomoteurs pivotent suffisamment lentement, l'attente est de 5ms. Cela conduit &#224; un balayage des 16 LED en 80ms ce qui est trop lent pour que la persistance r&#233;tinienne op&#232;re. Il faudrait balayer au moins 4 fois plus souvent. Par cons&#233;quent, le d&#233;lai dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt; va &#234;tre r&#233;duit &#224; 1ms et la gestion des poussoirs et des servomoteurs sera appel&#233;e toutes les 5 fois alors que la gestion des LED sera appel&#233;e toutes les fois. Nous allons donc ajouter un compteur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;compteurGestionServos&lt;/code&gt; initialis&#233; &#224; 0. Comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void loop() { compteurGestionServos++; if (compteurGestionServos == 5) { compteurGestionServos = 0; ... /* code de gestion des servos et des poussoir &#224; l'identique */ ... } gereLED(numLED); numLED++; if (numLED == 16) numLED = 0; delay(1); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il suffit ensuite de changer l'&#233;tat des LED en ALLUME ou ETEINT dans le tableau &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatLED&lt;/code&gt; en fonction des &#233;v&#233;nements. Deux fonctions membre de la classe &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; sont concern&#233;es : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo(...)&lt;/code&gt; o&#249; on va &#233;teindre la LED de la position que l'on quitte et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; o&#249; on va allumer la LED de la position que l'on atteint. Dans le tableau &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatLED&lt;/code&gt;, les LED sont alternativement rouges et vertes et par cons&#233;quent la paire de LED correspondant &#224; un servomoteur est &#224; la position &lt;i&gt;num&#233;ro de servo&lt;/i&gt; &#215; 2 (angle minimum) et &lt;i&gt;num&#233;ro de servo&lt;/i&gt; &#215; 2 + 1 (angle maximum).&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void evenementServo() { cptArret = -1; switch (etatServo) { case SERVO_A_ANGLE_MIN: etatLED[numServo * 2] = ETEINT; objetServo.attach(pin); case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: vitesse = 1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: etatLED[numServo * 2 + 1] = ETEINT; objetServo.attach(pin); case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: vitesse = -1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dans la fonction membre &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt;, la partie qui s'occupe du passage de la vitesse &#224; 0 quand les angles minimum ou maximum sont atteint est modifi&#233;e comme suit :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;if (! reglageEnCours || etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN || etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX) { if (angle &gt; angleMax) { angle = angleMax; arreteServo(); etatServo = SERVO_A_ANGLE_MAX; etatLED[numServo * 2 + 1] = ALLUME; } else if (angle &lt; angleMin) { angle = angleMin; arreteServo(); etatServo = SERVO_A_ANGLE_MIN; etatLED[numServo * 2] = ALLUME; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il ne faut pas oublier d'allumer la LED correspondant &#224; l'angle minimum dans la fonction membre &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;connecte(...)&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;/* allume la LED correspondante */ etatLED[numServo * 2] = ALLUME;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nous sommes parvenus au bout de ce d&#233;veloppement. Voici le sketch de l'application compl&#232;te &#224; t&#233;l&#233;charger.&lt;/p&gt;
&lt;div class='spip_document_337 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;123&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/zip/Huit_boutons_huit_servos_detach_reglage_eeprom_temoins_cpp-2.zip' class=&#034; spip_doc_lien&#034; title='Zip - 4.4 kio' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1779519117' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-337 '&gt;&lt;strong&gt;Sketch de l'application compl&#232;te
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-337 '&gt;mis &#224; jour en version 1.1. La position des servos est d&#233;sormais m&#233;moris&#233;e dans l'EEPROM.
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;&lt;div class='spip_document_341 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;214&#034; data-legende-lenx=&#034;xxx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;a href='https://modelleisenbahn.triskell.org/IMG/png/schema_fritzing_8s8p-2.png' class=&#034;spip_doc_lien mediabox&#034; type=&#034;image/png&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH454/schema_fritzing_8s8p-2-903fb.png?1692224382' width='500' height='454' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-341 '&gt;&lt;strong&gt;Dessin du montage complet
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-341 '&gt;&lt;strong&gt;Attention : le montage montre les 8 servomoteurs aliment&#233;s par l'Arduino. Ce n'est pas possible en pratique et il est n&#233;cessaire d'avoir une alimentation 5V s&#233;par&#233;e pour les servomoteurs&lt;/strong&gt;
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;&lt;div class='spip_document_342 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;235&#034; data-legende-lenx=&#034;xxx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/pdf/schema_fritzing_8s8p.pdf' class=&#034; spip_doc_lien&#034; title='PDF - 2.4 Mio' type=&#034;application/pdf&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/pdf-b8aed.svg?1779461898' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-342 '&gt;&lt;strong&gt;Dessin du montage complet &#224; t&#233;l&#233;charger en PDF
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-342 '&gt;&lt;strong&gt;Attention : le montage montre les 8 servomoteurs aliment&#233;s par l'Arduino. Ce n'est pas possible en pratique et il est n&#233;cessaire d'avoir une alimentation 5V s&#233;par&#233;e pour les servomoteurs&lt;/strong&gt;
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Ainsi qu'une vid&#233;o de d&#233;monstration.&lt;/p&gt;
&lt;div class=&#034;spip_document_336 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;53&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-336&#034; data-id=&#034;232d689cc7c6fedb727a86ce65db3e91&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/bMmDTduT-N8?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1779463451' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-336 '&gt;&lt;strong&gt;D&#233;monstration de l'application compl&#232;te et termin&#233;e
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript7308746026a3356b6bdd222.46801206&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzc5NDQzNTM4JyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3Nzk0NDM1MzgnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb2-1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh2-1&#034; class=&#034;spip_note&#034; title=&#034;Notes 2-1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;On peut noter que plus le nombre de LED est important, plus le temps d'allumage sur un cycle de balayage devient faible. En pratique, la luminosit&#233; n'est pas beaucoup plus faible avec 16 LED. Pour un plus grand nombre de LED, il peut &#234;tre n&#233;cessaire de diminuer la valeur des r&#233;sistances sans toutefois d&#233;passer les capacit&#233;s des entr&#233;es/sorties du micro-contr&#244;leur&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>T&#233;moins de positions : le Charlieplexing</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article64</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article64</guid>
		<dc:date>2013-12-02T21:08:29Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>LED</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;La derni&#232;re fonction &#224; mettre en &#339;uvre est la gestion des t&#233;moins de position. 16 LED sont n&#233;cessaires et il nous reste 6 broches. La broche num&#233;rique 13 ayant d&#233;j&#224; une LED soud&#233;e sur la carte de l'Arduino n'est pas tr&#232;s commode &#224; utiliser. Il nous reste donc en r&#233;alit&#233; 5 broches. Comment faire ? &lt;br class='autobr' /&gt;
Il existe une technique connue sous le nom de Charliplexing [1] qui permet de multiplexer des LED sur des entr&#233;es/sorties num&#233;riques. Examinons tout d'abord le cas de deux LED connect&#233;es &#224; 2 (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot9" rel="tag"&gt;LED&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;La derni&#232;re fonction &#224; mettre en &#339;uvre est la gestion des t&#233;moins de position. 16 LED sont n&#233;cessaires et il nous reste 6 broches. La broche num&#233;rique 13 ayant d&#233;j&#224; une LED soud&#233;e sur la carte de l'Arduino n'est pas tr&#232;s commode &#224; utiliser. Il nous reste donc en r&#233;alit&#233; 5 broches.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Comment faire ?&lt;/h2&gt;
&lt;p&gt;Il existe une technique connue sous le nom de Charliplexing&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb2-1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Le Charlieplexing est une technique propos&#233;e en 1995 par Charlie Allen, voir (&#8230;)&#034; id=&#034;nh2-1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt; qui permet de multiplexer des LED sur des entr&#233;es/sorties num&#233;riques. Examinons tout d'abord le cas de deux LED connect&#233;es &#224; 2 broches avec 2 r&#233;sistances de 150&#937;.&lt;/p&gt;
&lt;div class='spip_document_322 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;71&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L332xH132/charlie2-67a48.png?1692224382' width='332' height='132' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-322 '&gt;&lt;strong&gt;Charlieplexing avec 2 broches
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-322 '&gt;dont l'int&#233;r&#234;t est plus que discutable.
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Si la broche 0 est en sortie &#224; 5V et la broche 1 en sortie &#224; 0V, la LED rouge est allum&#233;e. Si la broche 0 est en sortie &#224; 0V et la broche 1 en sortie &#224; 5V, la LED verte est allum&#233;e. Toute autre configuration, une des broches ou les deux en entr&#233;e ou les deux en sortie au m&#234;me potentiel, &#233;teint les deux LED.&lt;/p&gt;
&lt;p&gt;&#199;a ne nous avance pas beaucoup me direz vous.&lt;/p&gt;
&lt;p&gt;Rajoutons donc une broche 2 et une r&#233;sistance et ajoutons une paire de LED entre la broche 2 et la broche 1 mais aussi entre la broche 2 et la broche 0, soit 6 LED au total.&lt;/p&gt;
&lt;div class='spip_document_325 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;31&#034; data-legende-lenx=&#034;&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L499xH231/charlie3-a2418.png?1692224382' width='499' height='231' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-325 '&gt;&lt;strong&gt;Charlieplexing avec 3 broches
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Pour allumer la LED D5 par exemple, il faut mettre la broche 0 en sortie &#224; 5V, la broche 2 en sortie &#224; 0V et pour que ni D1, ni D3 ne s'allument, mettre la broche 1 en entr&#233;e (donc en haute imp&#233;dance). On peut remarquer que D1 et D3 sont &#233;galement aliment&#233;es mais comme elle sont en s&#233;rie, elles pr&#233;sentent une tension de seuil 2 fois sup&#233;rieure&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb2-2&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;La tension de seuil d&#233;pend de la couleur de la LED mais m&#234;me en mettant en (&#8230;)&#034; id=&#034;nh2-2&#034;&gt;2&lt;/a&gt;]&lt;/span&gt; et le courant empruntera le chemin de plus faible tension de seuil.&lt;/p&gt;
&lt;p&gt;Pour la suite on va noter le fait de mettre une sortie &#224; 5V : 1, &#224; 0V, 0 et en entr&#233;e : Z.&lt;/p&gt;
&lt;p&gt;La table correspondant &#224; l'allumage de chaque LED est la suivante.&lt;/p&gt;
&lt;table class=&#034;table spip&#034;&gt;
&lt;tbody&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt; &lt;/td&gt;
&lt;td&gt;&lt;strong&gt;broche 0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;broche 1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;broche 2&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;&lt;strong&gt;D4&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;&lt;strong&gt;D5&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Z&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;De mani&#232;re g&#233;n&#233;rale, avec N broches, on peut piloter N &#215; N-1 LED. Avec nos 5 broches disponible, on pourra donc piloter 5 &#215; 4 = 20 LED.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Programme de d&#233;monstration&lt;/h2&gt;
&lt;p&gt;&#201;videmment, seule une LED peut &#234;tre allum&#233;e &#224; un instant. C'est donc l'Arduino qui va s'occuper de balayer les LED et, pour chacune les allumer ou non &#224; une vitesse suffisamment grande pour que l'&#339;il ait l'impression que l'allumage de chaque LED est permanent gr&#226;ce &#224; la persistance r&#233;tinienne. Avant de nous lancer dans l'allumage de 16 LED, voyons comment fonctionne le programme pour 3 broches et 6 LED. Dans un premier temps, nous allons balayer et allumer les 6 LED pour juger de l'effet rendu.&lt;/p&gt;
&lt;p&gt;Il faut tout d'abord transposer le table d'&#233;tats en C dont les lignes correspondront aux LED et les colonnes aux sortie. Les &#233;tats eux m&#234;me sont d&#233;finis par un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;enum&lt;/code&gt;, une mani&#232;re de donner un nom symbolique &#224; une constante num&#233;rique :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;enum { OUT0, OUT1, INZ }; const byte etatSortiePourLED[6][3] = { { OUT0, OUT1, INZ }, /* D0 */ { OUT1, OUT0, INZ }, /* D1 */ { INZ, OUT0, OUT1 }, /* D2 */ { INZ, OUT1, OUT0 }, /* D3 */ { OUT0, INZ, OUT1 }, /* D4 */ { OUT1, INZ, OUT0 } /* D5 */ };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;OUT0&lt;/code&gt; signifie que le broche est en sortie et &#224; 0, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;OUT1&lt;/code&gt; qu'elle est en sortie et &#224; 1 et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;INZ&lt;/code&gt; en entr&#233;e et &#224; haute imp&#233;dance, c'est &#224; dire sans r&#233;sistance de &lt;i&gt;pull-up&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Ajoutons une fonction pour programmer une broche en fonction de ce code :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void programmeBroche(int numBroche, byte etat) { switch (etat) { case OUT0: digitalWrite(numBroche,LOW); pinMode(numBroche,OUTPUT); break; case OUT1: digitalWrite(numBroche,HIGH); pinMode(numBroche,OUTPUT); break; case INZ: pinMode(numBroche,INPUT); digitalWrite(numBroche,LOW); /* pas de pullup */ break; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour que l'on puisse tour &#224; tour allumer une LED ou non, il nous faut un tableau qui, pour chaque LED, va indiquer son &#233;tat, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;ALLUME&lt;/code&gt; ou &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;ETEINT&lt;/code&gt;. De nouveau nous allons utiliser un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;enum&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;enum { ALLUME, ETEINT }; byte etatLED[6] = { ETEINT, ETEINT, ETEINT, ETEINT, ETEINT, ETEINT };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin, il nous faut une fonction qui, pour un num&#233;ro de LED, va chercher son &#233;tat et, si elle elle allum&#233;e, appelle, pour chaque broche, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;programmeBroche&lt;/code&gt; avec les &#233;tats de broche correspondant &#224; l'allumage de cet LED. Si elle est &#233;teinte, toutes les sorties sont mises dans l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;INZ&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void gereLED(int num) { if (etatLED[num] == ALLUME) { programmeBroche(10,etatSortiePourLED[num][0]); programmeBroche(11,etatSortiePourLED[num][1]); programmeBroche(12,etatSortiePourLED[num][2]); } else { programmeBroche(10,INZ); programmeBroche(11,INZ); programmeBroche(12,INZ); } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il suffit ensuite dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt; de balayer les LED, de 0 &#224; 5, en donnant leur &#233;tat avec une p&#233;riode de 2ms.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;int numLED = 0; void loop() { gereLED(numLed); numLED++; if (numLED &gt; 5) numLED = 0; delay(2); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Par dessus on superpose une s&#233;quence d'allumage comme, par exemple, un chenillard.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;int numLED = 0; int LEDAllumee = 0; int compteur1s = 0; void setup() { /* Au d&#233;but la LED 0 est allum&#233;e */ etatLED[LEDAllumee] = ALLUME; } void loop() { compteur1s++; if (compteur1s == 500) { /* Au bout de 1s, on allume la LED suivante */ compteur1s = 0; /* &#201;teint la LED qui &#233;tait allum&#233;e */ etatLED[LEDAllumee] = ETEINT; /* Passe &#224; la LED suivante */ LEDAllumee++; if (LEDAllumee &gt; 5) LEDAllumee = 0; /* Allume la nouvelle LED */ etatLED[LEDAllumee] = ALLUME; } gereLED(numLed); numLED++; if (numLED &gt; 5) numLED = 0; delay(2); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Voici le programme de chenillard en Charlieplexing sur 3 broches et 6 LED.&lt;/p&gt;
&lt;div class='spip_document_333 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;40&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/zip/charlie3_chenillard-2.zip' class=&#034; spip_doc_lien&#034; title='Zip - 969 octets' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1779519117' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-333 '&gt;&lt;strong&gt;Sketch du chenillard en Charlieplexing
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Ainsi que la vid&#233;o de d&#233;monstration&lt;/p&gt;
&lt;div class=&#034;spip_document_335 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;39&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-335&#034; data-id=&#034;3bee6585cba5ea8cf176b96838344622&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/yzJ-wb4sJlQ?version=3&amp;hl=fr_FR&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1779463451' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-335 '&gt;&lt;strong&gt;D&#233;monstration du sketch de chenillard
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript5838709256a3151cea5e217.64697248&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzc5NDQzNTM4JyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3Nzk0NDM1MzgnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb2-1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh2-1&#034; class=&#034;spip_note&#034; title=&#034;Notes 2-1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Le Charlieplexing est une technique propos&#233;e en 1995 par Charlie Allen, voir &lt;a href=&#034;http://en.wikipedia.org/wiki/Charlieplexing&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;l'article sur Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;&lt;div id=&#034;nb2-2&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh2-2&#034; class=&#034;spip_note&#034; title=&#034;Notes 2-2&#034; rev=&#034;appendix&#034;&gt;2&lt;/a&gt;] &lt;/span&gt;La tension de seuil d&#233;pend de la couleur de la LED mais m&#234;me en mettant en s&#233;rie 2 LED rouge dont la tension de seuil est la plus faible, 1,6V, 2 &#215; 1,6V = 3,2 V reste sup&#233;rieure &#224; la tension de seuil des LED violettes, 3,1V&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Am&#233;lioration et m&#233;morisation des r&#233;glages</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article67</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article67</guid>
		<dc:date>2013-12-02T07:45:39Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Comme indiqu&#233; dans la vid&#233;o au bas de l'article &#171; R&#233;glage des but&#233;es des servomoteurs &#187;, un probl&#232;me li&#233; &#224; l'inertie m&#233;canique subsiste. Nous avons aussi le probl&#232;me de la non m&#233;morisation des r&#233;glages. Nous allons voir comment r&#233;gler ces deux probl&#232;mes. &lt;br class='autobr' /&gt;
Prise en compte de l'inertie m&#233;canique &lt;br class='autobr' /&gt;
Quand la consigne de position, via la dur&#233;e de l'&#233;tat haut de la PWM, est envoy&#233; au servomoteur, celui-ci met quelques instants &#224; appliquer cette consigne. Or, le programme actuel coupe la PWM est (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Comme indiqu&#233; dans la vid&#233;o au bas de l'article &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article65' class=&#034;spip_in&#034;&gt;R&#233;glage des but&#233;es des servomoteurs&lt;/a&gt; &#187;, un probl&#232;me li&#233; &#224; l'inertie m&#233;canique subsiste. Nous avons aussi le probl&#232;me de la non m&#233;morisation des r&#233;glages. Nous allons voir comment r&#233;gler ces deux probl&#232;mes.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Prise en compte de l'inertie m&#233;canique&lt;/h2&gt;
&lt;p&gt;Quand la consigne de position, via la dur&#233;e de l'&#233;tat haut de la PWM, est envoy&#233; au servomoteur, celui-ci met quelques instants &#224; appliquer cette consigne. Or, le programme actuel coupe la PWM est appelant la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;detach()&lt;/code&gt; d&#232;s que la consigne atteint l'angle maximum ou l'angle minimum. Le servo n'a donc pas le temps de r&#233;pondre &#224; cette consigne et pour r&#233;gler le probl&#232;me il faut diff&#233;rer le d&#233;tachement du servo.&lt;/p&gt;
&lt;p&gt;Au lieu de d&#233;tacher imm&#233;diatement le servo, il faut initialiser un compteur, que nous appelleront &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;cptArret&lt;/code&gt;, qui quand il atteint 0 provoque le d&#233;tachement du servo. Une fois le servo d&#233;tach&#233;, le compteur est mis &#224; -1 pour &#233;viter de d&#233;tacher le servo de mani&#232;re r&#233;p&#233;titive. Actuellement dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; en plusieurs endroits, la vitesse est mise &#224; 0 et le servo est d&#233;tach&#233;.&lt;/p&gt;
&lt;p&gt;Il faut remplacer les &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;objetServo.detach()&lt;/code&gt; par l'initialisation du compteur. Pour rationaliser nous allons mettre le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;vitesse = 0;&lt;/code&gt; et l'initialisation du compteur dans une fonction membre s&#233;par&#233;e :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void arreteServo() { vitesse = 0; cptArret = 30; } &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Avec le d&#233;lai de 5ms dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;, une valeur de 30 engendre un d&#233;lai de 150ms ce qui est suffisant pour que la m&#233;canique rattrape l'&#233;lectronique.&lt;/p&gt;
&lt;p&gt;Il faut maintenant, dans la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt;, d&#233;cr&#233;menter ce compteur tant qu'il est &#8805; &#224; 0 et d&#233;tacher le servo quand ce compteur est &#233;gal &#224; 0. De plus, &#224; chaque fois que nous avons la mise de la vitesse &#224; 0 et le d&#233;tachement du servo, nous le rempla&#231;ons par l'appel &#224; la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;arreteServo()&lt;/code&gt;. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; devient :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void gereServo() { objetServo.writeMicroseconds(angle); if (vitesse == 0) { if (cptArret == 0) objetServo.detach(); if (cptArret &gt;= 0) cptArret--; } else angle += vitesse; if (! reglageEnCours || etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN || etatServo == SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX) { if (angle &gt; angleMax) { angle = angleMax; arreteServo(); etatServo = SERVO_A_ANGLE_MAX; } else if (angle &lt; angleMin) { angle = angleMin; arreteServo(); etatServo = SERVO_A_ANGLE_MIN; } } else { if (etatServo == SERVO_A_ANGLE_MIN) { if (vitesse &gt; 0 &amp;&amp; angle &gt;= angleMin) { angle = angleMin; arreteServo(); } else if (vitesse &lt; 0 &amp;&amp; angle &lt;= angleMin) { angle = angleMin; arreteServo(); } } else if (etatServo == SERVO_A_ANGLE_MAX) { if (vitesse &gt; 0 &amp;&amp; angle &gt;= angleMax) { angle = angleMax; arreteServo(); } else if (vitesse &lt; 0 &amp;&amp; angle &lt;= angleMax) { angle = angleMax; arreteServo(); } } } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il faut &#233;galement garantir que le servo ne sera pas d&#233;tach&#233; intempestivement. En effet, si l'utilisateur demande un mouvement du servo dans l'intervalle de temps entre le passage de la vitesse &#224; 0 et le passage du compteur &#224; 0, il faut passer directement le compteur &#224; -1 dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo()&lt;/code&gt; car sinon le d&#233;tachement du servo interviendra pendant le mouvement, ce qui est un dysfonctionnement.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;M&#233;morisation des but&#233;es&lt;/h2&gt;
&lt;p&gt;La plupart des microcontr&#244;leurs dispose d'une m&#233;moire permanente, c'est &#224; dire qui ne s'efface pas &#224; la mise hors tension, sous forme d'EEPROM (Electrically Erasable Programmable Read-Only Memory). La biblioth&#232;que de l'Arduino permet de lire et d'&#233;crire l'EEPROM de mani&#232;re tr&#232;s simple via deux fonctions : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EEPROM.read(...)&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EEPROM.write(..., ...)&lt;/code&gt;. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EEPROM.read(...)&lt;/code&gt; prend comme argument une adresse d'octet (byte) et retourne l'octet qui se trouve &#224; cet adresse et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EEPROM.write(..., ...)&lt;/code&gt; prend deux arguments. Le premier est l'adresse de l'octet que l'on souhaite &#233;crire et le second est la valeur que l'on souhaite y &#233;crire. L'EEPROM de l'ATMega328 qui &#233;quipe l'Arduino Uno a une taille de 1ko.&lt;/p&gt;
&lt;p&gt;Pour chaque servomoteur, il faut stocker les deux but&#233;es. Chaque but&#233;e est stock&#233;e dans un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;int&lt;/code&gt;. Sur l'Arduino Uno, un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;int&lt;/code&gt; prend 2 octets. Par cons&#233;quent il faut 4 octets pour chaque servos et donc 32 octets au total. En d&#233;marrant &#224; l'adresse 0 de l'EEPROM, l'adresse de stockage des but&#233;e d'une servo sera donc &#233;gale au &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4. Nous allons donc stocker le premier octet de angleMin &#224; &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4, le second &#224; &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4 + 1, le premier octet de angleMax &#224; &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4 + 2 et le 2e octet &#224; &lt;i&gt;num&#233;ro du servo&lt;/i&gt; &#215; 4 + 3. Nous allons donc ajouter une donn&#233;e membre &#224; la classe &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; pour y m&#233;moriser cette adresse. Cette donn&#233;e est initialis&#233;e dans le constructeur.&lt;/p&gt;
&lt;p&gt;Il est n&#233;cessaire d'&#234;tre prudent avec les EEPROM. En effet, elle supporte un nombre de cycle d'effacement/&#233;criture r&#233;duit. Par exemple, celle de l'ATMega328 qui &#233;quipe l'Arduino Uno supporte 100 000 cycles d'effacement/&#233;criture. Cela peut sembler une valeur importante mais si nous &#233;crivons imprudemment les but&#233;es des servos en EEPROM &#224; chaque passage dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;, l'EEPROM sera fichue en 5ms &#215; 100 000 = 500s = 8 minutes et 20 secondes.&lt;/p&gt;
&lt;p&gt;Il faut donc n'&#233;crire les but&#233;es que si un r&#233;glage a &#233;t&#233; effectu&#233; et si la valeur a chang&#233;. Nous allons donc ajouter un bool&#233;en membre de la classe &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt;, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;aSauver&lt;/code&gt;, qui sera mis &#224; vrai dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;regleServo()&lt;/code&gt; si l'une des but&#233;es a &#233;t&#233; chang&#233;e.&lt;/p&gt;
&lt;p&gt;Enfin, deux fonctions membres, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;ecrireEEPROMSiDifferent(...)&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;enregistre()&lt;/code&gt; sont ajout&#233;es pour m&#233;moriser les but&#233;es dans l'EEPROM. Le travail n'est effectu&#233; que si &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;aSauver&lt;/code&gt; est vrai et si les valeurs ont chang&#233;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void ecrireEEPROMSiDifferent(int adresseEcriture, byte valeur) { if (EEPROM.read(adresseEcriture) != valeur) EEPROM.write(adresseEcriture, valeur); } void enregistre() { if (aSauver) { ecrireEEPROMSiDifferent(adresse, angleMin &amp; 0xFF); ecrireEEPROMSiDifferent(adresse + 1, angleMin &gt;&gt; 8); ecrireEEPROMSiDifferent(adresse + 2, angleMax &amp; 0xFF); ecrireEEPROMSiDifferent(adresse + 3, angleMax &gt;&gt; 8); aSauver = false; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin, au d&#233;marrage du syst&#232;me dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;connecte()&lt;/code&gt;, il faut initialiser la position des servos aux valeurs enregistr&#233;es. La valeur lue est recadr&#233;e entre ANGLE_MIN et ANGLE_MAX car l'EEPROM peut contenir des valeurs &#233;crites par une autre application ou bien &#234;tre vierge&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Un octet d'EEPROM qui n'a jamais &#233;t&#233; &#233;crit est &#224; la valeur 255 en d&#233;cimal ou (&#8230;)&#034; id=&#034;nh1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;angleMin = EEPROM.read(adresse) | ((int)EEPROM.read(adresse + 1)) &lt;&lt; 8; angleMax = EEPROM.read(adresse + 2) | ((int)EEPROM.read(adresse + 3)) &lt;&lt; 8; if (angleMin &lt; ANGLE_MIN || angleMin &gt; ANGLE_MAX) angleMin = ANGLE_MIN; if (angleMax &lt; ANGLE_MIN || angleMax &gt; ANGLE_MAX) angleMax = ANGLE_MAX;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le sketch de l'application am&#233;lior&#233;e&lt;/p&gt;
&lt;div class='spip_document_334 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;66&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/zip/Huit_boutons_huit_servos_detach_reglage_eeprom_cpp-4.zip' class=&#034; spip_doc_lien&#034; title='Zip - 3.6 kio' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1779519117' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-334 '&gt;&lt;strong&gt;Sketch Arduino de l'application avec r&#233;glage des but&#233;es am&#233;lior&#233;
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Et enfin une petite vid&#233;o qui montre l'effet de ces deux am&#233;liorations.&lt;/p&gt;
&lt;div class=&#034;spip_document_331 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;66&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-331&#034; data-id=&#034;9eb5826d230e416a3f3cca7bcaa3eb95&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/VyTvpKi1KH0?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1779463451' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-331 '&gt;&lt;strong&gt;D&#233;monstration de l'am&#233;lioration et de la m&#233;morisation des but&#233;es
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript16715333266a31ae12b71d52.13111736&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzc5NDQzNTM4JyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3Nzk0NDM1MzgnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh1&#034; class=&#034;spip_note&#034; title=&#034;Notes 1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Un octet d'EEPROM qui n'a jamais &#233;t&#233; &#233;crit est &#224; la valeur 255 en d&#233;cimal ou 0xFF en hexad&#233;cimal (tous les bits de l'octet sont &#224; 1).&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>R&#233;glage des but&#233;es des servomoteurs</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article65</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article65</guid>
		<dc:date>2013-12-01T17:09:10Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Nous voici enfin &#224; l'avant derni&#232;re &#233;tape de d&#233;veloppement de notre syst&#232;me. Dans &#171; S&#233;lection d'un servomoteur pour le r&#233;glage des but&#233;es &#187;, nous avons vu la mise en &#339;uvre d'un codeur pour d&#233;signer le servomoteur &#224; r&#233;gler, dans &#171; Clavier de r&#233;glage des but&#233;es &#187;, nous avons vu l'ajout d'un second clavier analogique destin&#233; &#224; permettre le r&#233;glage des but&#233;es et, comme nous avions d&#233;j&#224; un clavier analogique, la g&#233;n&#233;ralisation de la gestion de ce type de clavier par le biais d'une classe C++. (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Nous voici enfin &#224; l'avant derni&#232;re &#233;tape de d&#233;veloppement de notre syst&#232;me. Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article61' class=&#034;spip_in&#034;&gt;S&#233;lection d'un servomoteur pour le r&#233;glage des but&#233;es&lt;/a&gt; &#187;, nous avons vu la mise en &#339;uvre d'un codeur pour d&#233;signer le servomoteur &#224; r&#233;gler, dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article62' class=&#034;spip_in&#034;&gt;Clavier de r&#233;glage des but&#233;es&lt;/a&gt; &#187;, nous avons vu l'ajout d'un second clavier analogique destin&#233; &#224; permettre le r&#233;glage des but&#233;es et, comme nous avions d&#233;j&#224; un clavier analogique, la g&#233;n&#233;ralisation de la gestion de ce type de clavier par le biais d'une classe C++.&lt;/p&gt;
&lt;p&gt;Nous allons maintenant voir comment int&#233;grer cette fonction de r&#233;glage au programme de pilotage des 8 servos. Mais tout d'abord quelques &#233;claircissement sur la fonction d&#233;sir&#233;e.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Le fonctionnement du r&#233;glage&lt;/h2&gt;
&lt;p&gt;Lorsqu'un des servo est d&#233;sign&#233; au moyen du codeur, le mouvement des servos restent actif. En effet, le r&#233;glage ne porte que sur la but&#233;e actuelle du servo d&#233;sign&#233;.&lt;/p&gt;
&lt;p&gt;Si le servo est en but&#233;e dans le sens horaire, une pression sur le poussoir de droite doit d&#233;placer la but&#233;e horaire un peu plus dans le sens horaire. Une pression sur le poussoir de gauche d&#233;place la but&#233;e un peu moins. De m&#234;me, si le servo est en but&#233;e dans le sens trigonom&#233;trique, une pression sur le poussoir de gauche d&#233;place un peu plus la but&#233;e dans le sens trigonom&#233;trique et une pression sur le poussoir de droite un peu moins.&lt;/p&gt;
&lt;p&gt;Pour passer du r&#233;glage d'une but&#233;e au r&#233;glage de l'autre but&#233;e, il suffit de presser le poussoir commandant le mouvement du servomoteur.&lt;/p&gt;
&lt;p&gt;Une tentative de r&#233;glage alors que le servo est en mouvement est ignor&#233;e.&lt;/p&gt;
&lt;p&gt;Le r&#233;glage en lui m&#234;me va donc augmenter ou diminuer les angles minimum et maximum. Si on veut un r&#233;glage pr&#233;cis, il faut r&#233;gler de pas en pas&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Un pas vaut 1&#181;s puisqu'on utilise la fonction pour piloter les servos&#034; id=&#034;nh1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt;. Mais r&#233;gler de pas en pas risque d'&#234;tre long. On veut donc pouvoir d&#233;cider de combien de pas la but&#233;e est augment&#233;e ou diminu&#233;e lors d'une pression sur un des poussoirs de r&#233;glage. Voici donc le r&#244;le des 2 boutons suppl&#233;mentaires du clavier de r&#233;glage, ils servent &#224; augmenter et diminuer le nombre de pas de r&#233;glage.&lt;/p&gt;
&lt;p&gt;Par d&#233;faut, lorsqu'on d&#233;signe un servo &#224; r&#233;gler, le nombre de pas sera de 8. Une pression sur le poussoir d'augmentation du pas le multipliera par 2 avec un maximum de 32. Une pression sur le poussoir de diminution du pas le divisera par 2 avec un minimum de 1. Le fait de d&#233;signer un nouveau servo r&#233;initialisera le pas de r&#233;glage &#224; 8.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Modification de la classe &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;La premi&#232;re modification est &#233;vidente. Auparavant, les but&#233;es &#233;taient d&#233;termin&#233;es globalement pour les 8 servomoteurs. Maintenant que l'on veut r&#233;gler les but&#233;es de chaque servomoteur individuellement, il faut que le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; comporte deux donn&#233;es membres &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMin&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMax&lt;/code&gt; comme ceci :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;class DescripteurServo { Servo objetServo; /* Objet issu de la biblioth&#232;que Servo de l'Arduino */ int vitesse; /* La vitesse de d&#233;placement du servomoteur */ int angle; /* L'angle du servo-moteur */ int angleMin; /* Angle minimum du servo */ int angleMax; /* Angle maximum du servo */ int pin; /* La broche sur laquelle il est connect&#233; */ byte etatServo; /* son &#233;tat : SERVO_A_ANGLE_MIN, SERVO_A_ANGLE_MAX SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX ou SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN */ ...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On va bien entendu conserver des constantes minimum et maximum absolues afin de limiter le r&#233;glage :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const int ANGLE_MIN = 1000; const int ANGLE_MAX = 2000;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ces constantes vont &#234;tre employ&#233;es dans le constructeur de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; pour initialiser les donn&#233;es membres &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMin&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMax&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La fonction de r&#233;glage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ensuite, il faut &#233;crire une fonction membre de r&#233;glage. Cette fonction est appel&#233;e de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt; lorsque le codeur d&#233;signe le servo concern&#233;. Cette fonction doit&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; lire un &#233;v&#233;nement sur le clavier de r&#233;glage ;&lt;/li&gt;&lt;li&gt; si l'&#233;v&#233;nement est un changement de pas de r&#233;glage, la variable de pas est multipli&#233;e par 2 ou divis&#233;e par 2 ;&lt;/li&gt;&lt;li&gt; si l'&#233;v&#233;nement est un r&#233;glage :
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; si l'&#233;tat du servo est SERVO_A_ANGLE_MIN, l'angle minimum est ajust&#233;, la vitesse du servo est mise &#224; 1 ou -1 selon le changement pour que le servo vienne de recaler sur l'angle minimum ;&lt;/li&gt;&lt;li&gt; si l'&#233;tat du servo est SERVO_A_ANGLE_MAX, l'angle maximum est ajust&#233;, la vitesse du servo est mise &#224; 1 ou -1 selon le changement pour que le servo vienne de recaler sur l'angle maximum.&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Afin de s&#233;parer clairement les diff&#233;rents cas, nous allons utiliser des &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch ... case&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void regleServo() { int numPoussoir; if (clavierReglage.lireEvenement(&amp;numPoussoir) == EVENEMENT_PRESSE) { switch(numPoussoir) { case 0: /* d&#233;placement de la but&#233;e dans le sens trigo */ switch(etatServo) { case SERVO_A_ANGLE_MIN: if (angleMin &lt; angleMax) angleMin += min(pasDeReglage, angleMax - angleMin); objetServo.attach(pin); vitesse = 1; break; case SERVO_A_ANGLE_MAX: if (angleMax &lt; ANGLE_MAX) angleMax += min(pasDeReglage, ANGLE_MAX - angleMax); objetServo.attach(pin); vitesse = 1; break; } break; case 1: /* d&#233;placement de la but&#233;e dans le sens horaire */ switch(etatServo) { case SERVO_A_ANGLE_MIN: if (angleMin &gt; ANGLE_MIN) angleMin -= min(pasDeReglage, angleMin - ANGLE_MIN); objetServo.attach(pin); vitesse = -1; break; case SERVO_A_ANGLE_MAX: if (angleMax &gt; angleMin) angleMax -= min(pasDeReglage, angleMax - angleMin); objetServo.attach(pin); vitesse = -1; break; } break; case 2: /* diminution du pas de r&#233;glage */ if (pasDeReglage &gt; 1) pasDeReglage /= 2; break; case 3: /* augmentation du pas de r&#233;glage */ if (pasDeReglage &lt; 32) pasDeReglage *= 2; break; } } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;La gestion du mouvement&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Le r&#233;glage est un cas particulier, l'angle du servo peut &#234;tre en dehors de la fourchette &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMin&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;angleMax&lt;/code&gt;. Or la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; suppose que l'angle est dans la fourchette. Il ne va donc pas fonctionner correctement pour le r&#233;glage. Il faut donc l'adapter.&lt;/p&gt;
&lt;p&gt;Tout d'abord, il nous faut une variable bool&#233;enne qui va indiquer si un r&#233;glage est en cours ou non. Cette variable sera modifi&#233;e dans loop en fonction de la valeur renvoy&#233;e par &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireReglage()&lt;/code&gt;, la fonction qui renvoie l'&#233;tat du codeur.&lt;/p&gt;
&lt;p&gt;Si il n'y a aucun r&#233;glage en cours ou si le servo est dans l'une des &#233;tats SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX ou SERVO_EN_MOUVEMENT_ VERS_ANGLE_MIN, il s'agit d'un mouvement normal du servo et le code existant fonctionne. Dans l'autre cas, il faut un code sp&#233;cifique pour g&#233;rer le mouvement vers la nouvelle but&#233;e. Selon la but&#233;e o&#249; le servo est et selon le signe de la vitesse, on d&#233;termine quand le mouvement doit &#234;tre arr&#234;t&#233; :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;if (etatServo == SERVO_A_ANGLE_MIN) { if (vitesse &gt; 0 &amp;&amp; angle &gt;= angleMin) { angle = angleMin; vitesse = 0; objetServo.detach(); } else if (vitesse &lt; 0 &amp;&amp; angle &lt;= angleMin) { angle = angleMin; vitesse = 0; objetServo.detach(); } } else if (etatServo == SERVO_A_ANGLE_MAX) { if (vitesse &gt; 0 &amp;&amp; angle &gt;= angleMax) { angle = angleMax; vitesse = 0; objetServo.detach(); } else if (vitesse &lt; 0 &amp;&amp; angle &lt;= angleMax) { angle = angleMax; vitesse = 0; objetServo.detach(); } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le fait de tester l'angle par rapport aux angles minimum et maximum avec des &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&gt;=&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&lt;=&lt;/code&gt; est une s&#233;curit&#233;. En effet, en testant avec une &#233;galit&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;==&lt;/code&gt; et si pour une raison ind&#233;termin&#233;e l'angle d&#233;passait l'angle min ou max, le servo continuerait sont mouvement et irait en but&#233;e m&#233;canique, ce qui pourrait l'endommager.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Modification de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt; est modifi&#233; pour prendre en compte la fonction de r&#233;glage.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void loop() { int numServo; /* gestion du mouvement des servos */ for (numServo = 0; numServo &lt; 8; numServo++) servoMoteur[numServo].gereServo(); /* lecture d'un ordre de mouvement */ byte evenement = clavierOrdreServo.lireEvenement(&amp;numServo); /* ex&#233;cution de l'ordre de mouvement */ if (evenement == EVENEMENT_PRESSE) servoMoteur[numServo].evenementServo(); /* lecture du codeur qui d&#233;signe le servo &#224; r&#233;gler */ int servoARegler = lireReglage(); /* si positif ou nul, il y a un servo &#224; r&#233;gler */ reglageEnCours = (servoARegler &gt;= 0); /* si on a chang&#233; de servo &#224; r&#233;gler, le pas est remis &#224; 8 */ if (servoARegler != ancienServoARegler) { ancienServoARegler = servoARegler; pasDeReglage = 8; } /* ex&#233;cution de r&#233;glage */ if (reglageEnCours) servoMoteur[servoARegler].regleServo(); delay(5); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Voici le code complet du sketch &#224; t&#233;l&#233;charger.&lt;/p&gt;
&lt;div class='spip_document_328 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;57&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/zip/Huit_boutons_huit_servos_detach_reglage_cpp-3.zip' class=&#034; spip_doc_lien&#034; title='Zip - 3.1 kio' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1779519117' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-328 '&gt;&lt;strong&gt;Sketch Arduino de l'application avec r&#233;glage des but&#233;es
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Et une vid&#233;o de la mise en &#339;uvre.&lt;/p&gt;
&lt;div class=&#034;spip_document_330 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;50&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-330&#034; data-id=&#034;719d7d6751e6f1f74f9768f9841bd654&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/rc7IQZXfZqM?version=3&amp;hl=fr_FR&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1779463451' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-330 '&gt;&lt;strong&gt;Test de l'application avec le r&#233;glage des but&#233;es
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript9365470186a31ae1701cac9.67372650&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzc5NDQzNTM4JyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3Nzk0NDM1MzgnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Comme expliqu&#233; dans la vid&#233;o, il reste une paire de d&#233;tails &#224; r&#233;gler. Nous verrons cela dans le prochain article mais on commence &#224; voir le bout du tunnel !&lt;/p&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh1&#034; class=&#034;spip_note&#034; title=&#034;Notes 1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Un pas vaut 1&#181;s puisqu'on utilise la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;writeMicroseconds(...)&lt;/code&gt; pour piloter les servos&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Clavier de r&#233;glage des but&#233;es</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article62</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article62</guid>
		<dc:date>2013-11-30T12:49:01Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Essayant de ne pas faire de trop gros articles indigestes, je saucissonne un peu plus les sujets. Voici le 2e sur le r&#233;glage des but&#233;es. Il porte sur la transformation du programme que nous avions &#233;crit pour le clavier analogique afin que le m&#234;me programme puisse servir pour le clavier de r&#233;glage et en fait pour n'importe quel clavier analogique. En informatique on appelle &#231;a la g&#233;n&#233;ricit&#233;. Poussoirs de r&#233;glage de la position &lt;br class='autobr' /&gt;
Les poussoirs de r&#233;glage de la position sont mis en &#339;uvre avec (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Essayant de ne pas faire de trop gros articles indigestes, je saucissonne un peu plus les sujets. Voici le 2&lt;sup&gt;e&lt;/sup&gt; sur le r&#233;glage des but&#233;es. Il porte sur la transformation du &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article59' class=&#034;spip_in&#034;&gt;programme que nous avions &#233;crit pour le clavier analogique&lt;/a&gt; afin que le m&#234;me programme puisse servir pour le clavier de r&#233;glage et en fait pour n'importe quel clavier analogique. En informatique on appelle &#231;a la g&#233;n&#233;ricit&#233;.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Poussoirs de r&#233;glage de la position&lt;/h2&gt;
&lt;p&gt;Les poussoirs de r&#233;glage de la position sont mis en &#339;uvre avec un clavier analogique de la m&#234;me mani&#232;re que les poussoirs de commande mais nous allons employer 4 poussoirs au lieu de 8 et les connecter sur l'entr&#233;e analogique A1. Nous allons voir plus tard pourquoi 4 et pas 2.&lt;/p&gt;
&lt;p&gt;Pour avoir les valeurs des r&#233;sistances, il suffit de faire sauter un poussoir sur deux dans le tableau de &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article59' class=&#034;spip_in&#034;&gt;Plusieurs boutons poussoir sur une entr&#233;e analogique&lt;/a&gt; &#187; et d'additionner les deux r&#233;sistances de part et d'autre des poussoirs supprim&#233;s. Les valeurs des r&#233;sistances peuvent &#234;tre moins pr&#233;cises car les plages de valeurs sont deux fois plus larges. Nous avons donc :&lt;/p&gt;
&lt;table class=&#034;table spip&#034;&gt;
&lt;tbody&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt; &lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tension&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;R&#233;sistance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;R&#233;sistance approch&#233;e&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tension approch&#233;e&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Erreur&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R1&lt;/td&gt;
&lt;td&gt;1,25V&lt;/td&gt;
&lt;td&gt;110&#937;&lt;/td&gt;
&lt;td&gt;120&#937;&lt;/td&gt;
&lt;td&gt;1,33V&lt;/td&gt;
&lt;td&gt;6,4%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;R2&lt;/td&gt;
&lt;td&gt;2,5V&lt;/td&gt;
&lt;td&gt;212&#937;&lt;/td&gt;
&lt;td&gt;220&#937;&lt;/td&gt;
&lt;td&gt;2,61V&lt;/td&gt;
&lt;td&gt;4,4%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R3&lt;/td&gt;
&lt;td&gt;3,75V&lt;/td&gt;
&lt;td&gt;650&#937;&lt;/td&gt;
&lt;td&gt;560&#937;&lt;/td&gt;
&lt;td&gt;3,65V&lt;/td&gt;
&lt;td&gt;1,78%&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;h2 class=&#034;spip&#034;&gt;Le logiciel&lt;/h2&gt;
&lt;p&gt;Nous avons maintenant deux clavier analogiques, l'un pour les 8 poussoirs de changement de positions des servomoteurs et l'autre avec 4 pour le r&#233;glage. Nous allons bien entendu utiliser les m&#234;mes fonctions pour les deux claviers et en profiter pour les passer en C++ &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article63' class=&#034;spip_in&#034;&gt;comme nous l'avons fait pour les servomoteurs&lt;/a&gt; car maintenant que nous avons 2 claviers, il est logique d'avoir des objets. Un clavier analogique est jusqu'&#224; pr&#233;sent repr&#233;sent&#233; par 2 variables.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;byte etatAutomate = NON_PRESSE; int etatPoussoir = -1;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mais les fonctions &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lirePoussoirs()&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement()&lt;/code&gt; que nous avons &#233;crites ont en dur dans le code le fait qu'il y ait 8 poussoirs. Il en est de m&#234;me pour la broche de connexion. Par cons&#233;quent, pour que les fonctions puissent &#234;tre g&#233;n&#233;riques, nous allons en plus avoir besoin de la broche de connexion, du nombre de poussoirs et de ce nombre de poussoirs, nous allons d&#233;duire la taille d'une plage de valeurs. Voici le d&#233;but de notre classe &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurClavierAnalogique&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;class DescripteurClavierAnalogique { byte etatAutomate; int etatPoussoir; int taillePlage; int nbPoussoirs; int pin; };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nous allons ajouter le constructeur qui contient les initialisations ind&#233;pendantes du nombre de poussoirs et de la broche et une fonction de connexion qui va contenir les initialisations qui en sont d&#233;pendantes.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; public: DescripteurClavierAnalogique() { etatAutomate = NON_PRESSE; etatPoussoir = -1; } void connecte(int pinDeConnexion, int nombreDePoussoirs) { pin = pinDeConnexion; nbPoussoirs = nombreDePoussoirs; /* * calcule la taille d'une plage * le convertisseur a 1024 valeurs, Le taille de plage * est &#233;gal &#224; 1024/nombreDePoussoirs. */ taillePlage = 1024 / nombreDePoussoirs; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin, nous allons modifier &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lirePoussoirs()&lt;/code&gt; afin de remplacer les valeur en dur par la plage de valeurs ou le nombre de poussoirs. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lirePoussoirs()&lt;/code&gt; est plac&#233; dans la partie priv&#233;e de la classe car il n'est appel&#233; que part la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pin) + taillePlage / 2) /taillePlage; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; nbPoussoirs) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; nbPoussoirs) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == nbPoussoirs) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nous pouvons maintenant cr&#233;er nos deux objets &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;clavierOrdreServo&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;clavierReglage&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;DescripteurClavierAnalogique clavierOrdreServo; DescripteurClavierAnalogique clavierReglage;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;et &#224; appeler la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;connect(...)&lt;/code&gt; dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; clavierOrdreServo.connecte(0,8); /* pin A0, 8 poussoirs */ clavierReglage.connecte(1,4); /* pin A1, 4 poussoirs */&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour finir, la classe compl&#232;te de gestion de clavier analogique avec l'ajout de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement(...)&lt;/code&gt;. Cette classe est r&#233;utilisable sans modification dans n'importe quel montage comportant un clavier analogique.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;class DescripteurClavierAnalogique { byte etatAutomate; int etatPoussoir; int taillePlage; int nbPoussoirs; int pin; int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pin) + taillePlage / 2) /taillePlage; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; nbPoussoirs) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; nbPoussoirs) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == nbPoussoirs) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; } public: DescripteurClavierAnalogique() { etatAutomate = NON_PRESSE; etatPoussoir = -1; } void connecte(int pinDeConnexion, int nombreDePoussoirs) { pin = pinDeConnexion; nbPoussoirs = nombreDePoussoirs; /* * calcule la taille d'une plage * le convertisseur a 1024 valeurs, Le taille de plage * est &#233;gal &#224; 1024/nombreDePoussoirs. Le d&#233;calage est * la taille de la plage sur 2 */ taillePlage = 1024 / nombreDePoussoirs; } /* * construction d'un &#233;v&#233;nement en comparant * le nouvel &#233;tat des poussoirs avec l'&#233;tat pr&#233;c&#233;dent. */ byte lireEvenement(int *numPoussoir) { byte evenement; int nouvelEtatPoussoir = lirePoussoirs(); if (nouvelEtatPoussoir == etatPoussoir) evenement = AUCUN_EVENEMENT; if (nouvelEtatPoussoir &gt;= 0 &amp;&amp; etatPoussoir == -1) evenement = EVENEMENT_PRESSE; if (nouvelEtatPoussoir == -1 &amp;&amp; etatPoussoir &gt;= 0) evenement = EVENEMENT_RELACHE; etatPoussoir = nouvelEtatPoussoir; *numPoussoir = etatPoussoir; return evenement; } };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Maintenant que les deux commandes n&#233;cessaires au r&#233;glage sont mises en place, nous allons pouvoir nous concentrer sur le r&#233;glage en lui-m&#234;me.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>S&#233;lection d'un servomoteur pour le r&#233;glage des but&#233;es</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article61</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article61</guid>
		<dc:date>2013-11-23T16:06:22Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Le r&#233;glage des but&#233;es est un point important. En effet, chaque servo moteur va avoir un neutre un peu diff&#233;rent de ses cong&#233;n&#232;res. Il en va de m&#234;me pour les positions extr&#234;mes. De plus, chaque installation d'aiguille est un peu diff&#233;rente des autres. &lt;br class='autobr' /&gt;
Il est donc essentiel de pouvoir, servomoteur par servomoteur, r&#233;gler les deux positions extr&#234;mes. &lt;br class='autobr' /&gt;
Le mat&#233;riel &lt;br class='autobr' /&gt;
Afin de s&#233;lectionner l'un des servomoteurs pour r&#233;gler, au moyen de deux poussoirs, sa position extr&#234;me actuelle nous avons (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Le r&#233;glage des but&#233;es est un point important. En effet, chaque servo moteur va avoir un neutre un peu diff&#233;rent de ses cong&#233;n&#232;res. Il en va de m&#234;me pour les positions extr&#234;mes. De plus, chaque installation d'aiguille est un peu diff&#233;rente des autres.&lt;/p&gt;
&lt;p&gt;Il est donc essentiel de pouvoir, servomoteur par servomoteur, r&#233;gler les deux positions extr&#234;mes.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Le mat&#233;riel&lt;/h2&gt;
&lt;p&gt;Afin de s&#233;lectionner l'un des servomoteurs pour r&#233;gler, au moyen de deux poussoirs, sa position extr&#234;me actuelle nous avons besoin d'un dispositif permettant de donner un num&#233;ro de servomoteur. Le dispositif le plus adapt&#233; est un codeur rotatif &#224; 10 positions comme celui-ci.&lt;/p&gt;
&lt;div class='spip_document_271 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;40&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH375/P-02274jpg-88850-655e4.jpg?1692224382' width='500' height='375' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-271 '&gt;&lt;a href=&#034;http://akizukidenshi.com/img/goods/2/P-02274.jpg&#034; class=&#034;spip_url spip_out&#034; rel=&#034;external&#034;&gt;http://akizukidenshi.com/img/goods/...&lt;/a&gt;
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Ces codeurs rotatifs ont 6 broches. 2 d'entre-elles sont reli&#233;es entre elles et communes, les 4 autres codent en binaire la position du bouton (4 bits).&lt;/p&gt;
&lt;p&gt;Comme 5 entr&#233;es analogiques sont disponibles et qu'il est aussi possible de les utiliser comme entr&#233;e num&#233;rique, on ne va pas finasser et simplement utiliser une entr&#233;e par bit&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;On rappelle que les entr&#233;es/sorties logiques, en haut de l'Arduino, encore (&#8230;)&#034; id=&#034;nh1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt;. 1 entr&#233;e analogique, A1, restera disponible pour les poussoirs de r&#233;glage.&lt;/p&gt;
&lt;p&gt;Je n'ai pas de codeur rotatif en stock, &#224; la place je vais utiliser un DIP-switch &#224; 4 interrupteurs sur lequel le num&#233;ro du servo sera cod&#233; en binaire et qui sera raccord&#233; exactement de la m&#234;me fa&#231;on que le codeur. Par convention, on d&#233;cide que la valeur 0 (position 0 du codeur) est le mode d'exploitation. Aucun servo n'est s&#233;lectionn&#233; par le codeur. Les valeurs de 1 &#224; 8 permettent de s&#233;lectionner le servo &#224; r&#233;gler. La valeur 9 correspond aussi au mode exploitation o&#249; aucun servo n'est s&#233;lectionn&#233;.&lt;/p&gt;
&lt;p&gt;Le codeur est donc raccord&#233; de la mani&#232;re suivante aux entr&#233;es A2 &#224; A5.&lt;/p&gt;
&lt;div class='spip_document_321 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;373&#034; data-legende-lenx=&#034;xxxx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L486xH543/codeur-b7f3c.png?1692224286' width='486' height='543' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-321 '&gt;&lt;strong&gt;C&#226;blage du codeur
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-321 '&gt;Les interrupteurs c3, c2, c1 et c0 repr&#233;sentent chacun un chiffre binaire. Par convention, un 0 correspond &#224; l'interrupteur ouvert et un 1 &#224; l'interrupteur ferm&#233;. Si tous les interrupteurs sont ouverts, la valeur 0 est cod&#233;e, si c0 est ferm&#233; et les autres ouverts la valeur 1 est cod&#233;e. Si c2 et c1 sont ferm&#233;s, les autres ouverts la valeur 6 est cod&#233;e.
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Les entr&#233;es dispose de r&#233;sistances de tirage &#224; 5V (on dit pull-up) interne que l'on peut activer par programme. Quand les interrupteurs sont ouverts, c'est &#224; dire &#224; 0 par convention, la valeur pr&#233;sente sur les entr&#233;es est 5V et non 0V ; Il faut en tenir compte pour construire le logiciel.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Le logiciel&lt;/h2&gt;
&lt;p&gt;Pour lire la valeur num&#233;rique cod&#233;e et la stocker dans une variable enti&#232;re &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoARegler&lt;/code&gt;, il faut donc lire les entr&#233;es A2, A3, A4 et A5 en num&#233;rique, en d&#233;duire une valeur de bit et positionner le bit correspondant dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoARegler&lt;/code&gt;. C'est l'occasion de voir une nouvelle sp&#233;cificit&#233; du langage C, la manipulation des bits dans une variable.&lt;/p&gt;
&lt;p&gt;Le langage C permet de faire des op&#233;rations logiques bit &#224; bit. Les op&#233;rateurs permettant de telles op&#233;rations sont : le &lt;i&gt;et&lt;/i&gt; bit &#224; bit, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&amp;&lt;/code&gt;, le &lt;i&gt;ou&lt;/i&gt; bit &#224; bit, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;|&lt;/code&gt;, le &lt;i&gt;ou exclusif&lt;/i&gt; bit &#224; bit, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;^&lt;/code&gt; et le &lt;i&gt;non&lt;/i&gt; (inversion de bit) bit &#224; bit not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;~&lt;/code&gt;. Il existe aussi deux op&#233;rateurs de d&#233;calage : &lt;i&gt;d&#233;calage logique vers la gauche&lt;/i&gt; d'un certain nombre de bits, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&lt;&lt;&lt;/code&gt; et le &lt;i&gt;d&#233;calage vers la droite&lt;/i&gt; d'un certain nombre de bits, not&#233; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&gt;&gt;&lt;/code&gt;. Dans les deux cas, les bits laiss&#233;s libres par le d&#233;calage sont &#224; 0&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb2&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Seulement si la variable est non sign&#233;e. Si la variable est sign&#233;e, le (&#8230;)&#034; id=&#034;nh2&#034;&gt;2&lt;/a&gt;]&lt;/span&gt;, les bits qui sont expuls&#233;s sont perdus.&lt;/p&gt;
&lt;p&gt;Ainsi, si l'on veut construire un byte dont tous les bits sont &#224; 0 sauf les bits 0, 2 et 4 qui sont &#224; 1 :&lt;/p&gt;
&lt;div class='spip_document_274 spip_document spip_documents spip_document_image spip_documents_center spip_document_center'&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L330xH56/valeur-ef212.png?1692224286' width='330' height='56' alt='' /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;On peut &#233;crire : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;1 &lt;&lt; 4 | 1 &lt;&lt; 2 | 1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;C'est &#224; dire :&lt;/p&gt;
&lt;div class='spip_document_316 spip_document spip_documents spip_document_image spip_documents_center spip_document_center'&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH233/composition-2-617da.png?1692224382' width='500' height='233' alt='' /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Ce qui est bien le r&#233;sultat escompt&#233;.&lt;/p&gt;
&lt;p&gt;On peut se poser la question de savoir que renvoit la lecture d'une entr&#233;e en num&#233;rique par un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;digitalRead(...)&lt;/code&gt;. Eh bien elle vaut soit HIGH, soit LOW. Ces deux constantes sont en fait des entiers qui valent 1 pour HIGH et 0 pour LOW. On peut donc utiliser la valeur renvoy&#233;e par un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;digitalRead(...)&lt;/code&gt; dans un calcul. C'est ce que nous allons faire pour calculer la valeur du codeur.&lt;/p&gt;
&lt;p&gt;En examinant le sch&#233;ma de connexion, on voit que la condition permettant de construire le bit correspondant &#224; une des entr&#233;es est l'inverse de la valeur renvoy&#233;e par &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;digitalRead(...)&lt;/code&gt; parce que la position ouverte de l'interrupteur correspond &#224; +5V. Il faut donc inverser cette valeur en utilisant le non logique : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;!&lt;/code&gt;. Cet op&#233;rateur retourne un 1 si son op&#233;rande est un 0 et un 0 si son op&#233;rande est diff&#233;rent de 0.&lt;/p&gt;
&lt;p&gt;Donc la valeur du codeur peut &#234;tre construite par l'expression suivante :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;servoARegler = (! digitalRead(A2)) &lt;&lt; 3 | (! digitalRead(A3)) &lt;&lt; 2 | (! digitalRead(A4)) &lt;&lt; 1 | (! digitalRead(A5));&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pour programmer proprement, on va loger ceci dans une fonction, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireReglage()&lt;/code&gt; et en profiter pour recadrer la valeur brute. Si la valeur brute est plus grande que 8, elle est remise &#224; 0 et la valeur brute - 1 est retourn&#233;e. De cette mani&#232;re -1 signifie &#171; rien &#224; r&#233;gler &#187; et une valeur positive d&#233;signe le num&#233;ro du servo &#224; r&#233;gler.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;/* * Lecture du codeur de r&#233;glage. * Retourne -1 si aucun servo n'est s&#233;lectionn&#233; et * le num&#233;ro du servo de 0 &#224; 7 si un servo est s&#233;lectionn&#233; */ int lireReglage() { int servoARegler = (! digitalRead(A2)) &lt;&lt; 3 | (! digitalRead(A3)) &lt;&lt; 2 | (! digitalRead(A4)) &lt;&lt; 1 | (! digitalRead(A5)); if (servoARegler &gt; 8) servoARegler = 0; return servoARegler - 1; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Comme c'est l'&#233;tat du codeur qui nous int&#233;resse et non les &#233;v&#233;nements de changement d'&#233;tat, il n'est pas n&#233;cessaire de se pr&#233;occuper des transitoires et autres rebonds.&lt;/p&gt;
&lt;p&gt;Il va aussi falloir activer les r&#233;sistances interne de pull-up. Faisons ceci dans une fonction qui sera appel&#233;e &#224; partir de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void initialiseCodeur() { /* Active le pullup des entr&#233;es A2, A3, A4 et A5 */ digitalWrite(A2,HIGH); digitalWrite(A3,HIGH); digitalWrite(A4,HIGH); digitalWrite(A5,HIGH); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh1&#034; class=&#034;spip_note&#034; title=&#034;Notes 1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;On rappelle que les entr&#233;es/sorties logiques, en haut de l'Arduino, encore disponibles sont r&#233;serv&#233;es pour les LED t&#233;moin.&lt;/p&gt;
&lt;/div&gt;&lt;div id=&#034;nb2&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh2&#034; class=&#034;spip_note&#034; title=&#034;Notes 2&#034; rev=&#034;appendix&#034;&gt;2&lt;/a&gt;] &lt;/span&gt;Seulement si la variable est non sign&#233;e. Si la variable est sign&#233;e, le d&#233;calage &#224; droite remplit les bits laiss&#233;s libres avec le bit de signe.&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Un zeste de C++</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article63</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article63</guid>
		<dc:date>2013-11-23T10:19:00Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Comme nous l'avons d&#233;taill&#233; dans l'article pr&#233;c&#233;dent &#171; 8 poussoirs et 8 servos, enfin ! &#187;, le passage d'un servomoteur &#224; 8 servomoteurs, nous &#224; contraint &#224; rassembler les variables permettant de d&#233;crire l'&#233;tat d'un servomoteur dans une struct afin de cr&#233;er un tableau de 8 &#233;l&#233;ments de ce type. &lt;br class='autobr' /&gt; struct DescripteurServo Servo objetServo ; int vitesse ; int angle ; int pin ; byte etatServo ; ; struct DescripteurServo servoMoteur[8] ; &lt;br class='autobr' /&gt;
Malheureusement, le programme (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Comme nous l'avons d&#233;taill&#233; dans l'article pr&#233;c&#233;dent &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article60' class=&#034;spip_in&#034;&gt;8 poussoirs et 8 servos, enfin !&lt;/a&gt; &#187;, le passage d'un servomoteur &#224; 8 servomoteurs, nous &#224; contraint &#224; rassembler les variables permettant de d&#233;crire l'&#233;tat d'un servomoteur dans une &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;struct&lt;/code&gt; afin de cr&#233;er un tableau de 8 &#233;l&#233;ments de ce type.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;struct DescripteurServo { Servo objetServo; int vitesse; int angle; int pin; byte etatServo; }; struct DescripteurServo servoMoteur[8];&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Malheureusement, le programme manipulant un servomoteur s'en est trouv&#233; alourdi car dor&#233;navant, il faut pr&#233;ciser de quel &#233;l&#233;ment du tableau il s'agit quand on veut modifier l'un des membre du descripteur de servomoteur. On se retrouve partout avec des &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur[numServo].&lt;/code&gt;, Ce qui n'est ni joli, ni agr&#233;able.&lt;/p&gt;
&lt;p&gt;De plus, si on examine le programme tel qu'il est actuellement, on s'aper&#231;oit que seules deux fonctions s'occupent du descripteur de servomoteur : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; pour accomplir le mouvement lent et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo()&lt;/code&gt; pour donner l'ordre de mouvement. Il y a aussi &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt; qui initialise les descripteurs mais on pourrait tr&#232;s bien le faire dans une fonction appel&#233;e par &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;. Il est donc tentant de mettre tout cela ensemble, le descripteur de servomoteur et les fonctions qui le manipule, et c'est exactement ce que permet le C++.&lt;/p&gt;
&lt;p&gt;Le C++ va donc venir &#224; notre secours pour simplifier et a&#233;rer consid&#233;rablement notre programme.&lt;/p&gt;
&lt;blockquote class=&#034;spip&#034;&gt;
&lt;p&gt;
Le C++ pris dans sa globalit&#233; est un langage complexe et nous n'avons pas besoin de tout. Nous n'allons prendre &lt;i&gt;que&lt;/i&gt; ce dont nous avons besoin et qui va nous faciliter la t&#226;che.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Le C++ est tr&#232;s utilis&#233; dans l'Arduino. Par exemple, la biblioth&#232;que Servo que nous utilisons est &#233;crite en C++. C++ est une extension du C qui ajoute principalement une chose : les objets. Un objet contient une ou plusieurs donn&#233;es et une ou plusieurs fonctions (on dit m&#233;thode dans le jargon) pour lire/&#233;crire cette valeur mais pas seulement. Pour cr&#233;er un objet, on a besoin d'un type, comme pour cr&#233;er une variable enti&#232;re, on a besoin du type int. Pour cr&#233;er un type d'objet, on d&#233;clare une classe. Faisons &#231;a directement avec notre &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; :&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;class DescripteurServo { Servo objetServo; int vitesse; int angle; int pin; byte etatServo; };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Rien de renversant jusqu'&#224; l&#224;. C'est exactement comme une &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;struct&lt;/code&gt;. La particularit&#233; est de pouvoir y mettre aussi des fonctions qui deviennent donc membres de la classe. Mettons y &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo()&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;class DescripteurServo { Servo objetServo; int vitesse; int angle; int pin; byte etatServo; public: void gereServo() { objetServo.writeMicroseconds(angle); angle += vitesse; if (angle &gt; angleMax) { angle = angleMax; vitesse = 0; objetServo.detach(); etatServo = SERVO_A_ANGLE_MAX; } else if (angle &lt; angleMin) { angle = angleMin; vitesse = 0; objetServo.detach(); etatServo = SERVO_A_ANGLE_MIN; } } void evenementServo() { switch (etatServo) { case SERVO_A_ANGLE_MIN: objetServo.attach(pin); case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: vitesse = 1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: objetServo.attach(pin); case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: vitesse = -1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } } };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Comme vous pouvez le constater, tous les &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur[numServo].&lt;/code&gt; ont disparu. En effet, les fonctions membre acc&#232;dent directement aux donn&#233;es membres de la classe. Par ailleurs, l'argument &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numServo&lt;/code&gt; des fonctions a disparu pour la m&#234;me raison.&lt;br class='autobr' /&gt;
Enfin, le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;public:&lt;/code&gt; permet de rendre les deux fonctions membres appelables depuis l'ext&#233;rieur de l'objet. Notez aussi que les donn&#233;es membres ne sont pas publiques, on ne peut donc y acc&#233;der depuis l'ext&#233;rieur de l'objet.&lt;/p&gt;
&lt;p&gt;Il reste une dernier point &#224; r&#233;gler. Dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;, une boucle initialise chaque descripteur de servo. Certaines initialisations sont d&#233;pendantes du num&#233;ro de servo (en fait du num&#233;ro de broche &#224; laquelle le servo est connect&#233;), d'autre ne le sont pas. En C++, un objet peut avoir un &lt;i&gt;constructeur&lt;/i&gt;. Il s'agit d'une fonction membre qui porte le m&#234;me nom que la classe et qui est ex&#233;cut&#233;e lors de la cr&#233;ation de l'objet. Nous allons ajouter ce constructeur pour y mettre les initialisations ind&#233;pendantes du num&#233;ro de broche. Enfin nous allons ajouter une fonction membre pour les initialisations qui sont d&#233;pendantes du num&#233;ro de broche.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; DescripteurServo() { angle = angleMin; vitesse = 0; etatServo = SERVO_A_ANGLE_MIN; } void connecte(int pinDeConnection) { pin = pinDeConnection; objetServo.attach(pinDeConnection); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il reste &#224; modifier le reste du programme pour l'adapter. Tout d'abord, dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt; les initialisations consistent maintenant &#224; appeler la fonction membre &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;connecte(...)&lt;/code&gt;. Les intialisation ind&#233;pendantes du num&#233;ro de broche sont d&#233;j&#224; faites.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void setup() { /* Initialisation des servos */ int numServo; for (numServo = 0; numServo &lt; 8; numServo++) servoMoteur[numServo].connecte(numServo + 2); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notez la syntaxe pour appeler une fonction membre. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur[numServo]&lt;/code&gt; est un objet du tableau, le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;.&lt;/code&gt; permet d'acc&#233;der &#224; un de ses membres et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;connecte(numServo +2)&lt;/code&gt; permet d'appeler la fonction membre &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;connecte&lt;/code&gt; en lui passant &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numServo + 2&lt;/code&gt; comme argument.&lt;/p&gt;
&lt;p&gt;De la m&#234;me mani&#232;re, la boucle qui appelait &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo()&lt;/code&gt; pour chacun des servomoteurs est modifi&#233;e.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; for (numServo = 0; numServo &lt; 8; numServo++) servoMoteur[numServo].gereServo();&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin, la notification d'un &#233;v&#233;nement sur le poussoir est aussi modifi&#233;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;cpp&#034; class='spip_code spip_code_block language-cpp' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; byte evenement = lireEvenement(&amp;numServo); if (evenement == EVENEMENT_PRESSE) { servoMoteur[numServo].evenementServo(); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Rien de bien sorcier finalement. Le programme est beaucoup plus clair &#233;crit de cette mani&#232;re et cerise sur le g&#226;teau, il prend 274 octets de moins une fois compil&#233; !&lt;/p&gt;
&lt;p&gt;Voici le sketch Arduino correspondant :&lt;/p&gt;
&lt;div class='spip_document_315 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;64&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/zip/Huit_boutons_huit_servos_detach_cpp-2.zip' class=&#034; spip_doc_lien&#034; title='Zip - 1.8 kio' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1779519117' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-315 '&gt;&lt;strong&gt;Logiciel de pilotage de 8 servos avec 8 boutons r&#233;&#233;crit en C++
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>8 poussoirs et 8 servos, enfin !</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article60</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article60</guid>
		<dc:date>2013-11-17T13:12:48Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Dans &#171; Commande du servo-moteur par bouton poussoir &#187;, nous avons vu comment commander un servo-moteur avec un poussoir. Dans &#171; Plusieurs boutons poussoir sur une entr&#233;e analogique &#187;, nous avons vu comment connecter 8 poussoirs sur une entr&#233;e analogique et d&#233;tecter lequel est press&#233;. Il reste maintenant &#224; mettre en &#339;uvre les 8 servos. &lt;br class='autobr' /&gt;
Les variables pour manipuler les 8 servos &lt;br class='autobr' /&gt;
Si vous vous rappelez, plusieurs variables &#233;taient employ&#233;es pour notre servo : l'objet de type Servo permettant (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article58' class=&#034;spip_in&#034;&gt;Commande du servo-moteur par bouton poussoir&lt;/a&gt; &#187;, nous avons vu comment commander un servo-moteur avec un poussoir. Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article59' class=&#034;spip_in&#034;&gt;Plusieurs boutons poussoir sur une entr&#233;e analogique&lt;/a&gt; &#187;, nous avons vu comment connecter 8 poussoirs sur une entr&#233;e analogique et d&#233;tecter lequel est press&#233;. Il reste maintenant &#224; mettre en &#339;uvre les 8 servos.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Les variables pour manipuler les 8 servos&lt;/h2&gt;
&lt;p&gt;Si vous vous rappelez, plusieurs variables &#233;taient employ&#233;es pour notre servo : l'objet de type &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;Servo&lt;/code&gt; permettant de le piloter, son angle, sa vitesse, son &#233;tat. Comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;Servo monServo; int vitesse = 0; int angle = angleMin; byte etatServo = SERVO_A_ANGLE_MIN;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Si nous avons 8 servos, il va falloir 8 exemplaires de chacune de ces variables. Plut&#244;t que de r&#233;pliquer 8 fois ces d&#233;finitions, ce qui serait fastidieux, nous allons cr&#233;er un tableau avec autant d'&#233;l&#233;ments que de servos. Mais avant de cr&#233;er ce tableau, nous devons &lt;i&gt;mettre ces variables ensemble&lt;/i&gt;. Pour les mettre ensemble, il existe en C les &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;struct&lt;/code&gt; pour structure. Comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;struct DescripteurServo { Servo objetServo; int vitesse; int angle; byte etatServo; };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Une struct a un nom, ici DescripteurServo, et des membres, objetServo, vitesse, angle et etatServo. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;struct DescripteurServo&lt;/code&gt; est en quelques sortes un nouveau type de donn&#233;e, comme int ou byte, et on peut l'utiliser pour cr&#233;er un tableau de 8 &#233;l&#233;ments que nous appelons &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur&lt;/code&gt; comme ceci.&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;struct DescripteurServo servoMoteur[8];&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur&lt;/code&gt; est le nom de notre tableau, le [8] indique qu'il contient 8 &#233;l&#233;ments et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;struct DescripteurServo&lt;/code&gt; est le type d'un &#233;l&#233;ment.&lt;/p&gt;
&lt;p&gt;Pour acc&#233;der &#224; un &#233;l&#233;ment du tableau &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur&lt;/code&gt;, il faut indiquer son num&#233;ro, entre 0 et 7 compris. Ainsi, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur[4]&lt;/code&gt; est le 5e &#233;l&#233;ment&lt;span class=&#034;spip_note_ref&#034;&gt; [&lt;a href=&#034;#nb2-1&#034; class=&#034;spip_note&#034; rel=&#034;appendix&#034; title=&#034;Oui le 5e puisque le premier &#224; le num&#233;ro 0&#034; id=&#034;nh2-1&#034;&gt;1&lt;/a&gt;]&lt;/span&gt; du tableau.&lt;/p&gt;
&lt;p&gt;Enfin, pour acc&#233;der &#224; un membre d'un &#233;l&#233;ment, il faut ajouter un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;.&lt;/code&gt; et le nom de l'&#233;l&#233;ment. Ainsi, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;servoMoteur[4].angle&lt;/code&gt; permet d'acc&#233;der &#224; l'angle du 5e servo.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;La mise &#224; jour de l'angle des 8 servos&lt;/h2&gt;
&lt;p&gt;Pour un seul servo, le morceau de programme de mise &#224; jour de l'angle &#233;tait le suivant.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; /* actualisation de l'angle du servo */ monServo.writeMicroseconds(angle); angle = angle + vitesse; if (angle &gt; angleMax) { angle = angleMax; vitesse = 0; etatServo = SERVO_A_ANGLE_MAX; } else if (angle &lt; angleMin) { angle = angleMin; vitesse = 0; etatServo = SERVO_A_ANGLE_MIN; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Comme nous avons maintenant un tableau de variables, il faut le r&#233;&#233;crire. Pour bien s&#233;parer les diff&#233;rentes parties du programme qui commence &#224; grossir, nous allons d&#233;placer ce morceau de programme dans une fonction, appelons la &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo&lt;/code&gt;. Cette fonction prendra un argument, le num&#233;ro de servo &#224; g&#233;rer. Ce num&#233;ro de servo va servir &#224; acc&#233;der au tableau.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void gereServo(int numServo) { servoMoteur[numServo].objetServo.writeMicroseconds( servoMoteur[numServo].angle); servoMoteur[numServo].angle += servoMoteur[numServo].vitesse; if (servoMoteur[numServo].angle &gt; angleMax) { servoMoteur[numServo].angle = angleMax; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX; } else if (servoMoteur[numServo].angle &lt; angleMin) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;, nous allons appeler cette fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo&lt;/code&gt; pour chacun des servos. Pour cela nous allons faire une boucle &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;for( ... ; ... ; ... )&lt;/code&gt;. Pour parcourir tous les servos, nous allons &#233;crire &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;for( numServo = 0; numServo &lt; 8; numServo++)&lt;/code&gt;. Le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numServo = 0;&lt;/code&gt; est ex&#233;cut&#233; une fois au d&#233;but de la boucle. il s'agit de l'initialisation. Le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numServo &lt; 8&lt;/code&gt; est une condition qui est test&#233;e au d&#233;but de chaque &lt;i&gt;it&#233;ration&lt;/i&gt;. Si la condition est vraie, la boucle continue, sinon elle s'arr&#234;te. Enfin le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numServo++&lt;/code&gt; est ex&#233;cut&#233; &#224; la fin de chaque it&#233;ration de la boucle, numServo est augment&#233; de 1. Par cons&#233;quent, cette boucle va produire 8 it&#233;rations et numServo vaudra successivement 0, 1, 2, 3, 4, 5, 6 et 7, ce qui correspond bien au parcours des &#233;l&#233;ments de notre tableau servoMoteur.&lt;/p&gt;
&lt;p&gt;G&#233;rer les 8 servos est donc pris en charge par cette ligne dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;for (numServo = 0; numServo &lt; 8; numServo++) gereServo(numServo);&lt;/code&gt;&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Int&#233;gration de la commande par poussoir&lt;/h2&gt;
&lt;p&gt;Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article58' class=&#034;spip_in&#034;&gt;Commande du servo-moteur par bouton poussoir&lt;/a&gt; &#187;, L'unique poussoir &#233;tait lu et la vitesse du servo &#233;tait chang&#233;e. Comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; byte evenement = lireEvenement(); if (evenement == EVENEMENT_PRESSE) { switch (etatServo) { case SERVO_A_ANGLE_MIN: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: vitesse = 1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: vitesse = -1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Nous allons isoler le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch ... case&lt;/code&gt; dans une fonction que nous appelons &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo(...)&lt;/code&gt; et dont l'argument est le num&#233;ro de servo. Ce num&#233;ro de servo est le num&#233;ro de bouton press&#233;. Il suffit alors de modifier la vitesse du servo correspondant. Comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void evenementServo(int numServo) { switch (servoMoteur[numServo].etatServo) { case SERVO_A_ANGLE_MIN: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: servoMoteur[numServo].vitesse = 1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: servoMoteur[numServo].vitesse = -1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il ne reste plus qu'&#224; lire l'&#233;v&#233;nement du bouton comme dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article59' class=&#034;spip_in&#034;&gt;Plusieurs boutons poussoir sur une entr&#233;e analogique&lt;/a&gt; &#187; et &#224; appeler la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo(...)&lt;/code&gt; avec le num&#233;ro de bouton recueilli.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; byte evenement = lireEvenement(&amp;numServo); if (evenement == EVENEMENT_PRESSE) evenementServo(numServo);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le programme complet est le suivant.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;#include &lt;Servo.h&gt; const byte SERVO_A_ANGLE_MIN = 0; const byte SERVO_A_ANGLE_MAX = 1; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3; const int angleMin = 1250; const int angleMax = 1750; struct DescripteurServo { Servo objetServo; int vitesse; int angle; byte etatServo; }; struct DescripteurServo servoMoteur[8]; const byte NON_PRESSE = 0; const byte ENFONCE = 1; const byte PRESSE = 2; byte etatAutomate = NON_PRESSE; int etatPoussoir = -1; const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2; const int pinPoussoirs = 0; /* * Lecture des poussoirs. &#192; l'aide d'un automate, on assure que les valeurs * transitoires sont filtr&#233;es. */ int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; 8) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; 8) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == 8) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; } /* * construction d'un &#233;v&#233;nement en comparant * le nouvel &#233;tat des poussoirs avec l'&#233;tat pr&#233;c&#233;dent. */ byte lireEvenement(int *numPoussoir) { byte evenement; int nouvelEtatPoussoir = lirePoussoirs(); if (nouvelEtatPoussoir == etatPoussoir) evenement = AUCUN_EVENEMENT; if (nouvelEtatPoussoir &gt;= 0 &amp;&amp; etatPoussoir == -1) evenement = EVENEMENT_PRESSE; if (nouvelEtatPoussoir == -1 &amp;&amp; etatPoussoir &gt;= 0) evenement = EVENEMENT_RELACHE; etatPoussoir = nouvelEtatPoussoir; *numPoussoir = etatPoussoir; return evenement; } /* * Initialisations. Chaque servomoteur est initialis&#233; &#224; l'angle minimum * sa vitesse est mise &#224; 0 */ void setup() { /* Initialisation des servos */ int numServo; for (numServo = 0; numServo &lt; 8; numServo++) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; servoMoteur[numServo].objetServo.attach(numServo+2); } } /* * Actualisation de l'angle du servo */ void gereServo(int numServo) { servoMoteur[numServo].objetServo.writeMicroseconds( servoMoteur[numServo].angle); servoMoteur[numServo].angle += servoMoteur[numServo].vitesse; if (servoMoteur[numServo].angle &gt; angleMax) { servoMoteur[numServo].angle = angleMax; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX; } else if (servoMoteur[numServo].angle &lt; angleMin) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; } } /* * changement de consigne d'un servomoteur. */ void evenementServo(int numServo) { switch (servoMoteur[numServo].etatServo) { case SERVO_A_ANGLE_MIN: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: servoMoteur[numServo].vitesse = 1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: servoMoteur[numServo].vitesse = -1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } } void loop() { int numServo; for (numServo = 0; numServo &lt; 8; numServo++) gereServo(numServo); byte evenement = lireEvenement(&amp;numServo); if (evenement == EVENEMENT_PRESSE) evenementServo(numServo); delay(3); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 class=&#034;spip&#034;&gt;Coupure de la commande dans les positions extr&#234;mes&lt;/h2&gt;
&lt;p&gt;Jusqu'&#224; maintenant, une fois qu'un servomoteur a gagn&#233; une de ses deux positions extr&#234;mes, la commande PWM de position reste active. Par cons&#233;quent l'&#233;lectronique du servomoteur continue d'asservir la position. Or, en pr&#233;sence d'une r&#233;sistance m&#233;canique comme par exemple l'effet ressort de la tige de commande de l'aiguille, l'asservissement de position fait que le servomoteur grogne. C'est un inconv&#233;nient, &#224; la fois pour les oreilles et pour la consommation &#233;lectrique.&lt;/p&gt;
&lt;p&gt;Pour supprimer cet asservissement une fois que le servomoteur a accompli son mouvement, il suffit de couper la commande PWM. Ce n'est pas explicitement pr&#233;vu dans la biblioth&#232;que Servo de l'Arduino mais il suffit de d&#233;tacher le servo de la broche de sortie par la m&#233;thode &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;detach()&lt;/code&gt; pour couper la commande PWM.&lt;/p&gt;
&lt;p&gt;Pour simplifier le programme, on va ajouter dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;DescripteurServo&lt;/code&gt; un membre pour stocker le num&#233;ro de broche. Appelons le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;pin&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;struct DescripteurServo { Servo objetServo; int vitesse; int angle; int pin; byte etatServo; };&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il faut &#233;videmment ne pas oublier d'initialiser &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;pin&lt;/code&gt; dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; for (numServo = 0; numServo &lt; 8; numServo++) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; servoMoteur[numServo].pin = numServo + 2; servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dans la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;gereServo(...)&lt;/code&gt; on va d&#233;tacher le servo quand une des positions extr&#234;mes est atteinte.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; if (servoMoteur[numServo].angle &gt; angleMax) { servoMoteur[numServo].angle = angleMax; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].objetServo.detach(); servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MAX; } else if (servoMoteur[numServo].angle &lt; angleMin) { servoMoteur[numServo].angle = angleMin; servoMoteur[numServo].vitesse = 0; servoMoteur[numServo].objetServo.detach(); servoMoteur[numServo].etatServo = SERVO_A_ANGLE_MIN; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin, dans la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;evenementServo&lt;/code&gt;, on va attacher de nouveau le servo &#224; la broche quand si le servo est dans une des positions extr&#234;mes. On voit ici l'int&#233;r&#234;t d'avoir s&#233;parer les cas SERVO_A_ANGLE_x et SERVO_EN_MOUVEMENT_VERS_ANGLE_x car pour le second il ne faut pas attacher le servo &#224; la broche.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;void evenementServo(int numServo) { switch (servoMoteur[numServo].etatServo) { case SERVO_A_ANGLE_MIN: servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin); case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: servoMoteur[numServo].vitesse = 1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: servoMoteur[numServo].objetServo.attach(servoMoteur[numServo].pin); case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: servoMoteur[numServo].vitesse = -1; servoMoteur[numServo].etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le programme devenant plus gros, je vais cesser de donner son code in-extenso sur les pages du blog. Le voici donc &#224; t&#233;l&#233;charger&lt;/p&gt;
&lt;div class='spip_document_277 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;51&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;a href='https://modelleisenbahn.triskell.org/IMG/zip/Huit_boutons_huit_servos_detach-3.zip' class=&#034; spip_doc_lien&#034; title='Zip - 1.4 kio' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1779519117' width='64' height='64' alt='' /&gt;&lt;/a&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-277 '&gt;&lt;strong&gt;Programme Arduino avec coupure de la commande PWM
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;&lt;h2 class=&#034;spip&#034;&gt;Les essais&lt;/h2&gt;&lt;blockquote class=&#034;spip&#034;&gt;
&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt;, avec 8 servomoteurs tirant sur l'alimentation de l'Arduino, il faut prendre certaines pr&#233;cautions. Il faut tout d'abord s'assurer que la consommation totale n'exc&#232;de pas ce que l'Arduino peut fournir. Son r&#233;gulateur de tension est donn&#233; pour 1A mais la carte elle-m&#234;me consomme.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Pour mes exp&#233;rimentations j'ai mesur&#233; la consommation des servos HK15178. Au repos, il consomment 7mA. En mouvement &#224; la vitesse impos&#233;e, ils montent &#224; un peu moins de 60mA. Si il n'y qu'un seul servo en mouvement &#224; un instant, l'ensemble va donc consommer 7 &#215; 7mA + 60mA = 110mA ce qui reste raisonnable. Bloqu&#233;, il consomme 150mA. Dans les faits la connexion du 6e servo a provoqu&#233; la coupure de l'alimentation car le r&#233;gulateur a d&#233;tect&#233; une consommation excessive. Comme d&#233;j&#224; indiqu&#233; dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article36' class=&#034;spip_in&#034;&gt;La carte de commande 6 servo-moteurs, le mat&#233;riel&lt;/a&gt; &#187;, l'appel de courant lors de la mise sous tension d'un servomoteur peut &#234;tre important.&lt;/p&gt;
&lt;p&gt;Pour une installation sur le r&#233;seau, il est donc pr&#233;f&#233;rable de pr&#233;voir une alimentation s&#233;par&#233;e pour les servomoteurs.&lt;/p&gt;
&lt;p&gt;Voici la vid&#233;o des essais.&lt;/p&gt;
&lt;div class=&#034;spip_document_270 spip_document spip_documents spip_document_video&#034;&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-270&#034; data-id=&#034;3d79cd4c58bb6325c6cd9345e9fdb9ff&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/9iFSObeONTY?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1779463451' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#034;base64javascript20148679026a324397b1e156.92689948&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzc5NDQzNTM4JyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3Nzk0NDM1MzgnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;La prochain article sera consacr&#233; &#224; l'ajout de la fonction de r&#233;glage des but&#233;es.&lt;/p&gt;&lt;/div&gt;
		&lt;hr /&gt;
		&lt;div class='rss_notes'&gt;&lt;div id=&#034;nb2-1&#034;&gt;
&lt;p&gt;&lt;span class=&#034;spip_note_ref&#034;&gt;[&lt;a href=&#034;#nh2-1&#034; class=&#034;spip_note&#034; title=&#034;Notes 2-1&#034; rev=&#034;appendix&#034;&gt;1&lt;/a&gt;] &lt;/span&gt;Oui le 5e puisque le premier &#224; le num&#233;ro 0&lt;/p&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Plusieurs boutons poussoir sur une entr&#233;e analogique</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article59</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article59</guid>
		<dc:date>2013-11-16T22:11:12Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Dans &#171; Commande du servo-moteur par bouton poussoir &#187;, nous avons vu comment connecter un bouton poussoir &#224; une entr&#233;e analogique. Dans celui-ci nous allons voir comment en connecter plusieurs et lire lequel est enfonc&#233;. &lt;br class='autobr' /&gt;
Cette id&#233;e de connecter plusieurs poussoirs sur une entr&#233;e analogique n'est pas nouvelle. Une Application Note de Freescale existe et l'id&#233;e m'a &#233;t&#233; souffl&#233;e par Marc-Henri que je remercie au passage. &lt;br class='autobr' /&gt; Marc-Henri vient de publier un article sur son blog qui d&#233;crit (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article58' class=&#034;spip_in&#034;&gt;Commande du servo-moteur par bouton poussoir&lt;/a&gt; &#187;, nous avons vu comment connecter un bouton poussoir &#224; une entr&#233;e analogique. Dans celui-ci nous allons voir comment en connecter plusieurs et lire lequel est enfonc&#233;.&lt;/p&gt;
&lt;p&gt;Cette id&#233;e de connecter plusieurs poussoirs sur une entr&#233;e analogique n'est pas nouvelle. Une &lt;a href=&#034;http://www.google.com/url?sa=t&amp;rct=j&amp;q=&amp;esrc=s&amp;source=web&amp;cd=1&amp;ved=0CD8QFjAA&amp;url=http%3A%2F%2Fwww.freescale.com%2Ffiles%2Fmicrocontrollers%2Fdoc%2Fapp_note%2FAN1775.pdf&amp;ei=N-mBUvfhOqSL0AXGjYDwAw&amp;usg=AFQjCNFrcxi0FKUV0ecL8sXGIpLDyUouQg&amp;sig2=fqTCJzuf9lbYd3E8jc0jVg&amp;bvm=bv.56146854,d.d2k&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;&lt;i&gt;Application Note&lt;/i&gt; de Freescale&lt;/a&gt; existe et l'id&#233;e m'a &#233;t&#233; souffl&#233;e par &lt;a href=&#034;http://savignyexpress.wordpress.com&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;Marc-Henri&lt;/a&gt; que je remercie au passage.&lt;/p&gt;
&lt;blockquote class=&#034;spip&#034;&gt;
&lt;p&gt;
Marc-Henri vient de publier un &lt;a href=&#034;http://savignyexpress.wordpress.com/2013/11/18/connecter-plusieurs-boutons-poussoir-a-un-microcontroleur/&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;article sur son blog&lt;/a&gt; qui d&#233;crit pr&#233;cis&#233;ment le calcul des r&#233;sistances ainsi qu'une &lt;a href=&#034;http://savignyexpress.files.wordpress.com/2013/11/clavieranalogique.xls&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;feuille de calcul&lt;/a&gt; (format Excel) le mettant en &#339;uvre pour un nombre quelconque de poussoirs&lt;/p&gt;
&lt;/blockquote&gt;&lt;h2 class=&#034;spip&#034;&gt;Principe de fonctionnement&lt;/h2&gt;
&lt;p&gt;Avec un seul poussoir, nous avons vu que l'entr&#233;e analogique de l'Arduino &#233;tait tir&#233;e &#224; la masse via une r&#233;sistance de 10k&#937;. L'appui sur le poussoir amenait cette entr&#233;e &#224; 5V. Pour la suite, on va inverser la connexion. L'entr&#233;e analogique esr tir&#233;e &#224; +5V et l'appui sur le poussoir am&#232;ne cette entr&#233;e &#224; la masse. En effet, avec plusieurs poussoirs, cette fa&#231;on de faire est plus commode car, sur le r&#233;seau, la masse est distribu&#233;e partout alors que ce n'est pas le cas pour le +5V.&lt;/p&gt;
&lt;div class='spip_document_258 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;85&#034; data-legende-lenx=&#034;xx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L490xH558/poussoir_gnd-33a32.png?1692301737' width='490' height='558' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-258 '&gt;&lt;strong&gt;Connexion d'un poussoir &#224; l'entr&#233;e analogique de l'Arduino Uno, &#233;tat de repos &#224; +5V
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Imaginons maintenant que nous ajoutions un second poussoir en parall&#232;le du premier et qu'il soit connect&#233; entre l'entr&#233;e analogique de l'Arduino et la masse via une r&#233;sistance, &#233;galement de 10k&#937;, comme ceci.&lt;/p&gt;
&lt;div class='spip_document_260 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;53&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH457/poussoir_double_gnd-2-18090.png?1692301737' width='500' height='457' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-260 '&gt;&lt;strong&gt;Connexion de deux poussoirs &#224; une entr&#233;e analogique
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Lorsque &lt;strong&gt;B0&lt;/strong&gt; est press&#233;, nous avons le m&#234;me comportement, l'entr&#233;e analogique est &#224; 0V. Lorsque &lt;strong&gt;B1&lt;/strong&gt; est press&#233;, les deux r&#233;sistances sont en s&#233;rie entre 5V et 0V et l'entr&#233;e analogique est &#224; la tension qui existe entre les deux r&#233;sistances. On voit qu'il s'agit d'un &lt;a href=&#034;http://fr.wikipedia.org/wiki/Diviseur_de_tension&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;diviseur de tension&lt;/a&gt;, et donc l'entr&#233;e analogique est &#224; 2,5V. Evidemment, on ne peut pas presser 2 poussoirs en m&#234;me temps, l'Arduino ne verra que le poussoir de rang le plus bas.&lt;/p&gt;
&lt;p&gt;On peut continuer &#224; ajouter des poussoirs en parall&#232;le avec la r&#233;sistance ad&#233;quate pour que le diviseur de tension donne une tension pr&#233;cise pour chaque poussoir. Pour nos 8 boutons-poussoir, nous allons proc&#233;der de cette mani&#232;re.&lt;/p&gt;
&lt;div class='spip_document_261 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;50&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH401/8_poussoirs-e055b.png?1692301737' width='500' height='401' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-261 '&gt;&lt;strong&gt;Connexion de 8 poussoirs &#224; une entr&#233;e analogique
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Avec 8 poussoirs, il faut diviser les 1024 valeurs possibles en 8 intervalles de 1024 &#247; 8 = 128 valeurs. Plus on ajoute des poussoirs et plus cet intervalle devient petit. Plus cet intervalle devient petit et plus il est n&#233;cessaire d'avoir des r&#233;sistances pr&#233;cises. Or, les r&#233;sistances standards ont des valeurs d&#233;termin&#233;es et sont pr&#233;cises &#224; 5%. Si les intervalles sont trop petits, il devient impossible de distinguer deux valeurs voisines de fa&#231;on fiable. Cela limite le nombre de poussoirs que l'on peut connecter mais 8 poussoirs ne devraient pas poser de probl&#232;me.&lt;/p&gt;
&lt;div class='spip_document_264 spip_document spip_documents spip_document_image spip_documents_center spip_document_center'&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L420xH387/decoupage_plage-2-ba260.png?1692301737' width='420' height='387' alt='' /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Sur la figure pr&#233;c&#233;dente, la plage de valeurs analogiques a &#233;t&#233; d&#233;coup&#233;e en 8 intervalles. En (a) le poussoir press&#233;, en (b) la tension correspondante, en (c) la valeur num&#233;rique, en (d) cette m&#234;me valeur num&#233;rique en binaire. Il faut donc d&#233;terminer les r&#233;sistances R1 &#224; R7 de mani&#232;re &#224; obtenir plus ou moins la tension voulue. On va voir que &#231;a se fait assez bien.&lt;/p&gt;
&lt;p&gt;Une fois une valeur analogique num&#233;ris&#233;e, il faut d&#233;terminer par programme de quel poussoir il s'agit. On peut le faire par une succession de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;if ... else ...&lt;/code&gt; en testant la valeur lue par rapport au milieu des intervalles : entre 0 et 63, aucun poussoir n'est press&#233;, entre 63 et 191, B0 est press&#233;, entre 192 et 319, B1 est press&#233;, etc. Mais c'est un peu long. On peut &#233;crire cela de mani&#232;re plus concise, un programmeur est un fain&#233;ant, moins il &#233;crit de code, mieux il se porte.&lt;/p&gt;
&lt;p&gt;Pour cela, nous allons diviser la valeur lue par la taille de l'intervalle (128).&lt;br class='autobr' /&gt;
Il s'agit &#233;videmment d'une division enti&#232;re, le r&#233;sultat donnerait le num&#233;ro du poussoir press&#233;, il s'agit des 3 bits de poids fort dans la colonne (d), ceux qui sont s&#233;par&#233;s des autres. Malheureusement, on peut voir que ce r&#233;sultat change au voisinage de la valeur lue. Par exemple au voisinage de 127, le r&#233;sultat peut &#234;tre 0 ou 1 et au voisinage de 255, le r&#233;sultat peut &#234;tre 1 ou 2. Par cons&#233;quent on peut confondre les deux poussoirs !&lt;/p&gt;
&lt;p&gt;Pour malgr&#233; tout proc&#233;der de cette mani&#232;re, il suffit de d&#233;caler l'intervalle. En ajoutant la moiti&#233; de la taille de l'intervalle &#224; la valeur lue, 64 donc, le r&#233;sultat donn&#233; pas la division enti&#232;re est directement le num&#233;ro du poussoir (de 0 &#224; 7), ou bien 8 si aucun poussoir n'est press&#233;, et ce num&#233;ro est stable et centr&#233; au voisinage des valeurs lues, comme montr&#233; &#224; la colonne (d). La d&#233;termination du poussoir press&#233; se fait alors en une ligne de code.&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Cette concision ne peut que r&#233;jouir le programmeur ^_^&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Immunit&#233; au bruit et d&#233;termination des r&#233;sistances&lt;/h2&gt;
&lt;p&gt;Les essais avec un seul poussoir ont employ&#233; une r&#233;sistance de 10k&#937; travers&#233;e par une courant de 0,5mA quand le poussoir est press&#233;. Avec de longs fils entre les poussoirs et l'Arduino, le bruit &#233;lectrique d&#251; aux ondes &#233;lectromagn&#233;tiques qui nous environnent peut &#234;tre important. Il est pr&#233;f&#233;rable d'utiliser des r&#233;sistances de plus faible valeur afin que le courant circulant dans le circuit quand un poussoir est press&#233; soit plus &#233;lev&#233; et que le bruit puisse &#234;tre absorb&#233; par l'alimentation. Nous allons donc choisir un courant maximum d'environ 15mA, soit une r&#233;sistance de 330&#937; &#224; la place de la r&#233;sistance de 10k&#937; utilis&#233;e jusqu'&#224; pr&#233;sent.&lt;/p&gt;
&lt;p&gt;Il faut maintenant d&#233;terminer les valeurs des r&#233;sistances R1 &#224; R7 pour obtenir les tensions que nous avons d&#233;termin&#233;es. Les diviseurs de tension pour chacun des poussoirs sont les suivants.&lt;/p&gt;
&lt;div class='spip_document_263 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;53&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L341xH417/diviseurs-2-d22db.png?1692301737' width='341' height='417' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-263 '&gt;&lt;strong&gt;Les diviseurs de tension pour chacun des poussoirs.
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Par calcul on d&#233;termine les valeurs des r&#233;sistances pour chaque poussoir. La colonne &lt;i&gt;R&#233;sistance&lt;/i&gt; donne la r&#233;sistance qui serait n&#233;cessaire, la colonne &lt;i&gt;R&#233;sistance approch&#233;e&lt;/i&gt; donne la valeur standard employ&#233;e et la colonne &lt;i&gt;Tension approch&#233;e&lt;/i&gt; donne la tension effectivement obtenue en supposant &#233;videmment que la r&#233;sistance est juste.&lt;/p&gt;
&lt;table class=&#034;table spip&#034;&gt;
&lt;tbody&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt; &lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tension&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;R&#233;sistance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;R&#233;sistance approch&#233;e&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Tension approch&#233;e&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Erreur&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R1&lt;/td&gt;
&lt;td&gt;0,625V&lt;/td&gt;
&lt;td&gt;47,14&#937;&lt;/td&gt;
&lt;td&gt;47&#937;&lt;/td&gt;
&lt;td&gt;0,634V&lt;/td&gt;
&lt;td&gt;0,04%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;R2&lt;/td&gt;
&lt;td&gt;1,25V&lt;/td&gt;
&lt;td&gt;62,85&#937;&lt;/td&gt;
&lt;td&gt;62&#937;&lt;/td&gt;
&lt;td&gt;1,27V&lt;/td&gt;
&lt;td&gt;0,23%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R3&lt;/td&gt;
&lt;td&gt;1,875V&lt;/td&gt;
&lt;td&gt;88&#937;&lt;/td&gt;
&lt;td&gt;82&#937;&lt;/td&gt;
&lt;td&gt;1,89V&lt;/td&gt;
&lt;td&gt;1,34%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;R4&lt;/td&gt;
&lt;td&gt;2,5V&lt;/td&gt;
&lt;td&gt;132&#937;&lt;/td&gt;
&lt;td&gt;130&#937;&lt;/td&gt;
&lt;td&gt;2,53V&lt;/td&gt;
&lt;td&gt;1,38%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R5&lt;/td&gt;
&lt;td&gt;3,125V&lt;/td&gt;
&lt;td&gt;220&#937;&lt;/td&gt;
&lt;td&gt;220&#937;&lt;/td&gt;
&lt;td&gt;3,17V&lt;/td&gt;
&lt;td&gt;1,03%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_odd odd'&gt;
&lt;td&gt;R6&lt;/td&gt;
&lt;td&gt;3,75V&lt;/td&gt;
&lt;td&gt;440&#937;&lt;/td&gt;
&lt;td&gt;430&#937;&lt;/td&gt;
&lt;td&gt;3,76V&lt;/td&gt;
&lt;td&gt;1,46%&lt;/td&gt;&lt;/tr&gt;
&lt;tr class='row_even even'&gt;
&lt;td&gt;R7&lt;/td&gt;
&lt;td&gt;4,375V&lt;/td&gt;
&lt;td&gt;1320&#937;&lt;/td&gt;
&lt;td&gt;1300&#937;&lt;/td&gt;
&lt;td&gt;4,377V&lt;/td&gt;
&lt;td&gt;1,50%&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;h2 class=&#034;spip&#034;&gt;Le retour du rebond&lt;/h2&gt;
&lt;p&gt;Il ne s'agit pas tout &#224; fait d'un rebond mais il va falloir prendre en compte ce que l'on appelle une transitoire.&lt;/p&gt;
&lt;p&gt;Quand l'un des poussoirs est press&#233;, l'entr&#233;e analogique passe de 5V &#224; la tension correspondante telle qu'elle a &#233;t&#233; r&#233;gl&#233;e par les r&#233;sistances. Mais elle ne le fait pas instantan&#233;ment. Cela prend un certain temps.&lt;/p&gt;
&lt;p&gt;Imaginons maintenant que le convertisseur analogique-num&#233;rique de l'Arduino capture la tension &lt;i&gt;alors que celle-ci est en train de descendre&lt;/i&gt;. Le r&#233;sultat va &#234;tre que le logiciel croit voir une pression sur un poussoir de rang sup&#233;rieur &#224; celui v&#233;ritablement press&#233;. De m&#234;me quand le poussoir va &#234;tre rel&#226;ch&#233;, la capture de la tension peut avoir lieu &lt;i&gt;alors qu'elle est en train de monter&lt;/i&gt; et retourner &#233;galement un num&#233;ro de poussoir de rang sup&#233;rieur. Il faut donc filtrer ces transitoires et n'accepter la valeur brute calcul&#233;e dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numPoussoir&lt;/code&gt; que sous certaines conditions.&lt;/p&gt;
&lt;p&gt;Avec un seul poussoir ce ph&#233;nom&#232;ne n'existait pas car il n'y avait pas d'autre poussoir.&lt;/p&gt;
&lt;p&gt;Pour filtrer les valeurs non voulues, nous allons mettre en &#339;uvre ce que l'on appelle un &lt;i&gt;syst&#232;me s&#233;quentiel&lt;/i&gt;. On repr&#233;sente ce genre de syst&#232;me par un graphe, appel&#233; automate. Un ovale est un &lt;i&gt;&#233;tat&lt;/i&gt;, une fl&#232;che est une &lt;i&gt;transition&lt;/i&gt; qui permet de passer d'un &#233;tat &#224; l'autre. Les textes en vert sont des &lt;i&gt;conditions&lt;/i&gt; qui permettent ou emp&#234;chent une transition et les textes en rouge des &lt;i&gt;actions&lt;/i&gt; qui sont effectu&#233;es lors d'une transition. L'ovale &#224; double bordure est l'&lt;i&gt;&#233;tat initial&lt;/i&gt;. La fl&#232;che qui vient de nulle part et qui pointe sur l'&#233;tat initial correspond aux actions d'initialisation.&lt;/p&gt;
&lt;p&gt;Voici l'automate de notre syst&#232;me.&lt;/p&gt;
&lt;div class='spip_document_326 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;414&#034; data-legende-lenx=&#034;xxxx&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH372/automate-2-76f26.png?1692301737' width='500' height='372' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-326 '&gt;&lt;strong&gt;Automate de lecture de l'&#233;tat des poussoirs
&lt;/strong&gt;&lt;/div&gt; &lt;div class='spip_doc_descriptif crayon document-descriptif-326 '&gt;Entre chaque transition, le temps n&#233;cessaire &#224; l'ex&#233;cution de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;loop()&lt;/code&gt;, s'&#233;coule.&lt;br class='autobr' /&gt;
Le passage par l'&#233;tat ENFONCE permet de laisser passer du temps entre la d&#233;tection de la pression sur un poussoir et la lecture du num&#233;ro correspondant. Ce num&#233;ro n'est pas r&#233;actualis&#233; dans l'&#233;tat PRESSE, ce qui permet de filtrer les valeurs non d&#233;sir&#233;es lors du rel&#226;chement du poussoir.
&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;&#192; partir de l'&#233;tat initial, NON_PRESSE, qui correspond &#224; aucun poussoir enfonc&#233;, on peut :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; rester dans cet &#233;tat (aucun poussoir enfonc&#233; correspond &#224; un num&#233;ro de poussoir &#233;gal &#224; 8) ;&lt;/li&gt;&lt;li&gt; passer dans l'&#233;tat ENFONCE (l'un des poussoir enfonc&#233; correspond &#224; un num&#233;ro de poussoir inf&#233;rieur &#224; 8).&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Une fois dans l'&#233;tat ENFONCE :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; soit le poussoir est rel&#226;ch&#233; imm&#233;diatement (c'est &#224; dire en quelques millisecondes, il s'agissait d'un rebond ou d'un parasite), le num&#233;ro de poussoir est &#233;gal &#224; 8 ;&lt;/li&gt;&lt;li&gt; soit il est toujours enfonc&#233;, num&#233;ro de poussoir inf&#233;rieur &#224; 8 et on confirme en passant dans l'&#233;tat PRESSE et en m&#233;morisant dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatBouton&lt;/code&gt; le num&#233;ro du poussoir enfonc&#233;.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Dans l'&#233;tat PRESSE :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; soit le poussoir est maintenu enfonc&#233; (numPoussoir &lt; 8) et on attend en restant dans l'&#233;tat PRESSE ;&lt;/li&gt;&lt;li&gt; soit le poussoir est rel&#226;ch&#233; (numPoussoir == 8) et on repasse dans l'&#233;tat NON_PRESSE en remettant &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatBouton&lt;/code&gt; &#224; -1.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Le passage de l'automate &#224; un programme C est direct. On va avoir besoin d'une variable pour stocker l'&#233;tat dans lequel se trouve l'automate ainsi que des variables employ&#233;es par l'automate. Comme il est impossible de d&#233;tecter plusieurs poussoirs enfonc&#233;s, il est inutile d'avoir une variable d'&#233;tat par poussoir. Une seule variable suffit mais elle a autant d'&#233;tats que de poussoirs plus une pour repr&#233;senter le fait qu'aucun poussoir n'est enfonc&#233;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const byte NON_PRESSE = 0; const byte ENFONCE = 1; const byte PRESSE = 2; byte etatAutomate = NON_PRESSE; int etatPoussoir = -1; /* aucun poussoir n'est press&#233; au d&#233;but */ const int pinPoussoirs = 0; int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; 8) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; 8) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == 8) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Il reste &#224; modifier &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement(...)&lt;/code&gt; pour l'adapter &#224; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lirePoussoirs()&lt;/code&gt;. En effet, en plus de l'information de pr&#233;sence d'&#233;v&#233;nement, il est n&#233;cessaire d'obtenir le num&#233;ro du poussoir qui a d&#233;clench&#233; l'&#233;v&#233;nement. Or une fonction C ne retourne qu'une seule valeur. Il faut donc trouver un moyen pour obtenir la seconde valeur, le num&#233;ro du poussoir.&lt;/p&gt;
&lt;p&gt;Nous allons employer un argument. En C les arguments sont pass&#233;s aux fonctions par valeur. C'est &#224; dire que la valeur contenue dans la variable que l'on passe &#224; la fonction est recopi&#233;e dans une variable locale de la fonction. Si la fonction change le contenu de cette variable, seule sa copie est chang&#233;e. Il faut donc employer un autre moyen pour que la fonction puisse modifier la variable qui lui est pass&#233;e. Ce moyen, ce sont les pointeurs.&lt;/p&gt;
&lt;p&gt;Une variable est plac&#233;e dans la m&#233;moire RAM du micro-contr&#244;leur. On peut voir la RAM comme un tableau de cases. Chaque case a un num&#233;ro, on dit une &lt;i&gt;adresse&lt;/i&gt;. Il est possible d'obtenir l'adresse d'une variable via l'op&#233;rateur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&amp;&lt;/code&gt;, de d&#233;finir une variable qui soit un pointeur vers un type, via la notation &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;*&lt;/code&gt; et il est possible d'&#233;crire ou de lire dans une variable par l'interm&#233;diaire de son adresse via l'op&#233;rateur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;*&lt;/code&gt;. Ainsi :&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;int *p;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;d&#233;finit un pointeur vers une variable de type int. Ce pointeur est pour l'instant non initialis&#233;, il ne pointe sur rien. Essayer d'acc&#233;der &#224; ce qu'il pointe est une erreur.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;int a; int *p = &amp;a;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;d&#233;finit un pointeur p vers une variable de type int qui pointe sur a. &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&amp;a&lt;/code&gt; retourne l'adresse de a.&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_inline language-C' dir='ltr'&gt;*p = 3;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;met la valeur 3 dans la variable a.&lt;/p&gt;
&lt;p&gt;Pour d&#233;finir la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement(...)&lt;/code&gt; qui retourne un byte et prend pour argument un pointeur vers un int, et qui modifie la variable point&#233;e, on &#233;crira.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;byte lireEvenement(int *numPoussoir) { byte evenement; int nouvelEtatPoussoir = lirePoussoirs(); if (nouvelEtatPoussoir == etatPoussoir) evenement = AUCUN_EVENEMENT; if (nouvelEtatPoussoir &gt;= 0 &amp;&amp; etatPoussoir == -1) evenement = EVENEMENT_PRESSE; if (nouvelEtatPoussoir == -1 &amp;&amp; etatPoussoir &gt;= 0) evenement = EVENEMENT_RELACHE; etatPoussoir = nouvelEtatPoussoir; *numPoussoir = etatPoussoir; return evenement; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;L'argument &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;int *numPoussoir&lt;/code&gt; d&#233;finit &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numPoussoir&lt;/code&gt; qui est un pointeur sur un int. &#192; l'avant derni&#232;re ligne de la fonction, l'&#233;tat du poussoir est &#233;crit dans la variable point&#233;e par &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numPoussoir&lt;/code&gt;, il s'agit de la ligne &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;*numPoussoir = etatPoussoir;&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Il faut donc que numPoussoir pointe sur la variable dans laquelle on d&#233;sire r&#233;cup&#233;rer le num&#233;ro de poussoir. Donc, pour appeler cette fonction, on &#233;crira.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; int numeroPoussoir; byte evenement = lireEvenement(&amp;numeroPoussoir);&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;ce qui a pour effet de passer &#224; la fonction l'adresse, op&#233;rateur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;&amp;&lt;/code&gt;, de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;numeroPoussoir&lt;/code&gt; afin d'obtenir la valeur d&#233;sir&#233;e dans cette variable.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Essai du syst&#232;me&lt;/h2&gt;
&lt;p&gt;La premi&#232;re &#233;tape consiste &#224; c&#226;bler sur la &lt;i&gt;breadboard&lt;/i&gt; les poussoirs est les r&#233;sistances comme ceci.&lt;/p&gt;
&lt;div class='spip_document_267 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;44&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH535/8_poussoirs_bb-2-28461.png?1692301737' width='500' height='535' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-267 '&gt;&lt;strong&gt;Placement des composants sur le breadboard
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Voici le programme complet de test du syst&#232;me. Les messages d'appui ou de rel&#226;chement des poussoirs sont affich&#233;s sur le moniteur s&#233;rie avec le num&#233;ro de poussoir enfonc&#233;.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt; const byte NON_PRESSE = 0; const byte ENFONCE = 1; const byte PRESSE = 2; byte etatAutomate = NON_PRESSE; int etatPoussoir = -1; const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2; const int pinPoussoirs = 0; int lirePoussoirs() { int resultat; int numPoussoir = (analogRead(pinPoussoirs) + 64) / 128; int nouvelEtatPoussoir = etatPoussoir; /* &#224; priori rien ne change */ switch (etatAutomate) { case NON_PRESSE: if (numPoussoir &lt; 8) etatAutomate = ENFONCE; break; case ENFONCE: if (numPoussoir &lt; 8) { etatAutomate = PRESSE; nouvelEtatPoussoir = numPoussoir; } else { etatAutomate = NON_PRESSE; } break; case PRESSE: if (numPoussoir == 8) { etatAutomate = NON_PRESSE; nouvelEtatPoussoir = -1; } break; } return nouvelEtatPoussoir; } /* * construction d'un &#233;v&#233;nement en comparant * le nouvel &#233;tat des poussoirs avec l'&#233;tat pr&#233;c&#233;dent. */ byte lireEvenement(int *numPoussoir) { byte evenement; int nouvelEtatPoussoir = lirePoussoirs(); if (nouvelEtatPoussoir == etatPoussoir) evenement = AUCUN_EVENEMENT; if (nouvelEtatPoussoir &gt;= 0 &amp;&amp; etatPoussoir == -1) evenement = EVENEMENT_PRESSE; if (nouvelEtatPoussoir == -1 &amp;&amp; etatPoussoir &gt;= 0) evenement = EVENEMENT_RELACHE; if (evenement == EVENEMENT_PRESSE) { *numPoussoir = nouvelEtatPoussoir; } else if (evenement == EVENEMENT_RELACHE) { *numPoussoir = etatPoussoir; } etatPoussoir = nouvelEtatPoussoir; return evenement; } void setup() { Serial.begin(9600); } void loop() { int numPoussoir; byte evenement = lireEvenement(&amp;numPoussoir); switch (evenement) { case EVENEMENT_PRESSE: Serial.print(&#034;Presse : &#034;); Serial.println(numPoussoir); break; case EVENEMENT_RELACHE: Serial.print(&#034;Relache : &#034;); Serial.println(numPoussoir); break; } delay(3); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Une petite vid&#233;o montrant la mise en &#339;uvre du programme.&lt;/p&gt;
&lt;div class=&#034;spip_document_268 spip_document spip_documents spip_document_video&#034;&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-268&#034; data-id=&#034;9d2ceb7dd5caaba544f271e115ddf616&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/qNStYgPLN6E?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1779463451' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#034;base64javascript1261662166a32439dede845.57267109&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzc5NDQzNTM4JyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3Nzk0NDM1MzgnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Le syst&#232;me de commande &#224; 8 boutons sur une entr&#233;e analogique est op&#233;rationnel.&lt;/p&gt;
&lt;p&gt;Nous avons vu quelques &#233;l&#233;ments suppl&#233;mentaires de langage C comme les pointeurs et leur emploi pour retourner plusieurs valeurs &#224; partir d'une fonction. Nous avons vu rapidement les automates et comment les mettre en &#339;uvre avec un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch ... case&lt;/code&gt;. La prochaine fois nous ajouterons nos 8 servo-moteurs.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<item xml:lang="fr">
		<title>Commande du servo-moteur par bouton poussoir</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article58</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article58</guid>
		<dc:date>2013-11-11T17:57:57Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>aiguille</dc:subject>
		<dc:subject>servo</dc:subject>
		<dc:subject>Arduino</dc:subject>

		<description>
&lt;p&gt;Nous allons maintenant ajouter un bouton poussoir pour commander le mouvement du servo-moteur. Cet article fait suite &#224; &#171; Mise en &#339;uvre d'un servo-moteur &#187;. &lt;br class='autobr' /&gt;
Le syst&#232;me fonctionnera de la mani&#232;re suivante : Lorsque le servo-moteur est dans une des positions extr&#234;mes, une pression sur le poussoir donnera au servo-moteur une vitesse lui permettant de gagner l'autre position extr&#234;me. Lorsque le servo-moteur est en mouvement, une pression sur le bouton inversera la vitesse. &lt;br class='autobr' /&gt;
Mise en &#339;uvre du (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique22" rel="directory"&gt;Man&#339;uvre des aiguilles avec des servo-moteurs&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot4" rel="tag"&gt;aiguille&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot5" rel="tag"&gt;servo&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Nous allons maintenant ajouter un bouton poussoir pour commander le mouvement du servo-moteur. Cet article fait suite &#224; &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article57' class=&#034;spip_in&#034;&gt;Mise en &#339;uvre d'un servo-moteur&lt;/a&gt; &#187;.&lt;/p&gt;
&lt;p&gt;Le syst&#232;me fonctionnera de la mani&#232;re suivante : Lorsque le servo-moteur est dans une des positions extr&#234;mes, une pression sur le poussoir donnera au servo-moteur une vitesse lui permettant de gagner l'autre position extr&#234;me. Lorsque le servo-moteur est en mouvement, une pression sur le bouton inversera la vitesse.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Mise en &#339;uvre du bouton poussoir&lt;/h2&gt;
&lt;p&gt;Comme d&#233;j&#224; expliqu&#233;, nous allons r&#233;server les entr&#233;es/sorties num&#233;riques, les broches 0 &#224; 13 de l'Arduino, au pilotage des servo-moteurs et &#224; l'allumage des LED t&#233;moin.&lt;/p&gt;
&lt;p&gt;Pour l'instant, l'unique bouton poussoir est connect&#233; sur une entr&#233;e analogique, A0 par exemple. Une entr&#233;e analogique permet &#224; l'Arduino de lire une grandeur analogique, entre 0V et 5V, et de la convertir en un nombre que l'on pourra manipuler dans le programme. Le nombre obtenu peut prendre des valeurs comprises entre 0 (pour 0V) et 1023 (pour 5V) avec donc 1024 valeurs possibles.&lt;/p&gt;
&lt;p&gt;Pour notre bouton, il n'y aura que deux valeurs, celle qui correspond au bouton rel&#226;ch&#233; et celle qui correspond au bouton enfonc&#233;. Le bouton est connect&#233; &#224; l'Arduino comme ceci.&lt;/p&gt;
&lt;div class='spip_document_248 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;46&#034; data-legende-lenx=&#034;x&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L490xH558/poussoir-24990.png?1692208044' width='490' height='558' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-248 '&gt;&lt;strong&gt;Connexion du bouton poussoir &#224; l'Arduino Uno
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Lorsque le bouton est rel&#226;ch&#233;, l'entr&#233;e analogique A0 est tir&#233;e &#224; 0V via la r&#233;sistance de 10k&#937;. Lorsque le bouton est press&#233;, l'entr&#233;e est mise &#224; 5V.&lt;/p&gt;
&lt;p&gt;Du c&#244;t&#233; du programme, nous allons s&#233;parer l'espace de valeurs (0 &#224; 1023) en deux parties &#233;gales : les valeurs inf&#233;rieures ou &#233;gales &#224; 511 et celles sup&#233;rieures &#224; 511 et nous allons d&#233;finir une fonction qui lit la valeur analogique, la compare &#224; la valeur milieu et retourne soit &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt;, soit &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt;. Ces deux constantes sont des bool&#233;ens, c'est &#224; dire des valeurs logiques. Elle sont d&#233;finies pour faciliter la lecture du programme. Jusqu'alors nous n'avons vu que des fonctions qui ne retournaient rien, c'est &#224; dire &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;void&lt;/code&gt;. Ici la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireBouton&lt;/code&gt; retourne un bool&#233;en, qui sera l'&#233;tat du bouton. Nous avons donc le morceau de programme suivant avec la d&#233;finition des constantes n&#233;cessaires et la fonction de lecture de l'&#233;tat du bouton poussoir.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;/* le bouton est connect&#233; &#224; la broche A0 */ const int pinBouton = 0; /* valeur logique pour indiquer que le bouton est press&#233; */ const boolean PRESSE = true; /* valeur logique pour indiquer que le bouton est rel&#226;ch&#233; */ const boolean RELACHE = false; /* * lecture du bouton poussoir. Le bouton poussoir est connect&#233; * sur une entr&#233;e analogique. Quand il est press&#233;, l'entr&#233;e est * connect&#233;e au +5V. Quand il est relach&#233;, l'entr&#233;e est connect&#233;e * &#224; la masse. On va discriminer les deux &#233;tats en comparant la * valeur analogique lue &#224; 511 qui est la valeur milieu. */ boolean lirePoussoir() { boolean resultat = RELACHE; if (analogRead(pinBouton) &gt; 511) { resultat = PRESSE; } /* retourne l'&#233;tat */ return resultat; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mais l'&#233;tat du bouton ne nous int&#233;resse pas directement. En effet, ne mettre le servo-moteur en mouvement que lorsque le bouton est press&#233; forcerait l'utilisateur &#224; maintenir le bouton press&#233; pendant le mouvement. Ce sont donc les changements d'&#233;tat du bouton qui nous int&#233;ressent : le fait de passer de l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt; &#224; l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt; ou le fait de passer de l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt; &#224; l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt;. Pour d&#233;tecter ces changements d'&#233;tat, il faut m&#233;moriser l'&#233;tat pr&#233;c&#233;dent du bouton et, quand on lit son &#233;tat actuel, le compar&#233; &#224; l'&#233;tat pr&#233;c&#233;dent pour d&#233;terminer si l'un des changements a eu lieu. On a donc besoin d'une variable pour y m&#233;moriser l'&#233;tat pr&#233;c&#233;dent. Pour clarifier les choses et rendre le programme lisible, nous allons aussi d&#233;finir 3 constantes : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;AUCUN_EVENEMENT&lt;/code&gt;, l'&#233;tat pr&#233;c&#233;dent du bouton est identique &#224; l'&#233;tat courant, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EVENEMENT_PRESSE&lt;/code&gt;, l'&#233;tat pr&#233;c&#233;dent du bouton &#233;tait &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt;, l'&#233;tat courant est &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EVENEMENT_RELACHE&lt;/code&gt;, l'&#233;tat pr&#233;c&#233;dent du bouton &#233;tait &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;PRESSE&lt;/code&gt;, l'&#233;tat courant est &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;RELACHE&lt;/code&gt;. Ces constantes sont des &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;byte&lt;/code&gt;, c'est &#224; dire un type de donn&#233;e pouvant prendre 256 valeurs diff&#233;rentes, ce qui suffit amplement.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin nous allons d&#233;finir la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;lireEvenement()&lt;/code&gt; qui va lire l'&#233;tat courant du bouton et calculer l'&#233;v&#233;nement. Le code vient assez naturellement.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;/* * construction d'un &#233;v&#233;nement. * - Si l'&#233;tat du bouton n'a pas chang&#233; entre l'&#233;tat pr&#233;c&#233;dent du bouton * et le nouvelle &#233;tat, l'&#233;v&#233;nement est AUCUN_EVENEMENT. * - Si le pouton &#233;tait pr&#233;c&#233;demment RELACHE et qu'il est maintenant PRESSE, * l'&#233;v&#233;nement est EVENEMENT_PRESSE. * - Si le pouton &#233;tait pr&#233;c&#233;demment PRESSE et qu'il est maintenant RELACHE, * l'&#233;v&#233;nement est EVENEMENT_RELACHE. */ byte lireEvenement() { byte evenement; /* lit l'&#233;tat courant du bouton */ boolean nouvelEtat = lirePoussoir(); /* calcule l'&#233;v&#233;nement */ if (nouvelEtat == etatBouton) evenement = AUCUN_EVENEMENT; if (nouvelEtat == PRESSE &amp;&amp; etatBouton == RELACHE) evenement = EVENEMENT_PRESSE; if (nouvelEtat == RELACHE &amp;&amp; etatBouton == PRESSE) evenement = EVENEMENT_RELACHE; /* L'&#233;tat courant devient l'&#233;tat pr&#233;c&#233;dent */ etatBouton = nouvelEtat; /* retourne l'&#233;v&#233;nement */ return evenement; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Afin de tester la lecture du poussoir ind&#233;pendamment, nous allons mettre en &#339;uvre l'envoi de message sur la ligne s&#233;rie qui, via l'USB, s'affiche dans le Moniteur S&#233;rie de l'environnement de programmation Arduino. Il faut tout d'abord ouvrir la connexion dans la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt; en utilisant la m&#233;thode &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;begin(...)&lt;/code&gt; de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;Serial&lt;/code&gt;. Nous allons ensuite utiliser la m&#233;thode &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;println&lt;/code&gt; pour afficher un message sur le moniteur s&#233;rie. Voici le programme complet pour cette premi&#232;re application mettant en &#339;uvre un bouton.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const int pinBouton = 0; /* le bouton est connect&#233; &#224; la broche A0 */ const boolean PRESSE = true; const boolean RELACHE = false; boolean etatBouton = RELACHE; const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2; boolean lirePoussoir() { boolean resultat = RELACHE; if (analogRead(pinBouton) &gt; 512) { resultat = PRESSE; } return resultat; } byte lireEvenement() { byte evenement; boolean nouvelEtat = lirePoussoir(); if (nouvelEtat == etatBouton) evenement = AUCUN_EVENEMENT; if (nouvelEtat == PRESSE &amp;&amp; etatBouton == RELACHE) evenement = EVENEMENT_PRESSE; if (nouvelEtat == RELACHE &amp;&amp; etatBouton == PRESSE) evenement = EVENEMENT_RELACHE; etatBouton = nouvelEtat; return evenement; } void setup() { Serial.begin(9600); } void loop() { byte evenement = lireEvenement(); if (evenement == EVENEMENT_PRESSE) Serial.println(&#034;presse !&#034;); if (evenement == EVENEMENT_RELACHE) Serial.println(&#034;relache !&#034;); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&#192; ma grande surprise ce programme fonctionne sans effort suppl&#233;mentaire ! &#192; ma grande surprise car lorsque l'on presse ou que l'on rel&#226;che un bouton, le contact ou la coupure ne s'effectue pas d'un coup et une succession rapide de contact-coupure a lieu. On appelle cela un rebond. Mon poussoir n'a pas de caract&#233;ristique particuli&#232;re et j'ai par ailleurs eu des rebonds en le connectant &#224; une entr&#233;e num&#233;rique. La r&#233;ponse &#224; ce myst&#232;re est donc ailleurs.&lt;/p&gt;
&lt;p&gt;Deux techniques sont possibles pour filtrer les rebonds des poussoirs :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; par mat&#233;riel : un condensateur de filtrage ;&lt;/li&gt;&lt;li&gt; par logiciel : laisser passer du temps entre deux lectures.&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Or, la conversion analogique num&#233;rique n'est pas instantan&#233;e. Entre deux conversions successives et donc deux acquisitions successive de la valeur analogique, il s'&#233;coule 100&#181;s. Ce qui &#233;quivaut &#224; la solution logicielle de &#171; laisser passer du temps entre 2 lectures &#187;. Cette dur&#233;e semble &#234;tre suffisante pour filtrer les rebonds de notre bouton.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Int&#233;gration avec le programme de pilotage du servo-moteur&lt;/h2&gt;
&lt;p&gt;Nous allons maintenant int&#233;grer notre fonction de lecture d'&#233;v&#233;nement au programme de pilotage du servo-moteur tel que nous l'avons pr&#233;sent&#233; dans l'&lt;a href='https://modelleisenbahn.triskell.org/spip.php?article57' class=&#034;spip_in&#034;&gt;article pr&#233;c&#233;dent&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Il faut proc&#233;der &#224; quelques modification. Tout d'abord, il faut supprimer l'aller-retour qu'effectue le servo-moteur. Ensuite, il faut ajouter une variable qui va permettre de savoir dans quel &#233;tat se trouve le servo-moteur afin de prendre la d&#233;cision ad&#233;quate quand le bouton est press&#233;. On va distinguer 4 &#233;tats :&lt;/p&gt;
&lt;p&gt;&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MIN&lt;/code&gt; : le servo-moteur est arr&#234;t&#233; dans la position correspondant &#224; l'angle minimum. Sa vitesse est &#233;gale &#224; 0.&lt;br/&gt;
&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MAX&lt;/code&gt; : le servo-moteur est arr&#234;t&#233; dans la position correspondant &#224; l'angle maximum. Sa vitesse est &#233;gale &#224; 0.&lt;br/&gt;
&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX&lt;/code&gt; : le servo est en mouvement vers la position d'angle maximum. Sa vitesse est &#233;gale &#224; 1.&lt;br/&gt;
&lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN&lt;/code&gt; : le servo est en mouvement vers la position d'angle minimum. Sa vitesse est &#233;gale &#224; -1.&lt;/p&gt;
&lt;p&gt;Comme tout est nombre, nous allons d&#233;finir chacune de ces constantes comme &#233;tant un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;byte&lt;/code&gt; et d&#233;finir une variable &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatServo&lt;/code&gt; de type &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;byte&lt;/code&gt; comme ceci.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;const byte SERVO_A_ANGLE_MIN = 0; const byte SERVO_A_ANGLE_MAX = 1; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3; const int angleMin = 1250; const int angleMax = 1750; Servo monServo; int vitesse = 0; int angle = angleMin; byte etatServo = SERVO_A_ANGLE_MIN;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&lt;/code&gt;, nous retrouvons l'accrochage de &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;monServo&lt;/code&gt; &#224; la broche 2. La gestion du mouvement du servo est modifi&#233;e. Quand l'angle d&#233;passe l'angle maximum, il est recal&#233; comme auparavant. Mais dor&#233;navant la vitesse est mise &#224; 0 et l'&#233;tat du servo est chang&#233; en &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MAX&lt;/code&gt;. Quand l'angle d&#233;passe l'angle minimum, il est recal&#233; &#224; l'angle minimum, la vitesse est mise &#224; 0 et l'&#233;tat du servo est chang&#233; en &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MIN&lt;/code&gt;. De cette mani&#232;re, le servo arr&#234;te son mouvement quand il atteint l'une des positions extr&#234;mes.&lt;/p&gt;
&lt;p&gt;On va ensuite lire l'&#233;v&#233;nement. Si l'&#233;v&#233;nement est &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;EVENEMENT_PRESSE&lt;/code&gt;, on va effectuer les actions suivantes :&lt;/p&gt;
&lt;ul class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; Si le servo est dans l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MIN&lt;/code&gt; ou&lt;br/&gt; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN&lt;/code&gt;, la vitesse est mise &#224; 1 et l'&#233;tat du servo est chang&#233; en &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX&lt;/code&gt;.&lt;/li&gt;&lt;li&gt; Si le servo est dans l'&#233;tat &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MAX&lt;/code&gt; ou&lt;br/&gt; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX&lt;/code&gt;, la vitesse est mise &#224; -1 et et l'&#233;tat du servo est chang&#233; en &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;Le programme complet est le suivant.&lt;/p&gt;
&lt;div class=&#034;precode&#034;&gt;&lt;pre data-raccourci=&#034;code&#034; data-language=&#034;C&#034; class='spip_code spip_code_block language-C' dir='ltr' style='text-align:left;'&gt;&lt;code&gt;#include &lt;Servo.h&gt; const byte SERVO_A_ANGLE_MIN = 0; const byte SERVO_A_ANGLE_MAX = 1; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX = 2; const byte SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN = 3; const int angleMin = 1250; const int angleMax = 1750; Servo monServo; int vitesse = 0; int angle = angleMin; byte etatServo = SERVO_A_ANGLE_MIN; const int pinBouton = 0; /* le bouton est connect&#233; &#224; la broche A0 */ const boolean PRESSE = true; const boolean RELACHE = false; boolean etatBouton = RELACHE; const byte AUCUN_EVENEMENT = 0; const byte EVENEMENT_PRESSE = 1; const byte EVENEMENT_RELACHE = 2; /* * fonctions de gestion du poussoir */ boolean lirePoussoir() { boolean resultat = RELACHE; if (analogRead(pinBouton) &gt; 512) { resultat = PRESSE; } return resultat; } byte lireEvenement() { byte evenement; boolean nouvelEtat = lirePoussoir(); if (nouvelEtat == etatBouton) evenement = AUCUN_EVENEMENT; if (nouvelEtat == PRESSE &amp;&amp; etatBouton == RELACHE) evenement = EVENEMENT_PRESSE; if (nouvelEtat == RELACHE &amp;&amp; etatBouton == PRESSE) evenement = EVENEMENT_RELACHE; etatBouton = nouvelEtat; return evenement; } /* * La fonction setup() est ex&#233;cut&#233;e 1 fois * au d&#233;marrage du programme */ void setup() { monServo.attach(2); } /* * La fonction loop() est ex&#233;cut&#233;e * r&#233;p&#233;titivement */ void loop() { /* actualisation de l'angle du servo */ monServo.writeMicroseconds(angle); angle = angle + vitesse; if (angle &gt; angleMax) { angle = angleMax; vitesse = 0; etatServo = SERVO_A_ANGLE_MAX; } else if (angle &lt; angleMin) { angle = angleMin; vitesse = 0; etatServo = SERVO_A_ANGLE_MIN; } /* lecture de la commande de l'utilisateur */ byte evenement = lireEvenement(); if (evenement == EVENEMENT_PRESSE) { switch (etatServo) { case SERVO_A_ANGLE_MIN: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN: vitesse = 1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX; break; case SERVO_A_ANGLE_MAX: case SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX: vitesse = -1; etatServo = SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN; break; } } delay(3); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Ce programme est l'occasion d'introduire une nouvelle construction du C, le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch ... case&lt;/code&gt;. Il s'agit d'un choix multiple. On a vu avec le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;if ... else ...&lt;/code&gt; un choix double. Ici la valeur de la variable &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;etatServo&lt;/code&gt; indique &#224; quel &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;case&lt;/code&gt; le programme continue son ex&#233;cution. L'ex&#233;cution se poursuit jusqu'&#224; rencontrer un &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;break&lt;/code&gt; qui fait que le programme continue sont ex&#233;cution apr&#232;s le &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;switch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Distinguer les &#233;tats &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MIN&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MIN&lt;/code&gt; n'est pas n&#233;cessaire, idem pour &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_A_ANGLE_MAX&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;SERVO_EN_MOUVEMENT_VERS_ANGLE_MAX&lt;/code&gt;. On le conserve tout de m&#234;me car le programme est plus lisible ainsi et la distinction qui est faite va nous servir plus tard.&lt;/p&gt;
&lt;p&gt;Une petite vid&#233;o du montage volant et de l'ex&#233;cution de ce dernier programme.&lt;/p&gt;
&lt;div class=&#034;spip_document_249 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;28&#034; data-legende-lenx=&#034;&#034;
&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt;
&lt;div class=&#034;video-intrinsic-wrapper&#034; style='height:0;width:640px;max-width:100%;padding-bottom:56.25%;position:relative;'&gt; &lt;div class=&#034;video-wrapper&#034; style=&#034;position: absolute;top:0;left:0;width:100%;height:100%;&#034;&gt; &lt;video class=&#034;mejs mejs-249&#034; data-id=&#034;55c926c5efee272582eef1bab2bd2f64&#034; data-mejsoptions='{&#034;iconSprite&#034;: &#034;plugins-dist/medias/lib/mejs/mejs-controls.svg&#034;,&#034;alwaysShowControls&#034;: true,&#034;pluginPath&#034;:&#034;plugins-dist/medias/lib/mejs/&#034;,&#034;loop&#034;:false,&#034;videoWidth&#034;:&#034;100%&#034;,&#034;videoHeight&#034;:&#034;100%&#034;}' width=&#034;100%&#034; height=&#034;100%&#034; controls=&#034;controls&#034; preload=&#034;none&#034; &gt; &lt;source type=&#034;application/x-shockwave-flash&#034; src=&#034;http://www.youtube.com/v/Pvx3_xM7B8E?hl=fr_FR&amp;version=3&amp;rel=0&#034; /&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/swf-d2c4d-75a7b.svg?1779463451' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-249 '&gt;&lt;strong&gt;D&#233;monstration du programme
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript1261662166a32439dede845.57267109&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzc5NDQzNTM4JyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3Nzk0NDM1MzgnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>



</channel>

</rss>
