interférence entre écran I2C et détecteur de poussiere

bonsoir,

je souhaite faire un capteur pour mesurer la qualité de l'air en partant sur le modèle du projet Aircitizen, et je rencontre un problème.
Quand je teste l'écran tout seul, ça va.
Quand je teste le capteur tout seul, ça va.
Les 2 dans le meme sketch, bonjour les dégats :confused:

voici mon code :

#include <SoftwareSerial.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

SoftwareSerial pmsSerial(2, 3);

void setup() {
  Serial.begin(9600);
 pmsSerial.begin(9600);
  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

 
}

struct pms5003data {
  uint16_t framelen;
  uint16_t pm10_standard, pm25_standard, pm100_standard;
  uint16_t pm10_env, pm25_env, pm100_env;
  uint16_t particles_03um, particles_05um, particles_10um, particles_25um, particles_50um, particles_100um;
  uint16_t unused;
  uint16_t checksum;
};
struct pms5003data data;

void loop() {
 
  if (readPMSdata(&pmsSerial)) {
    // reading data was successful!
    Serial.println();
    Serial.println("---------------------------------------");
    Serial.println("Concentration Units (standard)");
    Serial.print("PM 1.0: "); Serial.print(data.pm10_standard);
    Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_standard);
    Serial.print("\t\tPM 10: "); Serial.println(data.pm100_standard);
    Serial.println("---------------------------------------");
    Serial.println("Concentration Units (environmental)");
    Serial.print("PM 1.0: "); Serial.print(data.pm10_env);
    Serial.print("\t\tPM 2.5: "); Serial.print(data.pm25_env);
    Serial.print("\t\tPM 10: "); Serial.println(data.pm100_env);
    Serial.println("---------------------------------------");
    Serial.println("---------------------------------------");
 display.clearDisplay();
display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("PM 1.0 :"+ String(data.pm10_standard ));
  display.display();
  }
}

boolean readPMSdata(Stream *s) {
  if (! s->available()) {
    return false;
  }
  
  // Read a byte at a time until we get to the special '0x42' start-byte
  if (s->peek() != 0x42) {
    s->read();
    return false;
  }

  // Now read all 32 bytes
  if (s->available() < 32) {
    return false;
  }
    
  uint8_t buffer[32];    
  uint16_t sum = 0;
  s->readBytes(buffer, 32);

  // get checksum ready
  for (uint8_t i=0; i<30; i++) {
    sum += buffer[i];
  }

  /* debugging
  for (uint8_t i=2; i<32; i++) {
    Serial.print("0x"); Serial.print(buffer[i], HEX); Serial.print(", ");
  }
  Serial.println();
  */
  
  // The data comes in endian'd, this solves it so it works on all platforms
  uint16_t buffer_u16[15];
  for (uint8_t i=0; i<15; i++) {
    buffer_u16[i] = buffer[2 + i*2 + 1];
    buffer_u16[i] += (buffer[2 + i*2] << 8);
  }

  // put it into a nice struct :)
  memcpy((void *)&data, (void *)buffer_u16, 30);

  if (sum != data.checksum) {
    Serial.println("Checksum failure");
    return false;
  }
  // success!
  return true;
   display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
}

J'éia testé de partir de mon code de l'écran, et de rajouter petit a petit les éléments du code du capteur de poussiere.
quand je mets : SoftwareSerial pmsSerial(2, 3); c'est bon
quand je démarre pmsSerial c'est encore bon.
La ou ça va pas c'est quand je remplis la boucle, j'ai l'écran qui n'arrive pas a s'initialiser.
""SSD1306 allocation failed""

est ce que vous savez ce qui cloche ?
merci d'avance

Vous alimentez l’écran depuis la pin 3.3V ? Expliquez comment tout est câblé et quel arduino vous avez pris

Bonjour,

J'alimente tout en 5v car tout fonctionne en 5v.
voici mon écran oled
et mon capteur

et enfin, mon branchement :

l'écran tire 40 à 50mA selon les modèles
le Uno va manger 50mA environ

combien tire votre capteur ? est-ce ce capteur d'Adafruit ?

c'est bien celui là.
j'ai l'impression que c'est un problème dans le code, car branché comme ça, si je teste que la partie écran, c'est bon.
que la partie capteur, c'est bon aussi, et dès que je met le code dans la boucle, l'écran ne s'initialise plus

ewaca:
c'est bien celui là.

OK donc côté consommation ça rentre bien dans ce que peut fournir le port USB

Sinon Vous avez la mauvaise adresse non? le commentaire dit 0x3D et vous avez écrit

if (!display.begin(SSD1306_SWITCHCAPVCC, [color=red]0x3C[/color])) { // Address [color=green]0x3D[/color] for 128x64

sinon que fait le   display.begin(SSD1306_SWITCHCAPVCC, 0x3C);tout au bout du code? (il ne gène pas car après le return, donc jamais exécuté mais c'est pas top)

l'adresse est bien 0x3C, j'ai utilisé un code de scan I2C, et ça me retourne cette adresse.
Encore une fois ça marche très bien quand je teste l'écran et le capteur a part.

Le " display.begin(SSD1306_SWITCHCAPVCC, 0x3C);" a la fin c'est que je me suis dit qu'avec le code complet il n'arrivait plus a initialiser l'écran, du coup j'avais essayé de le mettre a différent endroit du code

postez le code qui fonctionne avec l'écran tout seul

Le " display.begin(SSD1306_SWITCHCAPVCC, 0x3C);" a la fin c'est que je me suis dit qu'avec le code complet il n'arrivait plus a initialiser l'écran, du coup j'avais essayé de le mettre a différent endroit du code

Mouais... la programmation c'est pas un truc au petit bonheur la chance....

si vous mettez le pmsSerial.begin(9600);après l'initialization de l'écran, ça dit quoi?

Avez vous un Arduino Mega ?

si je met le pms Serial.begin(9600); après l'initialisation de l'écran ça dit pareil :
SSD1306 allocation failed

voici le code de l'écran qui fonctionne :

#include <SoftwareSerial.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);




void setup() {
  Serial.begin(9600);

  // SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }

 
}



void loop() {
  display.clearDisplay();
display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.println("Hello, world!");
  display.display();
  delay(2000);
display.setCursor(0,10);
  display.println("bla!");
  display.display();
  delay(2000);
}

sinon, oui la programmation ce n'est pas au petit bonheur la chance, mais étant autodidacte sur ça, il y certaines fois ou des choses ne marchent pas, et en faisant des choses qui me semblent pas spécialement logiques ça fonctionne, après, j'essaye de comprendre pourquoi.

Je ne suis pas loin de penser que c'est un problème de mémoire.
Le display.begin() fait l'allocation d'un buffer de 1ko et retourne false s'il échoue. C'est il me semble le seul cas où begin() retourne un false.
A coté de ça, SoftwareSerial utilise aussi pas mal de mémoire pour son buffer d'entrée/sortie.

visiblement ça doit etre ça.

J'ai fait les branchement sur une mega, avec l'adaptation qu'il faut au niveau des pins pour le software serial, et j'ai bien l'écran qui m'affiche mes données.

je voulais faire ça un arduino nano (meme caractéristiques que le uno) pour avoir quelque chose de plus petit a transporter, mais ça semble rappé ...

J'ai essayé déja avec une nodemcu (esp8266) car plus de memoire qu'une nano, mais j'arrive meme pas a faire le blink avec ...

OK - oui sans doute soucis de SRAM alors.

Si vous utilisez une MEGA vous pouvez dégager le Software Serial et passer par un des autres port Série matériel. Ce sera bcp plus stable.

je voulais faire ça un arduino nano (meme caractéristiques que le uno) pour avoir quelque chose de plus petit a transporter, mais ça semble rappé ...

Si c'est l'encombrement qui vous gêne il existe une version compacte de l'Arduino Mega (Mega 2560 PRO MINI) qu'on trouve entre 6 et 9 euros en asie. (en 3.3V)

megasmall.png

J'ai essayé déja avec une nodemcu (esp8266) car plus de memoire qu'une nano, mais j'arrive meme pas a faire le blink avec ..

Si vous regardez les produits Wemos (Lolin) vous verrez qu'il y a

La LOLIN D1 mini

et dans les shields associés vous trouverez un petit écran OLED qui vous donne 64×48 pixels (avec deux petits boutons A et B pour interagir avec votre projet)


ou un écran TFT de 1.4 pouces couleur de 128x128 pixels.

(ils ont plein d'autres shields associés leur boutique officielle est sur Ali Express)

Si vous voulez rendre le tout portable, vous n'avez pas forcément besoin donc du port série matériel une fois le code téléchargé --> vous pourriez brancher votre capteur sur le port série standard.

megasmall.png

fdufnews:
Je ne suis pas loin de penser que c'est un problème de mémoire.

+1
La librairie SSD1306 consomme pas mal de mémoire RAM.
La compilation d'un simple exemple de la librairie : Les variables globales utilisent 1535 octets (74%) de mémoire dynamique.

Il devrait être possible de conserver la NANO, mais en adoptant un écran plus intelligent, un TFT par exemple : 1.8 pouces ou 1.44 pouces ST7735 ou 1.3 pouces ST7789
La librairie AdaFruit ST7735_ST7789 est deux fois moins gourmande.

J’ai eu un problème similaire avec un écran ssd1306. C’est un problème de mémoire, notamment à cause de la bibliothèque d’adafruit. Il existe des librairies allégées pour ce composant. Dont au moins une redéfinit sa propre liaison i2c. Je n’ai malheureusement pas les références sous la main mais ça ne décrit pas être trop difficile à trouver sur internet.

Je ne sais pas ce que tu fais exactement mais si tu veux juste afficher un chiffre ou un mot, j’ai vu un post sur la possibilité de définir sa propre police avec moins de caractères

merci pour toutes ces infos !
je connaissais pas l'existence de la mega en mini en 3.3v.
Dommage que mon capteur nécessite 5v car quand tout est compatible 3.3v c'est simple de faire quelque chose de portable avec une batterie 18650.

Après l'écran et le capteur de qualité de l'air, j'ai encore un capteur d'humidité a intégrer, et surtout un gps et un lecteur de carte SD
du coup niveau mémoire la nano ne suffira plus je pense.

Sauf si tu adoptes un écran TFT.

je viens de regarder les tft, ils sont plus cher, et j'en ai pas en stock :confused:
du coup je suis tombé sur cette librairie

qui semble consommer beaucoup moins de mémoire, je ferais mes test d'ici quelques jours quand j'aurais un peu de temps.

Pas mal : elle possède beaucoup de polices.

Bonjour,

Je ne connaissais pas cette librairie, elle semble très intéressante car le gros problème des écrans oled avec les librairies adafruit c'est taille de la mémoire ram utilisée.
Et effectivement elle propose un bel assortiment de polices.

Étant actuellement sur un projet sur lequel j'utilise un SSD1306 128x64 je viens d'essayer la librairie en question :

Avec la librairie AdaFruit :
Le croquis utilise 19592 octets (60%) de l'espace de stockage de programmes. Le maximum est de 32256 octets.
Les variables globales utilisent 1574 octets (76%) de mémoire dynamique, ce qui laisse 474 octets pour les variables locales. Le maximum est de 2048 octets.

Avec la librairie Greiman :
Le croquis utilise 13600 octets (42%) de l'espace de stockage de programmes. Le maximum est de 32256 octets.
Les variables globales utilisent 478 octets (23%) de mémoire dynamique, ce qui laisse 1570 octets pour les variables locales. Le maximum est de 2048 octets.

En ce qui concerne l'occupation mémoire, surtout RAM, il n'y a pas photo. Elle est clairement plus légère.
Par contre elle n'est pas capable de placer du texte en Y au pixel près.

Deuxièmement le principe est très différent.

La librairie AdaFruit travaille avec un espace mémoire interne à la librairie.

  • on efface la zone tampon avec clearDisplay()
  • on écrit avec print(), drawRect(), fillRect(), etc.
  • on affiche avec display()

La librairie Greiman travaille en direct avec l'écran

  • on n'efface pas
  • on écrit avec print() et l'affichage est fait dans la foulée
  • pas besoin d'effacer avant de réécrire par dessus un message précédent
    Il n'y a pas de routines graphiques

Par exemple pour afficher un indicateur de capacité batterie avec la librairie AdaFruit on peut le faire avec drawRect(), fillRect(), etc.

Avec la librairie Greiman on peut passer par une police de caractères spéciale. J'en ai réalisé une assez facilement :

GLCDFONTDECL(Batt6x14) = {
  0x0, 0x0, // size of zero indicates fixed width font,
  6,     // width
  14,     // height
  0x20,  // first character
  7,       // n characters
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // space
  0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0x3f, 0x20, 0x20, 0x20, 0x20, 0x3f, // Battery Empty
  0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0x3f, 0x38, 0x38, 0x38, 0x38, 0x3f, // Battery 20%
  0xff, 0x01, 0x01, 0x01, 0x01, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, // Battery 40%
  0xff, 0xc1, 0xc1, 0xc1, 0xc1, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, // Battery 60%
  0xff, 0xf1, 0xf1, 0xf1, 0xf1, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, // Battery 80%
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x3f, // Battery 100%
};

Il suffit d'afficher le caractère ESPACE + 1 + round(capacité / 20) pour afficher les caractères 0x21 à 0x26.
Le premier caractère (0x20 ESPACE) sert à effacer dans le cas où l'on veut faire clignoter l'indicateur.

Conclusion : plutôt pas mal.
Avec la librairie AdaFruit la limitation mémoire RAM est très contraignante, ce qui la cantonne aux petits projets.
Elle m'a déjà obligé à changer d'écran pour un TFT du genre ST7735 ou ILI9341.

La librairie Greinman permet d'envisager des projets beaucoup plus lourds.