Gérer 2 afficheurs I2C

Bonjour.

J’ai 2 arduinos qui communiquent en I2C. Sur chacun je voudrais gérer 1 afficheur I2C de façon indépendante. J’ai trouvé Bus I2C - MultiMaster + RTC + EEPROM pour m’aider mais j’ai des difficultés.

Pour être plus clair:

  • 2 arduinos qui communiquent
  • 2LCD I2c
  • 1 bus I2C commun à tout le monde.

Dans les faits, le 1er maître gère de façon égale mes 2 afficheurs. Le 2e maître est inexistant.

Le 1er maître:

#include "Wire.h"      // Utilisation du bus I2C
#include "LiquidCrystal_I2C.h"  // Utilisation afficheur1 I2C

LiquidCrystal_I2C LCDA(0x27, 16, 2);   // definition du type d'afficheur 

void setup() {

Wire.begin(50); // join I2C bus as the master
LCDA.init(); // initialisation de l'afficheur
LCDA.backlight();  // éclairage LED afficheur

LCDA.setCursor(1, 0);
LCDA.print(F("Initialisation"));

LCDA.setCursor(1, 1);
LCDA.print(F("batterie"));

Le Wire.begin(50); sert aussi à envoyer des datas vers le 2e arduino.

Wire.beginTransmission(0x08); // informs the bus that we will be sending data to slave device 8 (0x08)
Wire.write(reinterpret_cast<const uint8_t *>(&delesteurData), sizeof delesteurData);
Wire.endTransmission(); // informs the bus and the slave device that we have finished sending data

Le 2e maître

#include "Wire.h"        // Bus I2C
#include "LiquidCrystal_I2C.h"  // Utilisation afficheur I2C
LiquidCrystal_I2C LCDB(0x28, 16, 2);   // definition du type d'afficheur pour ballon

Wire.begin(); // join I2C bus en tant que maître
Wire.onReceive(reception);

Wire.begin(51);
// Ecran LCDB I2C
LCDB.init(); // initialisation de l'afficheur
LCDB.backlight();  // éclairage LED afficheur

LCDB.setCursor(1, 0);
LCDB.print(F("Initialisation"));

LCDB.setCursor(1, 1);
LCDB.print(F(" Ballon "));

Je crois comprendre qu’il faut des interruptions, mais comment faire ?

Bonsoir thierryr51

Une possibilité (que je n'ai jamais essayé) est de créer un bus software avec la bibliothèque:
image

ce qui te permettra, sur le slave, de gérer l'afficheur.

Cordialement
jpbbricole

Merci JP c’est encore une bonne idée. Ça doit être compliquer de gérer 2 maîtres sur un même bus, surtout si les 2 parlent ensemble. Je vais tester ta proposition.

EDIT: LiquidCrystal_I2C semble ne travailler qu’avec Wire. Comment le rediriger vers SoftwareWire ?

Bonjour thierryr51

J'ai posé la question à ChatGPT qui me propose une autre bibliothèque:
image

Ainsi qu'un code de démo que j'ai testé:

/**************************************************
   LCD I2C avec SoftI2CMaster sur Arduino UNO
   SDA = D4
   SCL = D5
**************************************************/

// ===== Configuration SoftI2C =====
#define SDA_PIN 4
#define SCL_PIN 5

// Ports AVR correspondants (UNO)
#define SDA_PORT PORTD
#define SDA_DDR  DDRD

#define SCL_PORT PORTD
#define SCL_DDR  DDRD

#include <SoftI2CMaster.h>

// ===== Adresse I2C du LCD =====
#define LCD_ADDR 0x27   // essayer 0x3F si besoin

// Bits PCF8574 → LCD
#define LCD_RS 0x01
#define LCD_EN 0x04
#define LCD_BL 0x08

uint8_t backlight = LCD_BL;

// =================================================
// Envoi d’un octet au PCF8574
// =================================================
void lcd_write(uint8_t data)
{
  i2c_start(LCD_ADDR << 1);
  i2c_write(data | backlight);
  i2c_stop();
}

// =================================================
// Pulse Enable
// =================================================
void lcd_pulse(uint8_t data)
{
  lcd_write(data | LCD_EN);
  delayMicroseconds(1);

  lcd_write(data & ~LCD_EN);
  delayMicroseconds(50);
}

// =================================================
// Envoi nibble (4 bits)
// =================================================
void lcd_send4(uint8_t nibble, uint8_t mode)
{
  uint8_t data = (nibble << 4) | mode;
  lcd_pulse(data);
}

// =================================================
// Commande LCD
// =================================================
void lcd_command(uint8_t cmd)
{
  lcd_send4(cmd >> 4, 0);
  lcd_send4(cmd & 0x0F, 0);
}

// =================================================
// Écrire un caractère
// =================================================
void lcd_char(char c)
{
  lcd_send4(c >> 4, LCD_RS);
  lcd_send4(c & 0x0F, LCD_RS);
}

// =================================================
// Initialisation LCD
// =================================================
void lcd_init()
{
  delay(50);

  // Séquence init spéciale HD44780
  lcd_send4(0x03, 0);
  delay(5);

  lcd_send4(0x03, 0);
  delayMicroseconds(150);

  lcd_send4(0x03, 0);

  // Mode 4 bits
  lcd_send4(0x02, 0);

  // Config LCD
  lcd_command(0x28); // 2 lignes, 5x8
  lcd_command(0x0C); // Display ON, cursor OFF
  lcd_command(0x06); // Auto increment
  lcd_command(0x01); // Clear
  delay(2);
}

// =================================================
// Position curseur (ligne, colonne)
// =================================================
void lcd_setCursor(uint8_t col, uint8_t row)
{
  uint8_t addr = (row == 0) ? 0x00 : 0x40;
  lcd_command(0x80 | (addr + col));
}

// =================================================
// Afficher une chaîne
// =================================================
void lcd_print(const char *str)
{
  while (*str)
    lcd_char(*str++);
}

// =================================================
// Programme principal
// =================================================
void setup()
{
  // Init bus I2C logiciel
  i2c_init();

  // Init LCD
  lcd_init();

  // Texte ligne 1
  lcd_setCursor(0, 0);
  lcd_print("Bonjour !");

  // Texte ligne 2
  lcd_setCursor(0, 1);
  lcd_print("Soft I2C UNO");
}

void loop()
{
  // Rien à faire
}

Bonne journée!
jpbbricole

Il n’y a pas de possibilité de changer l’adresse I2C de l’un des deux afficheurs ?

Sinon utiliser un multiplexeur I2C (TCA9548A par exemple).

J’ai aussi essayé ce soft. J’ai des erreurs de partout.

/tmp/ccyIh9Bn.s: Assembler messages:
/tmp/ccyIh9Bn.s:313: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:314: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:319: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:325: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:329: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:335: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:338: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:341: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:347: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:351: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:357: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:392: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:398: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:401: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:405: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:410: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:421: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:424: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:428: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:432: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:435: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:441: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:467: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:468: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:470: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:472: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:474: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:505: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:507: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:544: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:546: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:548: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:550: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:552: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:580: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:582: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:812: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:813: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:814: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:815: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:818: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:820: Error: number must be positive and less than 8
/tmp/ccyIh9Bn.s:1068: Error: number must be positive and less than 8
lto-wrapper: fatal error: /home/thierry/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/avr-gcc returned 1 exit status
compilation terminated.
/home/thierry/.arduino15/packages/arduino/tools/avr-gcc/7.3.0-atmel3.6.1-arduino7/bin/../lib/gcc/avr/7.3.0/../../../../avr/bin/ld: error: lto-wrapper failed
collect2: error: ld returned 1 exit status
exit status 1

Compilation error: exit status 1

Je constate que les afficheurs ont une adresse fixe. Ils ne fonctionnent pas avec une autre adresse que 0x27. J’ai donc séparé mes 2 bus i²c et ça fonctionne. Je vais m’atteler à faire communiquer mes 2 arduinos en UART mais pas celui de la console qui me sert en débogage.

C’est physiquement, sur le module I2C/parallèle de l’afficheur, que l’on peut modifier l’adresse… dans la majorité des cas.

Désolé. Je ne vois pas comment, car sur mon module I²c il n’y a pas de jump, ni quoi que ce soit pour paramétrer. Le seul qui existe éteint l’éclairage. C’est tout.

Rien qui ressemble aux petits plots marqués A0 A1 A2 sur ce modèle ?

Toutes mes excuses. Mes yeux ne voient pas assez bien pour les repérer. Je vais essayer… Merci.

Ça fonctionne impeccable. T’as trouvé la solution bravo.

Bonjour. J’ai un circuit:

#include "Wire.h"        // Bus I2C
#include "LiquidCrystal_I2C.h"  // Utilisation afficheur I2C
LiquidCrystal_I2C LCDB(0x26, 16, 2);   // definition du type d'afficheur pour ballon

byte CompteurAffichage = 0;

void setup {

LCDB.init(); // initialisation de l'afficheur
LCDB.backlight();  // éclairage LED afficheur

LCDB.setCursor(1, 0);
LCDB.print(F("Initialisation"));

LCDB.setCursor(1, 1);
LCDB.print(F(" Ballon "));

}

void loop() {

if(CompteurAffichage < 2){
if(Egalisation){
LCDB.setCursor(0, 0);
LCDB.print(F("Ballon arrete "));
LCDB.setCursor(0, 1);
LCDB.print(F("Egalisation batt "));

}    else if(BallonOn){
      LCDB.setCursor(0, 0);
      LCDB.print(F("Ballon en service "));    
      LCDB.setCursor(0, 1);
      LCDB.print(F("consigne: ")); 
      LCDB.print(tpConsigneBallon);
      LCDB.print(F(" deg         ")); 
    } else {
      LCDB.setCursor(0, 0);
      LCDB.print(F("Ballon arrete   "));    
      LCDB.setCursor(0, 1);
      LCDB.print(F("Non prioritaire ")); 
    }
  }  
  if(CompteurAffichage >= 2 && CompteurAffichage < 4) {
    LCDB.setCursor(0, 0);      //"
    LCDB.print(F("DelestageLevel  "));
    LCDB.setCursor(0, 1);
    LCDB.print(DelestageLevel);
    if(ForcageBallon)
      LCDB.print(F(" + Forcage      "));
    else
      LCDB.print(F("                "));
  }// if(CompteurAffichage > 2)
 if(CompteurAffichage >= 4 && CompteurAffichage < 6) {
    if(Chauffage){
      LCDB.setCursor(0, 0);      //"
      LCDB.print(F("Chauffage         "));
      LCDB.setCursor(0, 1);
      if(T1isOn)  LCDB.print(F("Niveau 2       "));
      else        LCDB.print(F("Niveau 1       "));
    } else       {
       LCDB.setCursor(0, 0); 
       LCDB.print(F("Pas_de_chauffage "));
       LCDB.setCursor(0, 1);
       LCDB.print(F("en maison         "));
    }
  }
  if(CompteurAffichage > 6) 
    CompteurAffichage = 0;
  else CompteurAffichage ++;




}  // void loop() 



Au début tout va bien. Puis petit à petit, apparait des sigles bizarres qui finissent par remplir tout l’afficheur. Après environ 1/2 heures, les écritures normales réapparaissent pour un temps.

Mais les sigles bizarres reviennent toujours. ( Pourtant ce n’est pas du Martien )

J’ai essayé un LCDB.clear mais ça ne change rien. Mais qu’aurais je donc oublié ?

Le code est incomplet.

Ce matin je m’aperçois que le javanais est passé sur l’autre écran. C’est donc un problème I²C. Comme il y a 2 maîtres, il doit y avoir télescopage de dialogue. Je vais travailler ce sujet…

Bonjour thierryr51

On en revient à ton post précédent, tu ne peut pas avoir 2 maîtres sur un bus, tes afficheurs ne peuvent gérés que depuis un maître, si tu veux gérer l'afficheur de l'esclave tu dois y ajouter la bibliothèque qui émule un nouvel i2C.

Cordialement
jpbbricole

Si c’est possible, la norme I2C le permet.
Mais il y a un énorme MAIS, il ne peut pas y avoir plusieurs maitres actifs simultanément.

Il y a donc un gros travail de gestion et il n’est pas certain que la bibliothèque dite ”arduino” (appeller l’objet i2c Wire me fait plus penser à ”Wiring” qu’à ”Arduino”) , donc que Two-Wire gere cette possibilité.

posts fusionnés car sur le même sujet

Il y a plusieurs bus de communication sur arduino. Je pourrais donc séparer mes 2 afficheurs et les mettre sur des bus i²c différents. Quant aux arduinos qui communiquent, je pourrais le faire en UART. Mais là ou je m’interroge: Peut-on transmettre une structure en UART ? ( Cependant j’aimerais conserver la console actuelle pour le débogage.)

struct Sdelesteur{
double  TensionBatt;
double  CourantBatt;
bool OnduleurSurSecteur;
int luminosite;
bool PleinHiver;
bool PeriodeHiver;
byte index ;
double niveauBat;

} ;

Bonjour thierryr51

Oui et c'est 64 octets maximum.

Cordialement
jpbbricole

ça veut dire quoi ?

  • Les 2 ne peuvent pas parler ensemble même pour des esclaves différents
  • La réponse doit être lue avant que le 2e ne parle ?