Two oled displays with u8glib and TCA9548A

Hi all...
I'm working on one project and I need help.
I'm using arduino nano, two 0.96'' i2c oled displays and tca9548a multiplexer and trying to show some text on both oleds but I can't manage to do it. Can somebody give me the basic code for that setup for 2 oleds?

Welcome to the forum.

Do you have enough memory for two OLED displays ?
You could use the U8x8 option from the u8g2 library. There are also smaller libraries for OLED displays.

You need two objects, one for each display. Set the I2C channel before using a OLED. Both OLED displays must be initialized.

Show us your sketch between code tags. The <code/> button is for code tags.

Have you been using ChatGPT ? :rofl:

Here is the code that I have for one screen

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE|U8G_I2C_OPT_DEV_0);
//---------------------------------------------------------------------------
#include <SoftwareSerial.h>
#define rxPin 2
#define txPin 3 //unused
SoftwareSerial neogps(rxPin,txPin);

#include <TinyGPS++.h> //1.0.3
TinyGPSPlus gps;
//---------------------------------------------------------------------------
int x_max    = 128;       //OLED display width, in pixels
int y_max    = 62;        //OLED display width, in pixels
int x_center = x_max/2;
int y_center = y_max/2+10;
int arc      = y_max/2;
int angle    = 0;
//---------------------------------------------------------------------------
int needle_pos = 0;
u8g_uint_t xx  = 0;
//---------------------------------------------------------------------------
//satellite logo
#define sat_logo_width 20
#define sat_logo_height 20

const unsigned char sat_logo[] = {
  0x00, 0x01, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x06, 0x00, 0x60, 0x30, 0x00,
  0x60, 0x78, 0x00, 0xc0, 0xfc, 0x00, 0x00, 0xfe, 0x01, 0x00, 0xff, 0x01,
  0x80, 0xff, 0x00, 0xc0, 0x7f, 0x06, 0xc0, 0x3f, 0x06, 0x80, 0x1f, 0x0c,
  0x80, 0x4f, 0x06, 0x19, 0xc6, 0x03, 0x1b, 0x80, 0x01, 0x73, 0x00, 0x00,
  0x66, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x70, 0x00, 0x00
};
//---------------------------------------------------------------------------

//Program variables
double lat;
double lng;
//int day, month, year;
String hour, minute;
int second;

int num_sat, speed;
String heading;


/*******************************************************************************************
 * gauge function
 * dispay gauge and other gps data on oled
*******************************************************************************************/
void gauge(uint8_t angle) {
  //fonts: u8g_font_chikita - u8g_font_04b_03br
  // u8g_font_orgv01 - u8g_font_freedoomr10r
  u8g.setFont(u8g_font_chikita);
  //---------------------------------------------------------------------------
  // draw border of the gauge
  u8g.drawCircle(x_center,y_center,arc+6, U8G_DRAW_UPPER_RIGHT);
  u8g.drawCircle(x_center,y_center,arc+4, U8G_DRAW_UPPER_RIGHT);
  u8g.drawCircle(x_center,y_center,arc+6, U8G_DRAW_UPPER_LEFT);
  u8g.drawCircle(x_center,y_center,arc+4, U8G_DRAW_UPPER_LEFT);
  //---------------------------------------------------------------------------
  // show gauge values
  u8g.drawStr(20,  42, "0");   
  u8g.drawStr(18,  29, "25");
  u8g.drawStr(28,  14, "50");
  u8g.drawStr(60,  14, "100");
  u8g.drawStr(91,  14, "150");
  u8g.drawStr(101, 29, "175");
  u8g.drawStr(105, 42, "200"); 
  //---------------------------------------------------------------------------
  // show gauge label
  u8g.setPrintPos(54,25);
  u8g.print("km/h");
  u8g.setPrintPos(50,32);
  u8g.print("SPEED");
  //---------------------------------------------------------------------------
  // draw the needle
  float x1=sin(2*angle*2*3.14/360);           
  float y1=cos(2*angle*2*3.14/360); 
  u8g.drawLine(x_center, y_center, x_center+arc*x1, y_center-arc*y1);
  u8g.drawDisc(x_center, y_center, 5, U8G_DRAW_UPPER_LEFT);
  u8g.drawDisc(x_center, y_center, 5, U8G_DRAW_UPPER_RIGHT);
  //---------------------------------------------------------------------------
  //TOP LEFT: draw satellite logo and number of satellites
  u8g.drawXBM(0, 0, sat_logo_width, sat_logo_height, sat_logo);
  u8g.setPrintPos(18, 5);
  u8g.print(num_sat, 5);
  //---------------------------------------------------------------------------
  //TOP RIGHT: Display direction
  u8g.setPrintPos(110, 5);
  u8g.print(heading);
  //---------------------------------------------------------------------------
  //Display latitude and longitude
  u8g.setPrintPos(0, 55);
  u8g.print(lat, 4);
  u8g.setPrintPos(0, 62);
  u8g.print(lng, 4);
  //---------------------------------------------------------------------------
  //Display time
  u8g.setFont(u8g_font_freedoomr10r);
  u8g.setPrintPos(90, 65);
  u8g.print(hour);
  
  if(second%2 == 0) 
    {u8g.drawStr(104, 65, ":");}
  else
    {u8g.drawStr(104, 65, " ");}
    
  u8g.setPrintPos(111, 65);
  u8g.print(minute);
  
  //u8g.drawStr(90, 65, "00:00");
  //---------------------------------------------------------------------------
  // Show Speed and align its position
  u8g.setFont(u8g_font_profont22);
  u8g.setPrintPos(54,60);
  if (speed<10){                              
    u8g.print("0");
  }
  if (speed>99) {                                  
    u8g.setPrintPos(47,60);
  }
  u8g.print(speed);
  //---------------------------------------------------------------------------
}

/*******************************************************************************************
 * gauge function
 * dispay gauge and other gps data on oled
*******************************************************************************************/
int i = 200;
void setup(void) {
  Serial.begin(9600);

  neogps.begin(9600);
  
  u8g.setFont(u8g_font_chikita);
  u8g.setColorIndex(1);
}

/*******************************************************************************************
 * gauge function
 * dispay gauge and other gps data on oled
*******************************************************************************************/
void loop(void){
  //----------------------------------------------------------
  Read_GPS();
  //----------------------------------------------------------
  needle_pos = map(speed,0,200,0,90); //SET NEEDLE
  // show needle and dial
  xx = needle_pos;                                    
  if (xx<45)
    {xx=xx+135;}
  else
    {xx=xx-45;} 
  //----------------------------------------------------------
  //Display Data on Oled
  {
    u8g.firstPage(); 
    do {             
      gauge(xx);
    }
    while( u8g.nextPage() );
  }
  //----------------------------------------------------------
}




void Read_GPS(){
  //------------------------------------------------------------------
  boolean newData = false;
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (neogps.available())
    {
      if (gps.encode(neogps.read()))
      {
        newData = true;
        break;
      }
    }
  }
  //------------------------------------------------------------------
  //If newData is true
  if(newData == true){
    newData = false;
    Get_GPS();
  }
  else { 
    //no data
  }
}

void Get_GPS(){
  num_sat = gps.satellites.value();

  if (gps.location.isValid() == 1) {
    speed = gps.speed.kmph();
    //Serial.print("Speed: ");Serial.println(gps_speed);
    lat = gps.location.lat();
    //Serial.print("lat: ");Serial.println(lat);
    lng = gps.location.lng();
    //Serial.print("lng: ");Serial.println(lng);
    heading = gps.cardinal(gps.course.value());
    //Serial.print("heading: ");Serial.println(heading);
  }
  
  if (gps.time.isValid()){
    hour = String(gps.time.hour());
    hour = (hour.length() == 1) ? "0"+hour : hour;
    
    minute = String(gps.time.minute());
    minute= (minute.length() == 1) ? "0"+minute : minute;
    
    second = gps.time.second();
  }
}

This code works fine on one screen but I want to display some informations from it on one screen and some informations on other screen. Since both screens have same address that could not be changed I'm using multiplexer.

Each OLED display needs it own object. The object for the display is called "u8g" in your sketch. You need two of these:

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0);

In setup(), you have to use any initialization for both.

I see no code for the I2C multiplexer.
Adafruit has the best tutorials: https://learn.adafruit.com/adafruit-tca9548a-1-to-8-i2c-multiplexer-breakout/overview

Arduino Nano + two OLED display + SoftwareSerial + TinyGPS++ :scream:
You might run into memory problems.

Adafruit has a function "freeMemory()": https://learn.adafruit.com/memories-of-an-arduino/measuring-free-memory#sram-370031
You could call it at the end of setup() and print it to the Serial Monitor.

I tryed to add two objects and name them u8g and u8g1 but still didn't manage to initialize them both.

Make a minimal sketch that only shows "Hello" on both OLED displays. Show the sketch. Make a drawing of how it is wired or make a schematic. Show a photo.

Thanks for help...
Using chatGPT I managed to make them work. Here is the working code in case that somebody need it.

#include <Wire.h>
#include "U8glib.h"
#include <SoftwareSerial.h>
#define rxPin 3
#define txPin 4 //unused
SoftwareSerial neogps(rxPin,txPin);

#include <TinyGPS++.h> //1.0.3
TinyGPSPlus gps;

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);  // Initialize U8glib instance

#define TCA9548A_ADDRESS 0x70  // I2C address of the TCA9548A multiplexer

String hour, minute;
int second;
int num_sat, speed;

#define sat_logo_width 20
#define sat_logo_height 20

const unsigned char sat_logo[] = {
  0x00, 0x01, 0x00, 0x80, 0x07, 0x00, 0xc0, 0x06, 0x00, 0x60, 0x30, 0x00,
  0x60, 0x78, 0x00, 0xc0, 0xfc, 0x00, 0x00, 0xfe, 0x01, 0x00, 0xff, 0x01,
  0x80, 0xff, 0x00, 0xc0, 0x7f, 0x06, 0xc0, 0x3f, 0x06, 0x80, 0x1f, 0x0c,
  0x80, 0x4f, 0x06, 0x19, 0xc6, 0x03, 0x1b, 0x80, 0x01, 0x73, 0x00, 0x00,
  0x66, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x70, 0x00, 0x00
};

void initializeDisplay() {
  Wire.beginTransmission(TCA9548A_ADDRESS);
  Wire.write(1 << 2);  // Enable the second channel (SC2, SD2) of the multiplexer
  Wire.endTransmission();

  u8g.setFont(u8g_font_unifont);
  u8g.setFontRefHeightAll();
  u8g.setFontPosTop();
}

void gauge(void) {
  u8g.setFont(u8g_font_chikita);

  // show gauge label
  u8g.setPrintPos(54,61);
  u8g.print("km/h");

  //TOP LEFT: draw satellite logo and number of satellites
  int num_sat, speed;
  u8g.drawXBM(0, 0, sat_logo_width, sat_logo_height, sat_logo);
  u8g.setPrintPos(18, 5);
  u8g.print(num_sat, 5);

  // Show Speed and align its position
  u8g.setFont(u8g_font_profont29);
  u8g.setPrintPos(54,45);
  if (speed<10){                              
    u8g.print("0");
  }
  if (speed>99) {                                  
    u8g.setPrintPos(47,60);
  }
  u8g.print(speed);
}

void displayClock() {
  // u8g.setFont(u8g_font_freedoomr10r);
  u8g.setPrintPos(30, 40);
  u8g.print(hour);
  
  if(second%2 == 0) 
    {u8g.drawStr(59, 38, ":");}
  else
    {u8g.drawStr(59, 38, "  ");}
    
  u8g.setPrintPos(71, 40);
  u8g.print(minute);
}

void setup() {
  Wire.begin();
  initializeDisplay();
  // Serial.begin(9600);
  neogps.begin(9600);
}

void loop() {
  Read_GPS();
  Wire.beginTransmission(TCA9548A_ADDRESS);
  Wire.write(1 << 2);  // Enable the second channel (SC2, SD2) of the multiplexer
  Wire.endTransmission();

  u8g.firstPage();
  do {
    gauge();
  } while (u8g.nextPage());

  Wire.beginTransmission(TCA9548A_ADDRESS);
  Wire.write(1 << 3);  // Enable the third channel (SC3, SD3) of the multiplexer
  Wire.endTransmission();

  u8g.firstPage();
  do {
    displayClock();
  } while (u8g.nextPage());
  delay(1000);
}

void Read_GPS(){
  boolean newData = false;
  for (unsigned long start = millis(); millis() - start < 1000;)
  {
    while (neogps.available())
    {
      if (gps.encode(neogps.read()))
      {
        newData = true;
        break;
      }
    }
  }
  if(newData == true){
    newData = false;
    Get_GPS();
  }
  else {}
}

void Get_GPS(){
  num_sat = gps.satellites.value();

  if (gps.location.isValid() == 1) {
    speed = gps.speed.kmph();
  }
  
  if (gps.time.isValid()) {
    int currentHour = gps.time.hour();
    currentHour += 2;  // Adding 2 hours to the current hour

    if (currentHour >= 24) {
      currentHour -= 24;  // Wrap around if the hour exceeds 23
    }
    
    hour = String(currentHour);
    hour = (hour.length() == 1) ? "0" + hour : hour;

    minute = String(gps.time.minute());
    minute = (minute.length() == 1) ? "0" + minute : minute;

    second = gps.time.second();
  }
}

Everything is working fine with that code. Only thing that I need to do now is to use some other arduino with more memory because fonts are to small for my needs.

I asked: "Have you been using ChatGPT" because of the way you asked for code. ChatGPT to generate code is not good, it is bad.

If you are serious about finishing your project, then throw away what you have now and start again.
You need two objects for the displays, which you still don't have. Have you read the tutorial about the I2C multiplexer ? and why didn't you add the "freeMemory()" function ?

A single object can be used for multiple displays, here is a discussion about using five displays with a shared buffer
https://forum.arduino.cc/t/u8g2-oled-multiplexing-with-tca9548a/1058114

A few notes on that code:
It uses U8g2 instead of U8glib.

begin() is called for each display. U8g2 does not allocate the buffer in begin(), that is done from the constructor. begin() performs any needed initialization of the display controller, clears the display, and turns the display on.

The constructor is wrong, it specifies software I2C when it should be hardware I2C (this was the solution for the problem the OP was having).

The sketch uses a full buffer, a page buffer will use less ram and will use the firstPage()/nextPage() loop similar to U8glib.

1 Like

Ooooh, I think you are right. There is not much going on in the object of the u8glib.
It might be possible. If the font and position are set every time when using a display, then even different fonts are possible. As far as I know, it is not officially allowed.

@deki4679 It might work what you have. I take back what I wrote. Sorry.

Look, I'm just beginer in arduino world, so I just wanted code that is working. Fill free to change code and optimize it to be smaller if that is possible. Anyways thank you all for sugestions.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.