Problema Arduino nano con dos pantallas OLED SSD1306 - SOLUCIONADO

Buenas a todos!
He montado un circuito de prueba con un arduino nano con dos pantallas ssd1306 (128x64 pixel) conectadas mediante I2C a través de unmultiplexor PCA 9548.
El sistema funciona bien, salvo en un tema: el aspecto del texto que muestra aparece como desdibujado,como si tuviera líneas negras intercaladas entre las blancas que forman los caracteres, como si se mostrara en una pantalla de menor resolución.
Sin embargo, con la misma librería (de Adafruit) con una sola pantalla, los caracteres se ven nítidos y bien definidos.
¿Alguien sabe a que puede deberse esta pérdida de calidad?
Gracias de antemano.

Os adjunto el programa:


#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_Address 0x3C
#define OLED_RESET 4
Adafruit_SSD1306 oled0(OLED_RESET);
Adafruit_SSD1306 oled1(OLED_RESET);

#include "Wire.h"
#define TCAADDR 0x70
#define SCREEN_WIDTH 128 // OLED ancho display
#define SCREEN_HEIGHT 64 // OLED alura display


void pantalla(uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission(); 
}

void setup()
{
Wire.begin();
pantalla(0);
oled0.begin(SSD1306_SWITCHCAPVCC, OLED_Address);
pantalla(1);
oled1.begin(SSD1306_SWITCHCAPVCC, OLED_Address);

}

void loop() 
{

  pantalla(0); // Texto en pantalla 0

  oled0.clearDisplay();
  oled0.setTextColor(WHITE);
  oled0.setCursor(0,0);
  oled0.setTextSize(2);
  oled0.print("PANTALLA 0");
  oled0.display();
  
  pantalla(1);//Texto en pantalla 1

  oled1.clearDisplay();
  oled1.setTextColor(WHITE);
  oled1.setCursor(0,0);
  oled1.setTextSize(2);
  oled1.print("PANTALLA 1");
  oled1.display();
}

Hi,
Tienes instaladas las resistencia de 10K al clk y al sda. Lee el voltaje cuando tienes una instalada y cuando instalas la segunda. Posiblemente el voltage al bajar puede causar problemas en el display.

Gracias por tu respuesta.
Si, al principio lo probé sin ellas, pero para descartar posibles problemas las equipé en la alimentación y las líneas SD y SC que salen del multiplexor a cada una de las pantallas. En la línea a SDA y SCL del arduino no son necesarias ya que poseen sus resistencias de pullup.

Y por que en cada loop borras la pantalla 0 y la 1? Eso no lo haces cuando la ves individualmente de modo que tu prueba no es la misma.
Aprende a trabajar sin usar borrado total de pantalla y en su defecto maneja el ancho a imprimir similar usando un buffer y escribe ahi si todo con lo que se modifique pero solo eso, en la linea que corresponda y no generar un parpadeo y por ende una perdida de calidad o nitidez.

Tienes razón. Se me quedó ahí de hacer pruebas.
Pero aunque quite el borrado del loop y solo borre la pantalla en el setup, sigue el mismo problema.

Cuando tengo el circuito con una sola pantalla, la parte del programa que corresponde a la pantalla es casi igual. Es posible que haya algo obvio que se me está pasando:

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


#define ANCHO 128			
#define ALTO 64				
#define OLED_RESET 4			
Adafruit_SSD1306 oled(ANCHO, ALTO, &Wire, OLED_RESET);	


[...]


oid setup() {

  Serial.begin(57600);

  Wire.begin();					
  oled.begin(SSD1306_SWITCHCAPVCC, 0x3C);	
  oled.display();

[...]

void loop() {

[...]

if (digitalRead(10)== HIGH){

  oled.clearDisplay();	
  oled.setTextColor(WHITE);	
  oled.setCursor(5, 00);			
  oled.setTextSize(2);	  
  oled.print("N. palas: "); 
  oled.setTextSize(2);
  oled.setCursor(115, 00);
  oled.print(palas); 
  oled.setCursor(5, 25);			
  oled.setTextSize(2);	  
  oled.print("Pulse para medir "); 
  oled.display(); 
  valormaximo = 0;
  valor = 0;
  contador=0;

[...]

Y en este caso funciona sin problemas. Si no fuera porque el driver es el mismo, diría que ha cogido la versión para la pantalla de 32 líneas verticales.

Os adjunto dos imágenes que muestran lo que digo.


Según los comentarios de la propia librería no debería influir pero por si acaso...
Prueba editar el archivo Adafruit_SSD1306.h y comenta esta línea

#define SSD1306_128_32 ///< DEPRECATED: old way to specify 128x32 screen

Gracias. Lo he probado, y no ha funcionado, sino que además, aunque guardé el archivo .h original, me ha tocado reinstalar la librería (!). Debe detectar la fecha de modificación o algo así.

He probado a ejecutar el I2scanner, y me muestra este resultado:

Scanning...

I2C device found at address 0x3C !
I2C device found at address 0x70 !
done

¿No debería aparecer solo el multiplexor en la dirección 0x70?

He reordenado un poco las definiciones de cabecera, por si influia, y ahora si que la pantalla en el canal0 del multiplexor muestra la fuente del tamaño y aspecto adecuados, pero con un molesto parpadeo, como si los caracteres corrieran de arriba a abajo.

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

#define OLED_Address 0x3C
#define OLED_RESET 4
#define SCREEN_WIDTH 128 // OLED ancho display
#define SCREEN_HEIGHT 64 // OLED alura display

Adafruit_SSD1306 oled0(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 oled1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define TCAADDR 0x70

void pantalla(uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission(); 
}

void setup()
{
Wire.begin();
pantalla(0);
oled0.begin(SSD1306_SWITCHCAPVCC, OLED_Address);

pantalla(1);
oled1.begin(SSD1306_SWITCHCAPVCC, OLED_Address);

oled0.clearDisplay();
oled1.clearDisplay();
}

void loop() 
{

  pantalla(0); // Texto en pantalla 0

  //oled0.clearDisplay();
  oled0.setTextColor(WHITE);
  oled0.setCursor(0,0);
  oled0.setTextSize(2);
  oled0.print("PANTALLA 0");
  oled0.display();
  
  pantalla(1);//Texto en pantalla 1

  //oled1.clearDisplay();
  oled1.setTextColor(WHITE);
  oled1.setCursor(0,0);
  oled1.setTextSize(2);
  oled1.print("PANTALLA 1");
  oled1.display();
}

¿Por qué usas un multiplexor?
¿La placa no tiene un pad para cambiar la dirección (de 0x3C a 0x3D)?

Supongo que "ve" una de las placas conectadas al multiplexor (probablemente la del canal 0).

No, esas SSD1306 no tienen la posibilidad de cambiar la dirección.
He probado a ve si se trataba de algún problema de las fuentes de texto por defecto, pero solo he conseguido sacar garabatos. :frowning:

Esto no deja de asombrarme.
He cambiado el código para hacer unas pruebas. Si le pongo la línea de definición:
Adafruit_SSD1306 oled(SCREEN_WIDTH,SCREEN_HEIGHT, &Wire, OLED_RESET);
Me saca la pantalla como si fuera de 32 líneas en lugar de 64, y el texto se ve bien.

Si la cambiamos por:
Adafruit_SSD1306 oled(OLED_RESET);
Obtenemos las pantallas completas con el texto "difuminado".

Curiosamente, en ambos casos, el texto parece superpuesto en PANTALLA 0 Y PANTALLA 1.


Hi,
Donde en el sketch tu cambias los canales de las pantallas en el multiplexer. No se supone que antes de enviar informacion tu cambies el canal en el multiplexer para enviar la informacion.

Cambia el canal con la función pantalla().

Sigo sin tener clara la solución, pero ya veo por donde va el problema.
La imagen con el texto más claro y definido, de tamaño 2, corresponde a la aplicación corriendo en un prototipo con una sola pantalla.
La imagen con el texto más pequeño, en el prototipo con dos pantallas que estamos comentando. He tenido que bajar el tamaño a 1, para que cupiera en la pantalla.
Pero lo importante, es que el texto "Pulse para medir" no lo he cambiado de ubicación, y está en (x,y) 5, 25. Como podeís ver, cerca del borde inferior:
Por algún motivo que no consiguo entender,
está utilizando la pantalla como si fuera una de 128x32 líneas.


Hi,

MaximoEsfuerzo) muchas gracias le pase por encima.

Hi,
Yo estuve mirando la data del PCA 9548 y creo que no estas selecionando los canales correctamente. Primero tienes que enviar un caracter que es fijo = E seguido de los bits que selecionan el address A0 A1 A2 = 0 y el ultimo bit es para escribir = 0 para leer = 1. En otras palabra debes mandar un byte como sigue 0xE0. Una vez que envias este caracter entonces tienes que envia el canal que vaz a selecionaar que =1. Una vez que hagas esto ya puedes enviar la informacion a la tarjeta seleccionada. Si quires verificar esta informacion lee la pagina 6 de la data del PCA9546 Adjunto link.

[PCA 9548. - Google Search]

Gracias por tu respuesta. No se, la verdad. He visto que en las aplicaciones que he mirado de ejemplo, en ninguna se usa las direcciones A0-A2. Estoy usando esta aplicación, que configura el PCA9548 a la dirección 0x70.
Si hay algo que me revienta, es que montando el mismo circuito y con el mismo programa, las cosas no anden bien.

Se supone que el objeto "pantalla" inicializa las comunicaciones:.

void tcaselect(uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission(); 

Disculpa!

Me he equivocado. Este es el objeto:

void pantalla(uint8_t i) {
  if (i > 7) return;
  Wire.beginTransmission(MULT_Address);
  Wire.write(1 << i);
  Wire.endTransmission(); 

Hi,
Ahora yo veo el problema de que los mensajes salen en una pantalla y es que no estas selecionando la pantaiia. Yo escribi una routina para que la prubes usandoel formato de la pagina 6. Adjunto el sketch para que lo prueves

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_Address 0x3C
#define OLED_RESET 4
#define SCREEN_WIDTH 128 // OLED ancho display
#define SCREEN_HEIGHT 64 // OLED alura display
Adafruit_SSD1306 oled0(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 oled1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define pantalla_1 0x01
#define pantalla_2 0x02
byte PCA_add_write = 0xE0;   //E+address=000+write=0 = data to send= 0xE0 
//**************************************************************
void setup() {
  // put your setup code here, to run once:
  Wire.begin();
  Serial.begin(115200);
  oled0.begin(SSD1306_SWITCHCAPVCC, OLED_Address);
   oled1.begin(SSD1306_SWITCHCAPVCC, OLED_Address);

}
//**************************************************************
void loop() {
  // put your main code here, to run repeatedly:
  //************ select pantalla 0
  sel_pantalla(0);
  oled0.setTextColor(WHITE);
  oled0.setCursor(0,0);
  oled0.setTextSize(2);
  oled0.print("PANTALLA 0");
  oled0.display();
  delay(1000);
  //************ select pantalla 1
  sel_pantalla(1);
  oled1.setTextColor(WHITE);
  oled1.setCursor(0,0);
  oled1.setTextSize(2);
  oled1.print("PANTALLA 1");
  oled1.display();
  delay(1000);
}
//**************************************************************
void sel_pantalla(byte num) {
  if (num == 0) {
    Wire.beginTransmission(PCA_add_write);  //seleciona panatalla 0
    Wire.write(pantalla_1);                 //seleciona canal 0                                //selecciona canal 0
    Wire.endTransmission();
  }
  if (num == 1) {
    Wire.beginTransmission(PCA_add_write);  //seleciona panatalla 1
    Wire.write(pantalla_2);                 //selecciona canal 1
    Wire.endTransmission();
  }
}
//***************************************************************************

Gracias por tu idea.
Tampoco funciona. Empiezo a pensar si las pantallas que compré puedan tener algún problema.
Esto es resultado de hacer correr tu programa.

Hi,
El problema es que no esta cambiando al canal 1. Cuando prendes el systema automaticamente va al canal 0 por eso siempre sale el mensaje bien en la panatalla uno. Le hice uu cambio para que haga un begin a la pantalla 2. Tratala para ver si trabaja.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define OLED_Address 0x3C
#define OLED_RESET 4
#define SCREEN_WIDTH 128 // OLED ancho display
#define SCREEN_HEIGHT 64 // OLED alura display
Adafruit_SSD1306 oled0(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Adafruit_SSD1306 oled1(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define pantalla_1 0x01
#define pantalla_2 0x02
byte PCA_add_write = 0xE0;   //E+address=000+write=0 = data to send= 0xE0 
//**************************************************************
void setup() {
  // put your setup code here, to run once:
  Wire.begin();
  Serial.begin(115200);
  oled0.begin(SSD1306_SWITCHCAPVCC, OLED_Address);
  oled1.begin(SSD1306_SWITCHCAPVCC, OLED_Address);

}
//**************************************************************
void loop() {
  // put your main code here, to run repeatedly:
  //************ select pantalla 0
  sel_pantalla(0);
  oled0.begin(SSD1306_SWITCHCAPVCC, OLED_Address);
  oled0.clearDisplay();
  oled0.setTextColor(WHITE);
  oled0.setCursor(0,0);
  oled0.setTextSize(2);
  oled0.print("PANTALLA 0");
  oled0.display();
  delay(1000);
  //************ select pantalla 1
  sel_pantalla(1);
  oled1.begin(SSD1306_SWITCHCAPVCC, OLED_Address);
  oled1.clearDisplay();
  oled1.setTextColor(WHITE);
  oled1.setCursor(0,0);
  oled1.setTextSize(2);
  oled1.print("PANTALLA 1");
  oled1.display();
  delay(1000);
}
//**************************************************************
void sel_pantalla(byte num) {
  if (num == 0) {
    Wire.beginTransmission(PCA_add_write);  //seleciona panatalla 0
    Wire.write(pantalla_1);                 //seleciona canal 0                                //selecciona canal 0
    Wire.endTransmission();
  }
  if (num == 1) {
    Wire.beginTransmission(PCA_add_write);  //seleciona panatalla 1
    Wire.write(pantalla_2);                 //selecciona canal 1
    Wire.endTransmission();
  }
}
//****************************************************************