<?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_mot=10&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>L'algorithme de rotation du pont tournant</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article74</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article74</guid>
		<dc:date>2014-01-01T12:12:33Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>Moteur pas-&#224;-pas</dc:subject>
		<dc:subject>Arduino</dc:subject>
		<dc:subject>Pont tournant</dc:subject>

		<description>
&lt;p&gt;Apr&#232;s avoir pr&#233;sent&#233; le mat&#233;riel n&#233;cessaire au pilotage du moteur pas-&#224;-pas par &#181;Pas et le choix de la DRV8824 de Pololu pour sa meilleure r&#233;solution et la fluidit&#233; de mouvement qui en r&#233;sulte, il est temps de se pencher sur l'algorithme qui permet de d&#233;cider du sens de rotation et de la d&#233;composition du mouvement en phase d'acc&#233;l&#233;ration, en r&#233;gime permanent et en phase de d&#233;c&#233;l&#233;ration. &lt;br class='autobr' /&gt;
Calcul du sens de rotation pour le plus court chemin &lt;br class='autobr' /&gt;
Le pont est bien &#233;videmment orient&#233;. C'est &#224; dire (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique19" rel="directory"&gt;La technologie&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot7" rel="tag"&gt;Moteur pas-&#224;-pas&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot11" rel="tag"&gt;Pont tournant&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Apr&#232;s avoir pr&#233;sent&#233; le mat&#233;riel n&#233;cessaire au pilotage du moteur pas-&#224;-pas par &#181;Pas et le choix de la &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article72' class=&#034;spip_in&#034;&gt;DRV8824 de Pololu&lt;/a&gt; pour sa meilleure r&#233;solution et la fluidit&#233; de mouvement qui en r&#233;sulte, il est temps de se pencher sur l'algorithme qui permet de d&#233;cider du sens de rotation et de la d&#233;composition du mouvement en phase d'acc&#233;l&#233;ration, en r&#233;gime permanent et en phase de d&#233;c&#233;l&#233;ration.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Calcul du sens de rotation pour le plus court chemin&lt;/h2&gt;
&lt;p&gt;Le pont est bien &#233;videmment orient&#233;. C'est &#224; dire que les positions &lt;i&gt;p&lt;/i&gt; et &lt;i&gt;p&lt;/i&gt;+180&#176; sont diff&#233;rentes. Avec la DRV8824, nous avons 12800 positions possibles que nous allons num&#233;roter de 0 &#224; 12799. Partant de la position courante, le pont devant aller dans une nouvelle position, il faut d&#233;cider dans quel sens tourner pour minimiser la distance parcourue. C'est &#224; dire que partant de la position courante 12799 et allant &#224; la position 0, il n'y a qu'un &#181;Pas &#224; effectuer et non 12799.&lt;/p&gt;
&lt;p&gt;On va distinguer deux cas :&lt;/p&gt;
&lt;ol class=&#034;spip&#034; role=&#034;list&#034;&gt;&lt;li&gt; La position &#224; atteindre &#224; un num&#233;ro &gt; &#224; la position courante ;&lt;/li&gt;&lt;li&gt; La position &#224; atteindre &#224; un num&#233;ro &lt; &#224; la position courante.&lt;/li&gt;&lt;/ol&gt;
&lt;p&gt;Par convention, on va &#233;galement d&#233;cider qu'un d&#233;placement positif se fait dans le sens horaire et un d&#233;placement n&#233;gatif dans le sens trigonom&#233;trique.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La position &#224; atteindre &#224; un num&#233;ro &lt;i&gt;sup&#233;rieur&lt;/i&gt; &#224; la position courante&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ce cas correspond &#224; la figure ci-dessous :&lt;/p&gt;
&lt;div class='spip_document_375 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/L469xH404/cheminsA-3-d7fd9.png?1692224381' width='469' height='404' alt='' /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;&lt;i&gt;chemin 1&lt;/i&gt; se calcule en soustrayant la position courante &#224; la position destination : &lt;i&gt;chemin 1&lt;/i&gt; = &lt;i&gt;position destination&lt;/i&gt; &#8212; &lt;i&gt;positition courante&lt;/i&gt;.&lt;br class='autobr' /&gt;
Il est bien positif, la rotation pour parcourir &lt;i&gt;chemin 1&lt;/i&gt; se fait dans le sens horaire.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;chemin 2&lt;/i&gt; doit &#234;tre n&#233;gatif puisque la rotation de fait dans le sens trigonom&#233;trique et il se d&#233;compose en deux : d'une part la portion entre la position courante et 0 et d'autre part la portion entre 12800 et la position destination.&lt;br/&gt;On a donc &lt;i&gt;chemin 2&lt;/i&gt; = &#8212; (&lt;i&gt;positition courante&lt;/i&gt; + 12800 &#8212; &lt;i&gt;position destination&lt;/i&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;La position &#224; atteindre &#224; un num&#233;ro &lt;i&gt;inf&#233;rieur&lt;/i&gt; &#224; la position courante&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Ce cas correspond &#224; la figure ci-dessous :&lt;/p&gt;
&lt;div class='spip_document_376 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/L433xH433/cheminsB-ea85d.png?1692224381' width='433' height='433' alt='' /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;&lt;i&gt;chemin 1&lt;/i&gt; se calcule &#233;galement en soustrayant la position courante &#224; la position destination : &lt;i&gt;chemin 1&lt;/i&gt; = &lt;i&gt;position destination&lt;/i&gt; &#8212; &lt;i&gt;positition courante&lt;/i&gt;.&lt;br class='autobr' /&gt;
Comme la position courante est plus grande que la position destination, il est bien n&#233;gatif, la rotation pour parcourir &lt;i&gt;chemin 1&lt;/i&gt; se fait dans le sens trigonom&#233;trique.&lt;/p&gt;
&lt;p&gt;&lt;i&gt;chemin 2&lt;/i&gt; doit &#234;tre positif et se d&#233;compose en deux : d'une part la portion entre la position courante et 12800 et d'autre part la portion entre 0 et la position destination.&lt;br/&gt;On a donc &lt;i&gt;chemin 2&lt;/i&gt; = 12800 &#8212; &lt;i&gt;positition courante&lt;/i&gt; + &lt;i&gt;position destination&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Pour choisir le chemin, il suffit de comparer les valeurs absolues de &lt;i&gt;chemin 1&lt;/i&gt; et &lt;i&gt;chemin 2&lt;/i&gt; et de choisir le chemin ayant la plus petite. Le signe du chemin donne le sens de rotation.&lt;/p&gt;
&lt;p&gt;Le code correspondant 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;int chemin1 = positionDestination - positionCourante; int chemin2; if (positionDestination &gt; positionCourante) chemin2 = - (positionCourante + 12800 - positionDestination); else chemin2 = 12800 - positionCourante + positionDestination; int chemin; int dir; if (abs(chemin1) &gt; abs(chemin2)) chemin = chemin2; else chemin = chemin1; /* Si chemin &lt; 0, la direction est mise &#224; 1 */ if (chemin &lt; 0) dir = HIGH; else dir = LOW;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le nombre de &#181;Pas &#224; parcourir sera mis dans une variable &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;distance&lt;/code&gt; calcul&#233;e comme suit : &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;distance = abs(chemin);&lt;/code&gt;.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Vitesse de rotation, acc&#233;l&#233;ration et d&#233;c&#233;l&#233;ration&lt;/h2&gt;
&lt;p&gt;La vitesse de rotation d'un pont tournant est assez faible. On peut par exemple voir dans cette vid&#233;o qu'il faut environ 2 minutes (entre 45&#034; et 2'45&#034;) pour que la 141TD 740 fasse son demi-tour, ce qui donne 4 minutes pour un tour.&lt;/p&gt;
&lt;div class=&#034;spip_document_377 spip_document spip_documents spip_document_video spip_document_avec_legende&#034; data-legende-len=&#034;65&#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:75%;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-377&#034; data-id=&#034;a5e1f03175df6ffab285f4851903f38f&#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/CYeE9b1WWqw?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?1772798901' 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-377 '&gt;&lt;strong&gt;La 141TD 740 s'engage sur le pont tournant et fait un demi-tour
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;
&lt;div class=&#034;base64javascript179256860569ce35256bef59.96790775&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Dans notre cas, il faut donc passer 12800 &#181;Pas en 4 minutes soit 240s, ce qui donne un d&#233;lai de 18 &#224; 19ms entre deux &#181;Pas. Pour clarifier le code, ce d&#233;lai va &#234;tre mis dans une variable &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;delaiInterMicropas&lt;/code&gt;, ce qui permettra aussi de changer la vitesse de rotation sans avoir &#224; modifier le code.&lt;/p&gt;
&lt;p&gt;Si on ne se soucie pas d'avoir des phases d'acc&#233;l&#233;ration et de d&#233;c&#233;l&#233;ration, le code est tr&#232;s simple :&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 (microPas = 0; microPas &lt; distance; microPas++) { digitalWrite(stepPin, LOW); delay(1); digitalWrite(stepPin, HIGH); delay(delaiInterMicroPas - 1); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Mais le mouvement a une allure artificielle. Il est donc pr&#233;f&#233;rable de simuler une petite phase d'acc&#233;l&#233;ration et de d&#233;c&#233;l&#233;ration.&lt;/p&gt;
&lt;p&gt;Les phases d'acc&#233;l&#233;ration vont &#234;tre r&#233;gl&#233;es en nombre de &#181;Pas pass&#233;s &#224; acc&#233;l&#233;rer et &#224; d&#233;c&#233;l&#233;rer. On va donc avoir 2 variables &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;microPasAcceleration&lt;/code&gt; et &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;microPasDeceleration&lt;/code&gt; pour r&#233;gler ces phases.&lt;/p&gt;
&lt;p&gt;Un mouvement d'une position courante &#224; une position de destination consiste donc &#224; parcourir &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;microPasAcceleration&lt;/code&gt; &#181;Pas avec un d&#233;lai variable et d&#233;croissant puis &#224; parcourir &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;distance - microPasAcceleration - microPasDeceleration&lt;/code&gt; &#181;Pas avec un d&#233;lai &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;delaiInterMicropas&lt;/code&gt; et enfin parcourir &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;microPasDeceleration&lt;/code&gt; &#181;Pas avec un d&#233;lai variable croissant.&lt;/p&gt;
&lt;p&gt;Bien entendu, il ne faut pas que &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;microPasAcceleration + microPasDeceleration&lt;/code&gt; soit sup&#233;rieur &#224; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;distance&lt;/code&gt;. En pratique les phases d'acc&#233;l&#233;ration et de d&#233;c&#233;l&#233;ration seront courte et la distance est sup&#233;rieur &#224; l'&#233;cartement de la voie utilis&#233;e. Par exemple pour un pont en N de 150mm de diam&#232;tre, les 9mm d'&#233;cartement correspondent &#224; 245 &#181;Pas.&lt;/p&gt;
&lt;p&gt;Le d&#233;lai initial de la phase d'acc&#233;l&#233;ration est calcul&#233; est ajoutant &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;microPasAcceleration&lt;/code&gt; &#224; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;delaiInterMicropas&lt;/code&gt;. On va ensuite boucler &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;microPasAcceleration&lt;/code&gt; fois en diminuant le d&#233;lai de 1 &#224; chaque tour pour donc terminer sur un d&#233;lai &#233;gal &#224; &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;delaiInterMicropas&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;int delai = delaiInterMicroPas - 1 + microPasAcceleration; for (microPas = 0; microPas &lt; microPasAcceleration; microPas++) { digitalWrite(stepPin, LOW); delay(1); digitalWrite(stepPin, HIGH); delay(delai); delai-- ; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le mouvement a vitesse maximum est accompli par la boucle 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;for (microPas = 0; microPas &lt; (distance - microPasAcceleration - microPasDeceleration); microPas++) { digitalWrite(stepPin, LOW); delay(1); digitalWrite(stepPin, HIGH); delay(delaiInterMicroPas - 1); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Enfin, la phase de d&#233;c&#233;l&#233;ration consiste &#224; boucler &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;microPasDeceleration&lt;/code&gt; fois en augmentant le d&#233;lai de 1 &#224; chaque tour, &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;delai&lt;/code&gt; est initialis&#233; &#224; la valeur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;delaiInterMicropas&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;for (microPas = 0; microPas &lt; microPasDeceleration; microPas++) { digitalWrite(stepPin, LOW); delay(1); digitalWrite(stepPin, HIGH); delay(delai); delai ++; }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Tout cela est mis dans une fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;allerAPosition(...)&lt;/code&gt;.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Sketch de d&#233;monstration&lt;/h2&gt;
&lt;p&gt;Voici le c&#226;blage :&lt;/p&gt;
&lt;div class='spip_document_363 spip_document spip_documents spip_document_image spip_documents_center spip_document_center'&gt;
&lt;figure class=&#034;spip_doc_inner&#034;&gt; &lt;a href='https://modelleisenbahn.triskell.org/IMG/png/sketchDRV8824_bb.png' class=&#034;spip_doc_lien mediabox&#034; type=&#034;image/png&#034;&gt; &lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L500xH238/sketchDRV8824_bb-c7c7d.png?1692224381' width='500' height='238' alt='' /&gt;&lt;/a&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Et le sketch de l'application de d&#233;monstration. Il contient la fonction &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;allerAPosition(...)&lt;/code&gt; et l'ex&#233;cution d'un sc&#233;nario de mouvement.&lt;/p&gt;
&lt;div class='spip_document_378 spip_document spip_documents spip_document_file spip_document_avec_legende' data-legende-len=&#034;42&#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/pont_tournant_demo-2.zip' class=&#034; spip_doc_lien&#034; title='Zip - 1.3 kio' type=&#034;application/zip&#034;&gt;&lt;img src='https://modelleisenbahn.triskell.org/local/cache-vignettes/L64xH64/zip-f045b.svg?1772799586' 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-378 '&gt;&lt;strong&gt;Sketch de d&#233;monstration du pont tournant
&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>Mise en &#339;uvre de l'EasyDriver v4.4 pour un pont tournant</title>
		<link>https://modelleisenbahn.triskell.org/spip.php?article69</link>
		<guid isPermaLink="true">https://modelleisenbahn.triskell.org/spip.php?article69</guid>
		<dc:date>2013-12-09T12:33:38Z</dc:date>
		<dc:format>text/html</dc:format>
		<dc:language>fr</dc:language>
		<dc:creator>Jean-Luc</dc:creator>


		<dc:subject>Moteur pas-&#224;-pas</dc:subject>
		<dc:subject>Arduino</dc:subject>
		<dc:subject>Pont tournant</dc:subject>

		<description>
&lt;p&gt;Voici le compte rendu de quelques essais de mise en &#339;uvre avec l'objectif de motoriser un pont tournant. &lt;br class='autobr' /&gt;
Le mat&#233;riel &lt;br class='autobr' /&gt;
Afin d'avoir la meilleure r&#233;solution possible, le moteur pas-&#224;-pas bipolaire choisi est un moteur 400 pas par tour vendu par Selectronic. Il s'agit de ce mod&#232;le. &lt;br class='autobr' /&gt;
Ce moteur est pr&#233;vu pour &#234;tre aliment&#233; en 12V. Les bobines ont une r&#233;sistance de 40&#937; et par cons&#233;quent chaque bobine consomme 300mA. Le couple de maintien est de 3,5 kg/cm. &lt;br class='autobr' /&gt;
J'ai fix&#233; sur l'arbre une latte en (&#8230;)&lt;/p&gt;


-
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?rubrique19" rel="directory"&gt;La technologie&lt;/a&gt;

/ 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot7" rel="tag"&gt;Moteur pas-&#224;-pas&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot10" rel="tag"&gt;Arduino&lt;/a&gt;, 
&lt;a href="https://modelleisenbahn.triskell.org/spip.php?mot11" rel="tag"&gt;Pont tournant&lt;/a&gt;

		</description>


 <content:encoded>&lt;div class='rss_texte'&gt;&lt;p&gt;Voici le compte rendu de quelques essais de mise en &#339;uvre avec l'objectif de motoriser un pont tournant.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Le mat&#233;riel&lt;/h2&gt;
&lt;p&gt;Afin d'avoir la meilleure r&#233;solution possible, le moteur pas-&#224;-pas bipolaire choisi est un moteur 400 pas par tour vendu par Selectronic. Il s'agit de &lt;a href=&#034;http://www.selectronic.fr/moteur-pas-a-pas-modele-pap-2.html&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;ce mod&#232;le&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ce moteur est pr&#233;vu pour &#234;tre aliment&#233; en 12V. Les bobines ont une r&#233;sistance de 40&#937; et par cons&#233;quent chaque bobine consomme 300mA. Le couple de maintien est de 3,5 kg/cm.&lt;/p&gt;
&lt;p&gt;J'ai fix&#233; sur l'arbre une latte en bois de 40 cm de longueur et donc un rayon de 20cm. Cette longueur est de 30% sup&#233;rieure &#224; la longueur d'un pont tournant en H0 et plus de 2 fois plus long qu'un pont tournant en N. Cela permet de visualiser la rotation et plus particuli&#232;rement les d&#233;fauts.&lt;/p&gt;
&lt;div class='spip_document_348 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;37&#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/L500xH171/moteur_pap-b4e87.jpg?1692224381' width='500' height='171' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-348 '&gt;&lt;strong&gt;Montage d'essai du moteur pas-&#224;-pas
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;En combinant les 400 pas par tour du moteur et les 8 &#181;pas de l'EasyDriver, on arrive &#224; 3200 positions sur le cercle. Avec un diam&#232;tre de 30cm, typiquement un pont tournant en H0, cela nous donne un pas d'environ 0,3mm en bout de pont. Avec un diam&#232;tre de 15cm qui correspond au pont tournant PECO en N, cela nous donne un pas de 0,15mm en bout de pont.&lt;/p&gt;
&lt;p&gt;La connexion de l'Arduino &#224; l'EasyDriver est particuli&#232;rement simple. Comme on la vu dans &#171; &lt;a href='https://modelleisenbahn.triskell.org/spip.php?article68' class=&#034;spip_in&#034;&gt;L'Easydriver v4.4&lt;/a&gt; &#187;, la plupart des broches de l'EasyDriver ont la configuration ad&#233;quate quand on les laisse tout simplement non connect&#233;es.&lt;/p&gt;
&lt;div class='spip_document_362 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/L500xH238/easydriver-c2cbd.png?1692224382' width='500' height='238' alt='' /&gt;
&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;Les sorties num&#233;riques 2 et 3 de l'Arduino sont employ&#233;es pour piloter le moteur. On garde les alimentations s&#233;par&#233;es. L'EasyDriver est aliment&#233; en 12V continu et, pour les essais, l'Arduino reste aliment&#233; via l'USB.&lt;/p&gt;
&lt;div class='spip_document_349 spip_document spip_documents spip_document_image spip_documents_center spip_document_center spip_document_avec_legende' data-legende-len=&#034;39&#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/L500xH373/arduino_et_easy-6707b.jpg?1692224382' width='500' height='373' alt='' /&gt;
&lt;figcaption class='spip_doc_legende'&gt; &lt;div class='spip_doc_titre crayon document-titre-349 '&gt;&lt;strong&gt;Connexion de l'Arduino &#224; l'EasyDriver
&lt;/strong&gt;&lt;/div&gt; &lt;/figcaption&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Influence de la limitation de courant&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Plus le courant maximum &lt;i&gt;I&lt;sub&gt;max&lt;/sub&gt;&lt;/i&gt;, c'est &#224; dire le courant correspondant &#224; 100% d'alimentation d'une bobine, est &#233;lev&#233; et plus le passage d'un &#181;Pas au suivant est rapide et franc. Comme on veut le passage le plus doux possible, il faut r&#233;gler le courant maximum &#224; la valeur la plus basse possible.&lt;/p&gt;
&lt;blockquote class=&#034;spip&#034;&gt;
&lt;p&gt;
&lt;strong&gt;Les indications de sens de rotation du potentiom&#232;tre sur l'EasyDriver 4.4 sont fausses.&lt;/strong&gt; La valeur minimum correspond en fait &#224; une rotation dans le sens trigonom&#233;trique (&#224; gauche) et la valeur maximum &#224; une rotation dans le sens horaire (&#224; droite).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;D'apr&#232;s &lt;a href=&#034;http://www.schmalzhaus.com/EasyDriver/EasyDriver_v44/EasyDriver_v44_sch.pdf&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;la sch&#233;matique&lt;/a&gt;, le &lt;i&gt;I&lt;sub&gt;max&lt;/sub&gt;&lt;/i&gt; minimum possible est de 166mA pour &lt;i&gt;V&lt;sub&gt;ref&lt;/sub&gt;&lt;/i&gt; = 1V, ce qui correspond &#224; la valeur minimum que l'on trouve dans la &lt;a href=&#034;http://www.allegromicro.com/~/media/Files/Datasheets/A3967-Datasheet.ashx&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;documentation de l'&lt;i&gt;Allegro A3967&lt;/i&gt;&lt;/a&gt;. En r&#233;alit&#233;, le &lt;i&gt;V&lt;sub&gt;ref&lt;/sub&gt;&lt;/i&gt; minimum mesur&#233; est de 1,59V au lieu des 1V annonc&#233;s. Par ailleurs, j'ai mesur&#233; une valeur de 1,2&#937; pour les r&#233;sistances de capture de courant au lieu des 0,75&#937; annonc&#233;s dans la sch&#233;matique. Le rapport &lt;i&gt;V&lt;sub&gt;ref&lt;/sub&gt;&lt;/i&gt; / &lt;i&gt;R&lt;sub&gt;s&lt;/sub&gt;&lt;/i&gt; est quasiment le m&#234;me et le &lt;i&gt;I&lt;sub&gt;max&lt;/sub&gt;&lt;/i&gt; pour &lt;i&gt;V&lt;sub&gt;ref&lt;/sub&gt;&lt;/i&gt; = 1,59V est donc bien de 166mA.&lt;/p&gt;
&lt;p&gt;Voici une vid&#233;o montrant l'influence de la limitation de courant sur la fluidit&#233; de la rotation pour les valeurs suivantes de &lt;i&gt;I&lt;sub&gt;max&lt;/sub&gt;&lt;/i&gt; : 280mA (&lt;i&gt;V&lt;sub&gt;ref&lt;/sub&gt;&lt;/i&gt; = 2,69V), 224mA (&lt;i&gt;V&lt;sub&gt;ref&lt;/sub&gt;&lt;/i&gt; = 2,15V) et 166mA (&lt;i&gt;V&lt;sub&gt;ref&lt;/sub&gt;&lt;/i&gt; = 1,59V). La vitesse de rotation est de 1 tour en 2 minutes.&lt;/p&gt;
&lt;div class=&#034;spip_document_352 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-352&#034; data-id=&#034;085b2ed9e754ac8b976180f80f056099&#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/ZFFToe1mCec?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?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#034;base64javascript179256860569ce35256bef59.96790775&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;On voit effectivement que le r&#233;glage &lt;i&gt;I&lt;sub&gt;max&lt;/sub&gt;&lt;/i&gt; au minimum donne le meilleur r&#233;sultat en terme de fluidit&#233; de mouvement m&#234;me si la vid&#233;o gomme les petites vibrations qui sont observables &#224; des &lt;i&gt;I&lt;sub&gt;max&lt;/sub&gt;&lt;/i&gt; plus &#233;lev&#233;s. Le couple reste largement suffisant.&lt;/p&gt;
&lt;h2 class=&#034;spip&#034;&gt;Le logiciel&lt;/h2&gt;
&lt;p&gt;La pilotage du moteur pas-&#224;-pas est tr&#232;s facile. La broche 2 de l'Arduino connect&#233;e &#224; l'entr&#233;e DIR de l'EasyDriver permet de fixer le sens de rotation et la broche 3 connect&#233;e &#224; l'entr&#233;e STEP de l'EasyDriver permet d'avancer d'un &#181;Pas. Ces deux broches sont donc mises en sortie dans &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;setup()&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 int pinSens = 2; const int pinMicroPas = 3; void setup() { pinMode(pinSens, OUTPUT); pinMode(pinMicroPas, OUTPUT); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Le jeu consiste ensuite &#224; choisir un sens de rotation en mettant &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;pinSens&lt;/code&gt; &#224; HIGH ou LOW puis &#224; encha&#238;ner &#224; une certaine cadence des HIGH et des LOW sur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;pinMicroPas&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;La cadence est d&#233;termin&#233;e par le d&#233;lai d'attente entre deux bagottages sur &lt;code data-raccourci=&#034;code&#034; class='spip_code spip_code_inline' dir='ltr'&gt;pinMicroPas&lt;/code&gt;. Par exemple, si l'on veut que le pont accomplisse un tour complet en 2 minutes, soit 120 s, on calcule ce temps d'attente de la mani&#232;re suivante : 3200 &#181;Pas en 120 s donne un d&#233;lai de 120/3200 = 37,5 ms &#8771; 37 ms.&lt;/p&gt;
&lt;p&gt;Ainsi le programme le plus simple possible consiste &#224; faire tourner le moteur en permanence 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;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 loop() { digitalWrite(pinMicroPas, LOW); digitalWrite(pinMicroPas, HIGH); delay(37); }&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Voici une vid&#233;o qui montre l'ex&#233;cution d'une s&#233;quence de d&#233;placement : positionnement en 100, puis 300, puis 200, puis 800, puis 1600, puis 1000 et enfin 2400. Dans la premi&#232;re partie, un d&#233;lai de 36ms entre deux &#181;Pas est utilis&#233;. Les &#181;Pas ne sont pas visibles. Dans la seconde on passe &#224; un d&#233;lai de 99ms, les &#181;Pas deviennent visibles. Enfin dans la 3e partie, le mouvement d'une position &#224; l'autre a une phase d'acc&#233;l&#233;ration pendant 0,5s en passant d'un d&#233;lai de 78ms &#224; 36ms par d&#233;cr&#233;ment de 3ms et une phase de d&#233;c&#233;l&#233;ration pendant 0,75s en passant d'un d&#233;lai de 36ms &#224; 99ms par incr&#233;ment de 3. Les phases d'acc&#233;l&#233;ration et de d&#233;c&#233;l&#233;ration sont l&#233;g&#232;rement hach&#233;es.&lt;/p&gt;
&lt;div class=&#034;spip_document_353 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-353&#034; data-id=&#034;d110361da115dd72f52c38af0431f1aa&#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/XXFy7AJD_TA?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?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#034;base64javascript179256860569ce35256bef59.96790775&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#034;&gt;&lt;/div&gt; &lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;L'EasyDriver remplit son office mais montre quelques limites pour les tr&#232;s faibles vitesses qui sont utilis&#233;es dans les phases d'acc&#233;l&#233;ration et de d&#233;c&#233;l&#233;ration. D'autres &lt;i&gt;breakout boards&lt;/i&gt; existent et la prochaine fois, nous verrons celle d&#233;velopp&#233;e par &lt;a href=&#034;http://www.pololu.com&#034; class=&#034;spip_out&#034; rel=&#034;external&#034;&gt;Pololu&lt;/a&gt; qui utilise un &lt;i&gt;Texas Instruments&lt;/i&gt; DRV8824 permettant 32 &#181;Pas.&lt;/p&gt;&lt;/div&gt;
		
		</content:encoded>


		

	</item>
<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?1772799586' 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?1772797407' 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?1772798901' 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;base64javascript179256860569ce35256bef59.96790775&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#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?1772799586' 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?1772798901' 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;base64javascript107803548769ce3530098c62.81944290&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#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?1772799586' 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?1772798901' 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;base64javascript166586552469cf630e859323.72063725&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#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?1772799586' 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?1772798901' 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;base64javascript95743841069cf6312f310b7.50465382&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#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?1772799586' 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?1772799586' 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?1772798901' width='64' height='64' alt='Impossible de lire la video' /&gt; &lt;/video&gt; &lt;/div&gt;
&lt;/div&gt;
&lt;div class=&#034;base64javascript88701264269e13b598d0719.76143009&#034; title=&#034;PHNjcmlwdD4gdmFyIG1lanNwYXRoPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudC1hbmQtcGxheWVyLm1pbi5qcz8xNzcyNzk1ODQwJyxtZWpzY3NzPSdwbHVnaW5zLWRpc3QvbWVkaWFzL2xpYi9tZWpzL21lZGlhZWxlbWVudHBsYXllci5taW4uY3NzPzE3NzI3OTU4NDAnOwp2YXIgbWVqc2xvYWRlcjsKKGZ1bmN0aW9uKCl7dmFyIGE9bWVqc2xvYWRlcjsidW5kZWZpbmVkIj09dHlwZW9mIGEmJihtZWpzbG9hZGVyPWE9e2dzOm51bGwscGx1Zzp7fSxjc3M6e30saW5pdDpudWxsLGM6MCxjc3Nsb2FkOm51bGx9KTthLmluaXR8fChhLmNzc2xvYWQ9ZnVuY3Rpb24oYyl7aWYoInVuZGVmaW5lZCI9PXR5cGVvZiBhLmNzc1tjXSl7YS5jc3NbY109ITA7dmFyIGI9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgibGluayIpO2IuaHJlZj1jO2IucmVsPSJzdHlsZXNoZWV0IjtiLnR5cGU9InRleHQvY3NzIjtkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgiaGVhZCIpWzBdLmFwcGVuZENoaWxkKGIpfX0sYS5pbml0PWZ1bmN0aW9uKCl7ITA9PT1hLmdzJiZmdW5jdGlvbihjKXtqUXVlcnkoImF1ZGlvLm1lanMsdmlkZW8ubWVqcyIpLm5vdCgiLmRvbmUsLm1lanNfX3BsYXllciIpLmVhY2goZnVuY3Rpb24oKXtmdW5jdGlvbiBiKCl7dmFyIGU9ITAsaDtmb3IoaCBpbiBkLmNzcylhLmNzc2xvYWQoZC5jc3NbaF0pO2Zvcih2YXIgZiBpbiBkLnBsdWdpbnMpInVuZGVmaW5lZCI9PQp0eXBlb2YgYS5wbHVnW2ZdPyhlPSExLGEucGx1Z1tmXT0hMSxqUXVlcnkuZ2V0U2NyaXB0KGQucGx1Z2luc1tmXSxmdW5jdGlvbigpe2EucGx1Z1tmXT0hMDtiKCl9KSk6MD09YS5wbHVnW2ZdJiYoZT0hMSk7ZSYmalF1ZXJ5KCIjIitjKS5tZWRpYWVsZW1lbnRwbGF5ZXIoalF1ZXJ5LmV4dGVuZChkLm9wdGlvbnMse3N1Y2Nlc3M6ZnVuY3Rpb24oYSxjKXtmdW5jdGlvbiBiKCl7dmFyIGI9alF1ZXJ5KGEpLmNsb3Nlc3QoIi5tZWpzX19pbm5lciIpO2EucGF1c2VkPyhiLmFkZENsYXNzKCJwYXVzaW5nIiksc2V0VGltZW91dChmdW5jdGlvbigpe2IuZmlsdGVyKCIucGF1c2luZyIpLnJlbW92ZUNsYXNzKCJwbGF5aW5nIikucmVtb3ZlQ2xhc3MoInBhdXNpbmciKS5hZGRDbGFzcygicGF1c2VkIil9LDEwMCkpOmIucmVtb3ZlQ2xhc3MoInBhdXNlZCIpLnJlbW92ZUNsYXNzKCJwYXVzaW5nIikuYWRkQ2xhc3MoInBsYXlpbmciKX1iKCk7YS5hZGRFdmVudExpc3RlbmVyKCJwbGF5IixiLCExKTsKYS5hZGRFdmVudExpc3RlbmVyKCJwbGF5aW5nIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlIixiLCExKTthLmFkZEV2ZW50TGlzdGVuZXIoInBhdXNlZCIsYiwhMSk7Zy5hdHRyKCJhdXRvcGxheSIpJiZhLnBsYXkoKX19KSl9dmFyIGc9alF1ZXJ5KHRoaXMpLmFkZENsYXNzKCJkb25lIiksYzsoYz1nLmF0dHIoImlkIikpfHwoYz0ibWVqcy0iK2cuYXR0cigiZGF0YS1pZCIpKyItIithLmMrKyxnLmF0dHIoImlkIixjKSk7dmFyIGQ9e29wdGlvbnM6e30scGx1Z2luczp7fSxjc3M6W119LGUsaDtmb3IoZSBpbiBkKWlmKGg9Zy5hdHRyKCJkYXRhLW1lanMiK2UpKWRbZV09alF1ZXJ5LnBhcnNlSlNPTihoKTtiKCl9KX0oalF1ZXJ5KX0pO2EuZ3N8fCgidW5kZWZpbmVkIiE9PXR5cGVvZiBtZWpzY3NzJiZhLmNzc2xvYWQobWVqc2NzcyksYS5ncz1qUXVlcnkuZ2V0U2NyaXB0KG1lanNwYXRoLGZ1bmN0aW9uKCl7YS5ncz0hMDthLmluaXQoKTtqUXVlcnkoYS5pbml0KTtvbkFqYXhMb2FkKGEuaW5pdCl9KSl9KSgpOzwvc2NyaXB0Pg==&#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>



</channel>

</rss>
