<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>PlayArduino.fr &#187; binaire</title>
	<atom:link href="http://www.playarduino.fr/tag/binaire/feed" rel="self" type="application/rss+xml" />
	<link>http://www.playarduino.fr</link>
	<description>L&#039;actualité Arduino en Français</description>
	<lastBuildDate>Thu, 25 Feb 2010 15:30:19 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Booster le temps de réponse de votre Arduino</title>
		<link>http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html</link>
		<comments>http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html#comments</comments>
		<pubDate>Mon, 16 Nov 2009 23:53:45 +0000</pubDate>
		<dc:creator>Michael Hurni</dc:creator>
				<category><![CDATA[Logiciel]]></category>
		<category><![CDATA[PlayArduino.fr]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[binaire]]></category>
		<category><![CDATA[DIY]]></category>
		<category><![CDATA[hardcoding]]></category>

		<guid isPermaLink="false">http://www.playarduino.fr/?p=173</guid>
		<description><![CDATA[Hardcoding
L&#8217;assignation d&#8217;un état LOW/HIGH sur une pin de votre Arduino, se fait couramment à l&#8217;aide de la méthode digitalWrite(pin, state). RazorConcepts nous présentait il y a quelques semaines une nouvelle méthode pour assigner des états aux pins de votre Arduino. Jugeant cette méthode très intéressante, j&#8217;ai décider d&#8217;aller aujourd&#8217;hui un peu plus loin dans l&#8217;explication [...]]]></description>
			<content:encoded><![CDATA[<h2>Hardcoding</h2>
<p>L&#8217;assignation d&#8217;un état <tt>LOW/HIGH</tt> sur une pin de votre Arduino, se fait couramment à l&#8217;aide de la méthode <a href="http://arduino.cc/en/Reference/DigitalWrite">digitalWrite(pin, state)</a>. RazorConcepts nous présentait <a href="http://www.instructables.com/id/Arduino-is-Slow-and-how-to-fix-it/">il y a quelques semaines</a> une nouvelle méthode pour assigner des états aux pins de votre Arduino. Jugeant cette méthode très intéressante, j&#8217;ai décider d&#8217;aller aujourd&#8217;hui un peu plus loin dans l&#8217;explication de cette technique.</p>
<p>La méthode consiste en effet à assigner directement des valeurs (binaires ou hexadécimal) aux variables PORTB PORTC et PORTD, correspondant au trois encarts ci-dessous.</p>
<p><img class="align:none" title="Arduino mapping" src="http://www.playarduino.fr/wordpress/wp-content/uploads/2009/10/arduino_mapping.png" alt="" width="545" height="313" /></p>
<p>Chacun de ces ports du micro-contrôleur utilisé par l&#8217;Arduino possède de 6 à 8 entrées/sorties. Ainsi, à chaque pins de la platine correspond un couple PORT / numéro d&#8217;entrée/sortie.</p>
<pre><span style="color: #777755;">// sortie 543210</span>
<span style="color: #777755;">//        ↓↓↓↓↓↓</span>
PORTC = 0b110110;</pre>
<ul>
<li><a href="http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html#p1">Notation explicite</a></li>
<li><a href="http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html#p2">Passer une sortie spécifique à l&#8217;état <tt>HIGH</tt></a></li>
<li><a href="http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html#p3">Passer une sortie à l&#8217;état <tt>LOW</tt></a></li>
<li><a href="http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html#p4">Notation groupée, basculement simultané</a></li>
<li><a href="http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html#p5">Inverser l&#8217;état d&#8217;une sortie</a></li>
<li><a href="http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html#p6">Gain de poids, gain de perfs</a></li>
<li><a href="http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html#p7">Conclusion</a></li>
</ul>
<h2><a name="p1" href="#"></a>Notation explicite</h2>
<p>Si vous souhaitez modifier l&#8217;ensemble des états de plusieurs sorties d&#8217;un même <tt>PORT</tt>, il est possible d&#8217;écrire explicitement la valeur (complète) de ce dernier. On souhaite par exemple définir les états des pins digitales 7, 5 et 2 de l&#8217;Arduino à HIGH, et les pins 6, 4, 3, 1 et 0 à <tt>LOW</tt>. Les pins digitales 0 à 7 de l&#8217;Arduino correspondent aux sorties 0 à 7 du <tt>PORTD</tt>.</p>
<pre><span style="color: #777755;">// sortie 76543210</span>
<span style="color: #777755;">//        ↓↓↓↓↓↓↓↓</span>
PORTD = 0b10100100;
PORTD = 0xA4; <span style="color: #777755;">// notation hexadécimale</span></pre>
<p>L&#8217;état 1, symbolise l&#8217;état <tt>HIGH</tt>, l&#8217;état 0, l&#8217;état <tt>LOW</tt>. Le numéro de sortie commence à zéro et part de la droite vers la gauche (du <abbr title="Least Significant Bit"><tt>LSB</tt></abbr> au <abbr title="Most Significant Bit"><tt>MSB</tt></abbr>). Pour la conversion binaire, hexadécimale, rien de plus simple qu&#8217;une <a href="http://www.google.com/search?q=0b10100100+to+hex">requête Google</a></p>
<p>Les assignations explicites peuvent s&#8217;avérer utile dans la méthode setup() visant à initialiser l&#8217;état de votre circuit. Il permet également de rendre votre code source plus pro, et plus légé <img src='http://www.playarduino.fr/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h2><a name="p2" href="#"></a>Passer une sortie spécifique à l&#8217;état <tt>HIGH</tt></h2>
<p>Prenons comme exemple le passage de la pin digitale 3 à <tt>HIGH</tt>. Le schéma nous montre que la pin digital 3 se trouve sur le <tt>PORT D3</tt>.</p>
<pre><span style="color: #777755;">//  sortie 76543210</span>
<span style="color: #777755;">//         ↓↓↓↓↓↓↓↓</span>
PORTD |= 0b00001000 (PORT PD3)</pre>
<p>ou encore avec l&#8217;une des notations suivantes</p>
<pre>PORTD |= 0b1000
PORTD |= 1 &lt;&lt; 3;
PORTD |= _BV(3);</pre>
<p>Le shortcut <tt>_<abbr title="Byte Value">BV</abbr></tt> est définit dans <tt>./hardware/tools/avr/avr/include/avr/sfr_defs.h</tt> de l&#8217;IDE Arduino. Contrairement à l&#8217;assignation explicite, ces opérations, utilisant la porte logique <tt>OR</tt>, <strong>ne modifie que l&#8217;état de la ou des sorties souhaitées</strong>.</p>
<h2><a name="p3" href="#"></a>Passer une sortie à l&#8217;état <tt>LOW</tt></h2>
<p>Nous souhaitons, définir l&#8217;état de la pin digitale 11 à <tt>LOW</tt>, soit le <tt>PORT B, sortie 3</tt>. C&#8217;est à l&#8217;aide des portes logiques <tt>AND</tt> et <tt>NOT</tt> que nous pouvons écrire :</p>
<pre>PORTB &amp;= ~0b0000<strong>1</strong>000</pre>
<p>Ou l&#8217;une de ces notations équivalentes :</p>
<pre>PORTB &amp;=  0b11110111
PORTB &amp;=  <span style="color: #CC0000;">B11110111</span> <span style="color: #777755;">// constante</span>
PORTB &amp;= ~(1&lt;&lt;3)
PORTB &amp;= ~_BV(PB3);
PORTB &amp;= ~_BV(3);
<span style="color: #777755;">// Ou enfin, en hexadécimal</span>
PORTB &amp;= ~0x8;
PORTB &amp;= 0xF7;</pre>
<p>Les constantes B* sont définies de B0 à B11111111</p>
<h2><a name="p4" href="#"></a>Notation groupée</h2>
<p>Si les sorties, dont on souhaite modifier l&#8217;état, se trouvent sur le même port, il est possible de grouper l&#8217;ensemble des instructions en une seule. Nous souhaitons dans notre exemple passer les pins 6, 2 et 1 à <tt>LOW</tt>. Commençons par écrire chacune des trois instructions nécessaires à cet exemple.</p>
<pre>PORTD &amp;= ~B01000000  <span style="color: #777755;">// sortie 6, port D</span>
PORTD &amp;= ~B00000100  <span style="color: #777755;">// sortie 2, port D</span>
PORTD &amp;= ~B00000010  <span style="color: #777755;">// sortie 1, port D</span></pre>
<p>L&#8217;opération étant la même (passage à <tt>LOW</tt>) et concernant les sorties d&#8217;un même port (le D), il est donc possible les additionner</p>
<pre>pin D6 =&gt; PD6  0b01000000
pin D2 =&gt; PD2  0b00000100
pin D1 =&gt; PD1  0b00000010
               __________
on additionne  0b01000110</pre>
<p>L&#8217;opération &#8220;groupée&#8221; à effectuer est donc</p>
<pre>PORTD &amp;= ~0b01000110
<span style="color: #777755;">//           ↑   ↑↑</span>
<span style="color: #777755;">//           6   21  fixe les sorties 6,2 et 1 du PORT D à LOW</span>
<span style="color: #777755;">//                   sans modifier l'état des autres sorties</span></pre>
<p>Ce type de programmation permet donc <strong>un basculement simultané (en un cycle processeur) de plusieurs sorties</strong>. Dans le meilleur des cas, 9 cycles processeurs sont nécessaires avec la méthode classique <tt>digitalWrite</tt>.</p>
<h2>Explication sur l&#8217;opération <tt>AND NOT &amp;=~..</tt></h2>
<p>gardons notre exemple du triple passage à <tt>LOW</tt> (sorties 6, 2 et 1).</p>
<p>~ est l&#8217;opérateur NOT qui permet &#8220;d&#8217;inverser&#8221; la valeur des bits<br />
<tt>~..000001000110  =  ..111110111001</tt></p>
<p>le nombre de 1 devant la notation binaire dépends de l&#8217;architecture du microprocesseur (ici 8 bits)</p>
<p>On peut donc écrire,</p>
<pre>  <span style="color: #777755;">//       7 543  0</span>
  <span style="color: #777755;">//       ↓ ↓↓↓  ↓    keep on if on</span>
PORTD &amp;= 0b10111001
  <span style="color: #777755;">//        ↑   ↑↑</span>
  <span style="color: #777755;">//        6   21     switch off if on</span></pre>
<p><strong>On renseigne enfaite ici les bits à maintenir allumé</strong>, si ils le sont déjà.</p>
<p>Ainsi, dans ce même exemple (mettre pin 6,2, et 1 à LOW) supposons, au hasard, un état du port D initial à <tt>0b01011101</tt></p>
<p>Nous appliquons l&#8217;opération <tt>PORTD &amp;= ~B01000110</tt> vu précédemment, qui peut également s&#8217;écrire :</p>
<pre>PORTD &amp;= 0b10111001
PORTD = PORTD &amp; 0b10111001
PORTD = 0b01011101 &amp; 0b10111001 

<span style="color: #777755;">//      0b01011101
//  &amp;   0b1<strong>0</strong>111<strong>00</strong>1
//      ----------
//      0b0<strong>0</strong>011<strong>00</strong>1
//        ↑↑↑↑↑↑↑↑
// sortie 7<strong>6</strong>543<strong>21</strong>0</span></pre>
<p>On applique l&#8217;opération AND sur chaque bit, (rappel : <tt>0b1 &amp; 0b1 = 0b1</tt>)</p>
<p>l&#8217;état final, <tt>0b0<strong>0</strong>011<strong>00</strong>1</tt>, montre donc bien une modification de l&#8217;état des sorties 6 et 2 à <tt>LOW</tt> (la pin 1 étant déjà à LOW).<strong> Cette opération n&#8217;a eu aucune incidence sur l&#8217;état des autres pins</strong>, comme souhaité ; <strong>le tout en un seul cycle</strong>.</p>
<h2><a name="p5" href="#"></a>Inverser l&#8217;état d&#8217;une sortie</h2>
<p><em>Exemple :</em> nous souhaitons inverser l&#8217;état de la sortie 5 et 7 du PORTD. Dans un cas concret, deux LED clignotant en alternance l&#8217;une de l&#8217;autre sur les pins digitales 5 et 7.</p>
<pre><span style="color: #996600;">int</span> state = 1;

<span style="color: #CC6600;">void</span> <span style="color: #993300;"><strong>setup</strong></span>() {}
<span style="color: #CC6600;">void</span> <span style="color: #993300;"><strong>loop</strong></span>() {
  <span style="color: #CC6600;">if</span>(state==1) { <span style="color: #777755;">// on réalise l'alternance à l'aide d'une variable</span>
    state = 0;
    <span style="color: #996600;">digitalWrite</span>(5, <span style="color: #CC0000;">LOW</span>);
    <span style="color: #996600;">digitalWrite</span>(7, <span style="color: #CC0000;">HIGH</span>);
  }
  <span style="color: #CC6600;">else</span> {
    state = 1;
    <span style="color: #996600;">digitalWrite</span>(5, <span style="color: #CC0000;">HIGH</span>);
    <span style="color: #996600;">digitalWrite</span>(7, <span style="color: #CC0000;">LOW</span>);
  }
  <span style="color: #996600;">delay</span>(1000); <span style="color: #777755;">// on attend 1 seconde</span>
}</pre>
<p>Avec les opérations binaires, la fonction <abbr title="eXclusive OR">XOR</abbr> nous permet d&#8217;écrire</p>
<pre><span style="color: #CC6600;">void</span> <span style="color: #993300;"><strong>setup</strong></span>() {
  PORTD = <span style="color: #CC0000;">B10000000</span>; <span style="color: #777755;">// on définit l'état initial</span>
}
<span style="color: #CC6600;">void</span> <span style="color: #993300;"><strong>loop</strong></span>() {
  <span style="color: #777755;">//sorties 7 5</span>
  <span style="color: #777755;">//        ↓ ↓</span>
  PORTD ^= <span style="color: #CC0000;">B10100000</span>; <span style="color: #777755;">// ou PORTD ^= 0xA0;</span>
  <span style="color: #996600;">delay</span>(1000);
}</pre>
<p>Une fois compilée, on obtient une ROM de 550 bytes en opération binaire contre 846 bytes en écriture standard.</p>
<p>Autre avantage, si l&#8217;on souhaite modifier l&#8217;état initial (pour par exemple faire clignoter les LEDs ensembles), une seule modification suffit, l&#8217;état initial de <tt>PORTD</tt>.</p>
<h2><a name="p6" href="#"></a>Gain de poids, gain de performances</h2>
<p>Voici un exemple simple mettant en œuvre un chenillard à 8 LEDs. En écriture &#8220;binaire&#8221;</p>
<pre><span style="color: #996600;">int</span> lednum = 0;

<span style="color: #CC6600;">void</span> <span style="color: #993300;"><strong>setup</strong></span>(){}
<span style="color: #CC6600;">void</span> <span style="color: #993300;"><strong>loop</strong></span>() {
  PORTD = 1 &lt;&lt; lednum; <span style="color: #777755;">// un seul cycle processeur</span>
  <span style="color: #996600;">delay</span>(1000);
  lednum++;
  <span style="color: #CC6600;">if</span>(lednum==8) lednum = 0;
}</pre>
<p>Le même algorithme en écriture standard</p>
<pre><span style="color: #996600;">int</span> lednum = 0;

<span style="color: #CC6600;">void</span> <span style="color: #993300;"><strong>setup</strong></span>(){}
<span style="color: #CC6600;">void</span> <span style="color: #993300;"><strong>loop</strong></span>() {
  <span style="color: #996600;">digitalWrite</span>(0, <span style="color: #CC0000;">LOW</span>); <span style="color: #777755;">// on éteint l'ensemble des LED</span>
  <span style="color: #996600;">digitalWrite</span>(1, <span style="color: #CC0000;">LOW</span>);
  <span style="color: #996600;">digitalWrite</span>(2, <span style="color: #CC0000;">LOW</span>);
  <span style="color: #996600;">digitalWrite</span>(3, <span style="color: #CC0000;">LOW</span>);
  <span style="color: #996600;">digitalWrite</span>(4, <span style="color: #CC0000;">LOW</span>);
  <span style="color: #996600;">digitalWrite</span>(5, <span style="color: #CC0000;">LOW</span>);
  <span style="color: #996600;">digitalWrite</span>(6, <span style="color: #CC0000;">LOW</span>);
  <span style="color: #996600;">digitalWrite</span>(7, <span style="color: #CC0000;">LOW</span>);
  <span style="color: #996600;">digitalWrite</span>(lednum, <span style="color: #CC0000;">HIGH</span>);
  <span style="color: #996600;">delay</span>(1000);
  lednum++;
  <span style="color: #CC6600;">if</span>(lednum==8) lednum = 0;
}</pre>
<p>Une fois compilé on obtient ici un programme 588 bytes contre 886 bytes avec le premier code source.</p>
<p>Sur ces quelques exemples concrets, le gain en poids est de l&#8217;ordre de 35 %. Toutefois, si l&#8217;on soustrait à ces tailles de programme les 436 bytes occupés par un programme vide (afin de ne retenir uniquement la taille de l&#8217;espace occupé par les instructions propres au programme). On obtient une taille de 152 bytes contre 450 bytes, soit <strong>une réduction de 66% du code</strong>.</p>
<h2><a name="p7" href="#"></a>Conclusion</h2>
<p>Outre <strong>le gain de taille, crucial sur un microprocesseur de ce type</strong>, le gain en performances. <a href="http://www.instructables.com/id/S79LPX4G145RVFC">Un benchmark réalisé par RazorConcepts</a> montre <strong>des temps de réponse 10 fois supérieurs à la fonction standard digitalWrite()</strong> proposée par l&#8217;IDE Arduino.</p>
<p>Bien entendu, je vous ai présenté ici les exemples &#8220;qui vont bien&#8221; (même PORT, opérations simples,.. ). Il y a fort à parier que dans d&#8217;autre cas, plus spécifiques, les instructions binaires ne soit pas nécessairement un choix très judicieux.</p>
<p>Ainsi, à moins de frôler dangereusement la limite imposée par votre micro-contrôleur (16 ou 32K), <strong>l&#8217;utilisation de cette technique reste dédiée aux librairies, aux montages nécessitant une réactivité accrue, ou ceux nécessitant des changements d&#8217;état simultanés</strong>.</p>
<p><strong>Trois opérations à retenir :</strong></p>
<ul>
<li>le <tt>OR</tt> (<tt>|=</tt>) qui permet de modifier la valeur des bits choisi à 1, et donc de passer les sorties à l&#8217;état <tt>HIGH</tt>.</li>
<li>le <tt>AND NOT</tt> (différent de <tt>NAND</tt> !) (<tt>&amp;=~</tt>) qui permettra de &#8220;soustraire 1&#8243; aux bits choisis, et permet donc de mettre des sorties à l&#8217;état <tt>LOW</tt></li>
<li>le <tt>XOR</tt> (<tt>^=</tt>) qui permettra d&#8217;inverser l&#8217;état des sorties renseignées pas un bit positif</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.playarduino.fr/2009/11/booster-le-temps-de-reponse-de-votre-arduino.html/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
