{"id":413,"date":"2020-05-16T01:25:23","date_gmt":"2020-05-16T01:25:23","guid":{"rendered":"https:\/\/marcjuneau.ca\/?p=413"},"modified":"2020-05-20T12:40:27","modified_gmt":"2020-05-20T12:40:27","slug":"esp32-et-atmega32u4-arduino-micro-via-i2c","status":"publish","type":"post","link":"https:\/\/marcjuneau.ca\/?p=413","title":{"rendered":"ESP32 et Atmega32u4 (Arduino micro) via I2C"},"content":{"rendered":"\n<p>Dans cet article, nous allons \u00e9changer des donn\u00e9es entre le ESP32 et le\u00a0 Atmega32u4 (Arduino micro) via un lien I2C. Le ESP32 sera programm\u00e9 dans PlatformIO dans le cadre Arduino alors que le Atmega32u4 sera programm\u00e9 sous Atmel studio avec les librairies C de base. Pour les r\u00f4les, le ESP32 sera le ma\u00eetre et le Atmega32U4 sera l&rsquo;esclave.<\/p>\n<p>La fonctionnalit\u00e9 sera valid\u00e9e par un bouton et une DEL sur chacun des deux modules. Ainsi, lorsque l&rsquo;on appuiera sur le bouton du ESP32, la DEL du Atmega32 sera allum\u00e9e et vise-versa.\u00a0<\/p>\n<p>Finalement, nous utiliserons l&rsquo;analyseur logique (Digital Discovery) afin de visualiser le protocole I2C entre les deux modules.<\/p>\n<p>D\u00e9butons par le montage. Voici le sch\u00e9ma :<\/p>\n<p><a href=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/schemaEsp32I2C.jpg\" target=\"_blank\" rel=\"noopener noreferrer\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-415 size-full\" src=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/schemaEsp32I2C.jpg\" alt=\"\" width=\"1586\" height=\"538\" srcset=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/schemaEsp32I2C.jpg 1586w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/schemaEsp32I2C-300x102.jpg 300w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/schemaEsp32I2C-1024x347.jpg 1024w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/schemaEsp32I2C-768x261.jpg 768w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/schemaEsp32I2C-1536x521.jpg 1536w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/schemaEsp32I2C-465x158.jpg 465w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/schemaEsp32I2C-695x236.jpg 695w\" sizes=\"auto, (max-width: 1586px) 100vw, 1586px\" \/><\/a><\/p>\n<p>Notez que le ESP32 n&rsquo;est pas tol\u00e9rant au 5V sur les GPIO et que le Atmega32u4 supporte les niveaux logiques du 3V3. Une approche simple consiste donc d&rsquo;utiliser des r\u00e9sistances tire-haut \u00e0 3V3.<\/p>\n<p>Lorsque l&rsquo;on appuiera sur le bouton SW1, la valeur transmise du ESP32 au Atmega32u4 sera 1 et 0 lorsqu&rsquo;il ne sera pas appuy\u00e9.<\/p>\n<h5>1- Programmation de la transmission dans le ESP32<\/h5>\n<p>La librairie Wire dans arduino permet d&rsquo;utiliser le lien I2C sans difficult\u00e9.\u00a0<\/p>\n<p>Dans la fonction <em>setup<\/em>, nous d\u00e9butons par l&rsquo;initialisation du I2C. Par d\u00e9faut, pour le ESP32, les broches SCL et SDA sont respectivement GPIO22 et GPIO21. L&rsquo;appel de la m\u00e9thode begin() se fait donc sans param\u00e8tre.<\/p>\n<pre>void\u00a0setup()\u00a0<br \/>{<br \/>\u00a0Wire.begin();\u00a0<br \/>}<\/pre>\n<p>Ensuite dans <em>loop<\/em>, la lecture du bouton conserve l&rsquo;\u00e9tat dans une variable (pour utilisation future) qui sera transmise sur le lien I2C. Pour la transmission, il suffit de d\u00e9marrer la transmission en pr\u00e9cisant l&rsquo;adresse du module vis\u00e9 (ici nous utiliserons 8 pour le Atmega32u4). Ensuite, l&rsquo;envoi de la donn\u00e9e se fait avec la m\u00e9thode <em>write<\/em>, qui re\u00e7oit en param\u00e8tre la donn\u00e9e \u00e0 transmettre. Finalement, la transmission est termin\u00e9e \u00e0 l&rsquo;aide de la m\u00e9thode <em>endTransmission<\/em>, qui va \u00e9mettre la condition stop sur le I2C. Le d\u00e9lai de 100ms est seulement pour envoyer moins de donn\u00e9es durant l&rsquo;exemple.<\/p>\n<p><span style=\"color: #23282d; font-family: Menlo, Consolas, monaco, monospace; font-size: 14px; white-space: pre-wrap;\">uint8_t\u00a0stateOut\u00a0=\u00a00;<\/span><\/p>\n<div>\n<pre>void loop()\u00a0<br \/>{<br \/> \u00a0Wire.beginTransmission(8); \/\/ L'adresse du atmega32u4 sera 8<br \/> \u00a0Wire.write(stateOut);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0 <br \/> \u00a0Wire.endTransmission();\u00a0\u00a0\u00a0\u00a0 <br \/><br \/> \u00a0\/\/ Lecture du bouton vers une variable.<br \/>  if(digitalRead(23)==0)<br \/> \u00a0\u00a0\u00a0stateOut\u00a0=1;<br \/> \u00a0else<br \/> \u00a0\u00a0\u00a0stateOut\u00a0=0;<br \/><br \/>\u00a0\u00a0delay(100);<br \/>}<\/pre>\n<h5>2 &#8211; Programmation de la r\u00e9ception dans le Atmega32u4<\/h5>\n<p>Pour simplifier la r\u00e9ception, nous utiliserons l&rsquo;interruption du TWI (I2C chez Atmel). L&rsquo;interruption est d\u00e9clench\u00e9e lorsque l&rsquo;adresse du module est d\u00e9tect\u00e9e en r\u00e9ception, si une donn\u00e9e est re\u00e7ue ou si une donn\u00e9e est transmise. Les d\u00e9finitions sont dans la librairie twi.h dans les fichiers avr.<\/p>\n<p>Pour la r\u00e9ception, nous allons utiliser un tableau de 16 octets m\u00eame si dans la premi\u00e8re application, nous transmettons un seul octet. Nous d\u00e9butons donc par d\u00e9clarer nos variables :<\/p>\n<pre>#define _I2C_RX_BUFFER_MAX_SIZE 16<br \/><br \/>volatile uint8_t _i2c_rxBuffer[_I2C_RX_BUFFER_MAX_SIZE];<br \/>volatile uint8_t _i2c_rxBuffer_indexIn = 0;<br \/>volatile uint8_t _i2c_newRxData = 0;<br \/><br \/><\/pre>\n<p>Ensuite, dans le traitement de l&rsquo;interruption, nous allons faire le traitement en fonction du registre d&rsquo;\u00e9tat. Si l&rsquo;adresse esclave est re\u00e7ue et que la commande est un Write, nous initialisons l&rsquo;index de r\u00e9ception et nous nous assurons que le module va envoyer un ACK apr\u00e8s la r\u00e9ception des donn\u00e9es.<\/p>\n<p>Si c&rsquo;est une donn\u00e9e qui est re\u00e7ue, elle est plac\u00e9e en m\u00e9moire et l&rsquo;index est augment\u00e9. Si l&rsquo;index arrive au dernier \u00e9l\u00e9ment du tableau de r\u00e9ception, la configuration passe \u00e0 la g\u00e9n\u00e9ration d&rsquo;un NACK pour le prochain \u00e9l\u00e9ment re\u00e7u. Un indicateur est utilis\u00e9 afin de savoir qu&rsquo;une nouvelle donn\u00e9e est re\u00e7ue.<\/p>\n<pre>ISR(TWI_vect)<br \/>{<br \/> switch ((TWSR &amp; 0xF8))<br \/> {<br \/>  \/\/ Adresse du module re\u00e7u et W<br \/>  case TW_SR_SLA_ACK :<br \/>    _i2c_rxBuffer_indexIn = 0;<br \/>    \/\/ pr\u00e9pare pour r\u00e9ception de la donn\u00e9e<br \/>    TWCR |=(1&lt;&lt;TWEA);<br \/>    break;<br \/>  \/\/ Donn\u00e9e re\u00e7ue<br \/>  case TW_SR_DATA_ACK:<br \/>    \/\/ place en m\u00e9moire si le buffer n'est pas plein<br \/>    if(_i2c_rxBuffer_indexIn &lt; _I2C_RX_BUFFER_MAX_SIZE)<br \/>      _i2c_rxBuffer[_i2c_rxBuffer_indexIn++] = TWDR;<br \/><br \/>    \/\/  Si le buffer est au dernier \u00e9l\u00e9ment, g\u00e9n\u00e9rer un NACK au prochain.<br \/>    if(_i2c_rxBuffer_indexIn &gt;= _I2C_RX_BUFFER_MAX_SIZE-1)<br \/>      TWCR &amp;= ~(1&lt;&lt;TWEA);<br \/>    else<br \/>      TWCR |=(1&lt;&lt;TWEA);<br \/><br \/>    _i2c_newRxData = 1;<br \/>    break;<br \/>  <br \/>  default :<br \/>    TWCR |=(1&lt;&lt;TWEA);<br \/> }<br \/> \/\/ Dans tous les cas, rel\u00e2che le flag du ISR<br \/> TWCR |= (1&lt;&lt;TWIE) | (1&lt;&lt;TWINT) | (1&lt;&lt;TWEN);<br \/>}<\/pre>\n<p>Pour l&rsquo;initialisation c&rsquo;est simple, car le mode esclave ne configure par la vitesse. Il faut simplement s&rsquo;assurer que le l&rsquo;horloge interne est au moins 16x plus rapide que le SCL. Par contre dans le mode esclave, il faut configurer l&rsquo;adresse du module.<\/p>\n<pre>void i2cInitSlaveMode(uint8_t add )<br \/>{<br \/>  TWAR = (add&lt;&lt;1) ; \/\/ Place l'adresse du slave + Ne r\u00e9pondra pas sur l'adresse g\u00e9n\u00e9rale<br \/>  TWCR = (1&lt;&lt;TWIE) | (1&lt;&lt;TWEA) | (1&lt;&lt;TWINT) | (1&lt;&lt;TWEN); \/\/ active le ISR et le I2c et le ACK<br \/>  sei();<br \/>}<\/pre>\n<p>Afin de d\u00e9tecter les nouvelles donn\u00e9es re\u00e7ues \u00e0 l&rsquo;ext\u00e9rieur de la librairie, nous utiliserons les deux fonctions suivantes :<\/p>\n<pre>void i2cClearNewDataFlag()<br \/>{<br \/>  cli();<br \/>  _i2c_newRxData = 0;<br \/>  sei();<br \/>}<br \/>uint8_t i2cNewDataAvailable()<br \/>{<br \/>  return _i2c_newRxData;<br \/>}<\/pre>\n<p>Finalement, une fonction permet de lire un octet dans le tableau de r\u00e9ception.<\/p>\n<pre>uint8_t i2cReadBuffer(uint8_t add)<br \/>{<br \/>  if(add &lt; _I2C_RX_BUFFER_MAX_SIZE)<br \/>    return _i2c_rxBuffer[add];<br \/>  return _i2c_rxBuffer[0];<br \/>}<\/pre>\n<p>La fonction main est tr\u00e8s petite. Elle regarde si une nouvelle donn\u00e9e est re\u00e7ue. Si c&rsquo;est le cas, elle va lire le premier octet en m\u00e9moire, elle efface l&rsquo;indication qu&rsquo;une donn\u00e9e est re\u00e7ue, puis elle change l&rsquo;\u00e9tat de la DEL.<\/p>\n<pre>int main(void)<br \/>{<br \/> i2cInitSlaveMode(8);<br \/> DDRC |= (1&lt;&lt;7);<br \/> while (1) <br \/> {<br \/>  if(i2cNewDataAvailable())<br \/>  {<br \/>   stateIn = i2cReadBuffer(0);<br \/>   i2cClearNewDataFlag();<br \/>   if(stateIn &amp; 1)<br \/>    PORTC |= (1&lt;&lt;7);<br \/>   else<br \/>    PORTC &amp;= ~(1&lt;&lt;7);<br \/>  }<br \/>  _delay_ms(1);<br \/> }<br \/>}<\/pre>\n<h5>3- Ajout de la lecture du slave dans le ESP32<\/h5>\n<p>Maintenant que le ESP32 peut envoyer des donn\u00e9es vers le Atmega32u4, nous allons ajouter le sens inverse.\u00a0\u00a0<\/p>\n<p>Pour d\u00e9clencher la lecture de l&rsquo;esclave, il faut utiliser la commande Wire.requestFrom(#adresse, #nombre d&rsquo;octets \u00e0 lire). Ensuite la lecture se fait avec la fonction Wire.read() qui retourne 1 octet re\u00e7u \u00e0 la fois.<\/p>\n<div>\n<pre>delayMicroseconds(10);<br \/>Wire.requestFrom(8, 1);\u00a0\u00a0\/\/ Lire 1 octet du module #8 <br \/>stateIn = Wire.read();<\/pre>\n<h5>4- Ajout de la transmission dans le atmega32u4<\/h5>\n<p>Pour que le atmega32u4 r\u00e9ponde \u00e0 la demande de lecture du ma\u00eetre, il faut ajouter le support pour la condition o\u00f9 l&rsquo;on re\u00e7oit l&rsquo;adresse du module et la commande Read. Lorsque l&rsquo;adresse est re\u00e7ue avec la commande Read, la premi\u00e8re \u00e9tape consiste \u00e0 remettre l&rsquo;index de transmission \u00e0 0 et \u00e0 envoyer la premi\u00e8re donn\u00e9e. Ensuite, pour chaque r\u00e9ception d&rsquo;un ACK par le ma\u00eetre, transmettre une autre donn\u00e9e. L&rsquo;arr\u00eat se fait sur r\u00e9ception d&rsquo;un NACK. Sinon, si la lecture d\u00e9passe le tableau de transmission, il va transmettre des 0. Voici le code pour cette section.<\/p>\n<pre>\/\/ Adresse re\u00e7ue avec demande de lecture<br \/>case TW_ST_SLA_ACK :<br \/>case TW_ST_ARB_LOST_SLA_ACK :<br \/>  _i2c_txBuffer_indexOut = 0; \/\/ au d\u00e9but on clear l'index<br \/>case TW_ST_DATA_ACK :<br \/>  \/\/ Transmission de la donn\u00e9e<br \/> if(_i2c_txBuffer_indexOut &lt; _I2C_TX_BUFFER_MAX_SIZE)<br \/>   TWDR = _i2c_txBuffer[_i2c_txBuffer_indexOut++];<br \/> else<br \/>   TWDR = 0; <br \/> break;<br \/>\/\/ Derni\u00e8re donn\u00e9e NACK, on fait rien<br \/>case TW_ST_DATA_NACK :<br \/>  break;<\/pre>\n<h5>5- Lectures avec l&rsquo;analyseur logique<\/h5>\n<p>Voici ce que l&rsquo;on pourra observ\u00e9 sur l&rsquo;analyseur logique avec les signaux SDA et SCL. La premi\u00e8re s\u00e9quence est lorsque le ESP32 transmet vers le Atmega32u4 et la seconde, est lorsque le ESP32 va lire le Atmega32u4.<\/p>\n<p style=\"text-align: center;\">Si aucun bouton n&rsquo;est appuy\u00e9<\/p>\n<p><a href=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_00.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-423 size-full\" title=\"Lors qu\u2019aucun bouton n'est appuy\u00e9\" src=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_00.png\" alt=\"Lors qu\u2019aucun bouton n'est appuy\u00e9\" width=\"1586\" height=\"102\" srcset=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_00.png 1586w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_00-300x19.png 300w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_00-1024x66.png 1024w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_00-768x49.png 768w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_00-1536x99.png 1536w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_00-465x30.png 465w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_00-695x45.png 695w\" sizes=\"auto, (max-width: 1586px) 100vw, 1586px\" \/><\/a><\/p>\n<p style=\"text-align: center;\">Si le bouton du ESP32 est appuy\u00e9<\/p>\n<p><a href=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_10.png\" target=\"_blank\" rel=\"noopener noreferrer\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-426 size-full\" src=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_10.png\" alt=\"\" width=\"1586\" height=\"102\" srcset=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_10.png 1586w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_10-300x19.png 300w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_10-1024x66.png 1024w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_10-768x49.png 768w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_10-1536x99.png 1536w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_10-465x30.png 465w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_10-695x45.png 695w\" sizes=\"auto, (max-width: 1586px) 100vw, 1586px\" \/><\/a><\/p>\n<p style=\"text-align: center;\">Si le bouton du Atmega32u4 est appuy\u00e9<\/p>\n<p><a href=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_01.png\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-437 size-full\" src=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_01.png\" alt=\"\" width=\"1586\" height=\"98\" srcset=\"https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_01.png 1586w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_01-300x19.png 300w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_01-1024x63.png 1024w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_01-768x47.png 768w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_01-1536x95.png 1536w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_01-465x29.png 465w, https:\/\/marcjuneau.ca\/wp-content\/uploads\/2020\/05\/esp_at_01-695x43.png 695w\" sizes=\"auto, (max-width: 1586px) 100vw, 1586px\" \/><\/a><\/p>\n<p>\u00a0<\/p>\n<h5>6- Codes complets<\/h5>\n<p>Voici donc le code complet pour le ESP32<\/p>\n<div>\n<pre>#include\u00a0&lt;Arduino.h&gt;<br \/>#include &lt;Wire.h&gt;<br \/><br \/>void\u00a0setup()\u00a0<br \/>{<br \/> \u00a0Wire.begin();\u00a0<br \/> \u00a0pinMode(15,OUTPUT);<br \/>}<br \/><br \/>uint8_t\u00a0stateOut\u00a0=\u00a00;<br \/>uint8_t stateIn = 0;<br \/><br \/>void\u00a0loop()\u00a0<br \/>{<br \/> \u00a0Wire.beginTransmission(8);<br \/> \u00a0Wire.write(stateOut);\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\u00a0sends\u00a0value\u00a0byte\u00a0\u00a0<br \/> \u00a0Wire.endTransmission();\u00a0\u00a0\u00a0\u00a0\u00a0\/\/\u00a0stop\u00a0transmitting\u00a0\u00a0<br \/> \u00a0if(digitalRead(23)==0)<br \/> \u00a0\u00a0\u00a0stateOut\u00a0=1;<br \/> \u00a0else<br \/> \u00a0\u00a0\u00a0stateOut\u00a0=0;<br \/> \u00a0delayMicroseconds(10);<br \/> \u00a0Wire.requestFrom(8,\u00a01);\u00a0\u00a0\u00a0\u00a0\/\/\u00a0request\u00a06\u00a0bytes\u00a0from\u00a0slave\u00a0device\u00a0#2<br \/> \u00a0stateIn\u00a0=\u00a0Wire.read();<br \/> \u00a0digitalWrite(15,stateIn);<br \/> \u00a0delay(100);<br \/>}<br \/><br \/><\/pre>\n<p>Le code complet pour le fichier i2cSlave.c<\/p>\n<pre>#include \"i2c.h\"<br \/>#include &lt;avr\/io.h&gt;<br \/>#include &lt;util\/twi.h&gt; \/\/ pour les defines des \u00e9tats<br \/>#include &lt;avr\/interrupt.h&gt;<br \/><br \/>#define _I2C_TX_BUFFER_MAX_SIZE 16<br \/>volatile uint8_t _i2c_txBuffer[_I2C_TX_BUFFER_MAX_SIZE];<br \/>volatile uint8_t _i2c_txBuffer_indexOut = 0;<br \/><br \/>#define _I2C_RX_BUFFER_MAX_SIZE 16<br \/>volatile uint8_t _i2c_rxBuffer[_I2C_RX_BUFFER_MAX_SIZE];<br \/>volatile uint8_t _i2c_rxBuffer_indexIn = 0;<br \/>volatile uint8_t _i2c_newRxData = 0;<br \/><br \/>ISR(TWI_vect)<br \/>{<br \/> switch ((TWSR &amp; 0xF8))<br \/> {<br \/>  \/\/ Adresse du module re\u00e7u et W<br \/>  case TW_SR_SLA_ACK :<br \/>    _i2c_rxBuffer_indexIn = 0;<br \/>    \/\/ pr\u00e9pare pour r\u00e9ception de la donn\u00e9e<br \/>    TWCR |=(1&lt;&lt;TWEA);<br \/>    break;<br \/>  \/\/ Donn\u00e9e re\u00e7ue<br \/>  case TW_SR_DATA_ACK:<br \/>    \/\/ place en m\u00e9moire si le buffer n'est pas plein<br \/>    if(_i2c_rxBuffer_indexIn &lt; _I2C_RX_BUFFER_MAX_SIZE)<br \/>      _i2c_rxBuffer[_i2c_rxBuffer_indexIn++] = TWDR;<br \/><br \/>    \/\/ le buffer est full, arr\u00eater la r\u00e9ception, sinon pr\u00e9pare pour la prochaine r\u00e9ception<br \/>    if(_i2c_rxBuffer_indexIn &gt;= _I2C_RX_BUFFER_MAX_SIZE)<br \/>      TWCR &amp;= ~(1&lt;&lt;TWEA);<br \/>    else<br \/>      TWCR |=(1&lt;&lt;TWEA);<br \/><br \/>    _i2c_newRxData = 1;<br \/>    break;<br \/>  \/\/ Adresse re\u00e7ue avec demande de lecture<br \/>  case TW_ST_SLA_ACK :<br \/>  case TW_ST_ARB_LOST_SLA_ACK :<br \/>    _i2c_txBuffer_indexOut = 0;<br \/>  case TW_ST_DATA_ACK :<br \/>    \/\/ Transmission de la premi\u00e8re donn\u00e9e<br \/>    if(_i2c_txBuffer_indexOut &lt; _I2C_TX_BUFFER_MAX_SIZE)<br \/>      TWDR = _i2c_txBuffer[_i2c_txBuffer_indexOut++];<br \/>    else<br \/>      TCDR = 0;<br \/>    break;<br \/>     \/\/ Derni\u00e8re donn\u00e9e NACK, on fait rien<br \/>  case TW_ST_DATA_NACK :<br \/>    break;<br \/>  default :<br \/>    TWCR |=(1&lt;&lt;TWEA);<br \/> }<br \/> \/\/ Dans tous les cas, rel\u00e2che le flag du ISR<br \/> TWCR |= (1&lt;&lt;TWIE) | (1&lt;&lt;TWINT) | (1&lt;&lt;TWEN);<br \/>}<br \/><br \/>void i2cWriteBuffer(uint8_t add, uint8_t data)<br \/>{<br \/>  if(add &lt; _I2C_TX_BUFFER_MAX_SIZE)<br \/>    _i2c_txBuffer[add] = data;<br \/>}<br \/><br \/>uint8_t i2cReadBuffer(uint8_t add)<br \/>{<br \/>  if(add &lt; _I2C_RX_BUFFER_MAX_SIZE)<br \/>    return _i2c_rxBuffer[add];<br \/>  return _i2c_rxBuffer[0];<br \/>}<br \/><br \/>void i2cClearNewDataFlag()<br \/>{<br \/>  cli();<br \/>  _i2c_newRxData = 0;<br \/>  sei();<br \/>}<br \/>uint8_t i2cNewDataAvailable()<br \/>{<br \/>  return _i2c_newRxData;<br \/>}<br \/><br \/>void i2cInitSlaveMode(uint8_t add )<br \/>{<br \/>  TWAR = (add&lt;&lt;1) ; \/\/ Place l'adresse du slave + Ne r\u00e9pondra pas sur l'adresse g\u00e9n\u00e9rale<br \/>  TWCR = (1&lt;&lt;TWIE) | (1&lt;&lt;TWEA) | (1&lt;&lt;TWINT) | (1&lt;&lt;TWEN); \/\/ active le ISR et le I2c et le ACK<br \/>  sei();<br \/>}<\/pre>\n<p>Le code complet pour le fichier main.c<\/p>\n<pre>#define F_CPU 16000000<br \/>#include &lt;avr\/io.h&gt;<br \/>#include &lt;util\/delay.h&gt;<br \/>#include \"i2cSlave.h\"<br \/><br \/>uint8_t stateIn = 0;<br \/>uint8_t stateOut = 0;<br \/><br \/>int main(void)<br \/>{<br \/>  i2cInitSlaveMode(8);<br \/>  DDRC |= (1&lt;&lt;7);<br \/>  while (1) <br \/>  {<br \/>    if(PINB &amp; (1&lt;&lt;4))<br \/>      stateOut = 0;<br \/>    else<br \/>      stateOut = 1;<br \/>    i2cWriteBuffer(0,stateOut);<br \/>    if(i2cNewDataAvailable())<br \/>    {<br \/>      stateIn = i2cReadBuffer(0);<br \/>      i2cClearNewDataFlag();<br \/>      if(stateIn &amp; 1)<br \/>        PORTC |= (1&lt;&lt;7);<br \/>      else<br \/>        PORTC &amp;= ~(1&lt;&lt;7);<br \/>    }<br \/>  _delay_ms(1);<br \/>  }<br \/>}<br \/><br \/><\/pre>\n<p>N&rsquo;h\u00e9sitez pas \u00e0 donner vos commentaires et \u00e0 poser vos questions.<\/p>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Dans cet article, nous allons \u00e9changer des donn\u00e9es entre le ESP32 et le\u00a0 Atmega32u4 (Arduino micro) via un lien I2C. Le ESP32 sera programm\u00e9 dans PlatformIO dans le cadre Arduino alors que le Atmega32u4 sera programm\u00e9 sous Atmel studio avec les librairies C de base. Pour les r\u00f4les, le ESP32<span class=\"more-link\"><a href=\"https:\/\/marcjuneau.ca\/?p=413\">Continue Reading<\/a><\/span><\/p>\n","protected":false},"author":1,"featured_media":417,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[12,20,22],"tags":[],"class_list":["entry","author-mjuneau","post-413","post","type-post","status-publish","format-standard","has-post-thumbnail","category-arduino","category-esp32_cat","category-esp32-projets"],"_links":{"self":[{"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=\/wp\/v2\/posts\/413","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=413"}],"version-history":[{"count":14,"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=\/wp\/v2\/posts\/413\/revisions"}],"predecessor-version":[{"id":439,"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=\/wp\/v2\/posts\/413\/revisions\/439"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=\/wp\/v2\/media\/417"}],"wp:attachment":[{"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=413"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=413"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/marcjuneau.ca\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=413"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}