Controlling images displayed on mini OLED screens using a rotary switch selector

Hi all

Further to my DIY simulator car and plane cockpit, one of the problems I have had is where certain buttons perform different tasks on certain multi use panels depending on the game you are playing, but of course you can only label them as one thing physically.

It is easy enough to set a small OLED screen in the panel adjacent to the button in question, and have it display an icon or text string to show the funtion of the button, and an arduino can do that on multiple i2C devices using a multiplexer - I've used these items before successfully on other parts of my sim rig. I've even seen how they could be used as the actual switch buttons by careful fixing and using SMD switches under them.

However to change from one sim to another requires reprogramming the Arduino, which while it is not a major hassle, doesn't make the best use.

What I wondered was whether you are able to have the arduino program read the output from a rotary switch, and depending on the position selected display a preset set of images or text. The actual button function is handled by a separate joystick controller board and the game you play will assign the control accordingly, so that bit is covered. However if I select game A, I want to set the selctor to position 1, and the appropiate icons apear next to their designated button.

How could that be achieved?

Cheers

Les

You want to use some sort of selector switch to set a state (or profile) in the Arduino. On the basis of that state, you want to display appropriate messages on the OLED screens to indicate the function of adjacent buttons. Is that so ? Then you have several options. A simple one is a potentiometer or you could use a rotary encoder or even a rotary switch, depending on how many pins you have available. Your sketch would use these to set the value of a variable and the part responsible for controlling the displays would use this variable to determine the text to display.

For this below, you would actually press on the glass face of the OLED display ?

i've even seen how they could be used as the actual switch buttons by careful fixing and using SMD switches under them.

Thanks, so if I understand it, on the basis of using a four way rotary switch (or even four separate press switches) I would assign each switch input to an input pin and assign the pin as a variable? I would then make a preset 'library' of the different sets of icons that the variable woud refer to? I imagine that just making named .bmp files would be easier to manage. What would the sketch argument be that states 'for variable 1 use library X' - would an array do this?

With regard to the OLED being used as the buttons, by facing them with clear acrylic, and a shaped plastic layer underneath them that is allowed to bend in a specific place to act like a hinge, they can be made into the buttons. Of course, they are not heavy duty buttons, you could not use them on a game pad. But as a fascia mounted switch that does not require frequent use or force, they work.

Les

I think you've understood it. Setting a variable based on a switch setting (or multiple switch settings) is not difficult. Neither is making what is displayed on a display dependent on a variable. The number of free pins on the Arduino affects your choice of input device. I'd probably use a rotary encoder (which needs 2 pins) and a potentiometer if I had only one free (analog input) pin.

For the data structure in the sketch, I'd probably define a struct designed to represent all the text and/or icons to be displayed for a single simulation. Then create an array of that struct for each specific simulation. The selection by the user choses the particular struct out of the array appropriate to the required simulation.

Thanks again

I would be looking at four or maybe five input pins, and then up to eight i2C OLEDS; as the i2C OLEDS are the same I would have to use the multiplexer as they all have the same address and can't be changed. That means from a mental tally that I would be using five digital pins, +5v, GND, A5 and A4. I am reasonably sure a Nano could handle it, as the.bmp library would not have to hold that many .bmps, and that way I would avoid text libraries, and keep the memory use down

Les

6v6gt: For the data structure in the sketch, I'd probably define a struct designed to represent all the text and/or icons to be displayed for a single simulation. Then create an array of that struct for each specific simulation. The selection by the user choses the particular struct out of the array appropriate to the required simulation.

Might be worth making that a 2D array of structs.

wildbill: Might be worth making that a 2D array of structs.

Hi Wildbill, can you expand on that a little for my understanding? Another related question - does it matter if the switch pins are pin to GND or pin to 5V? I can do either but am just thinking ahead to PCB design. I also assume a 10K resistor would have to be used if the pin was to 5v Cheers

Les

If each struct contains the wherewithal to specify what is to be put on a single display, you need an array of eight of them to account for the number you have.

But, you need them to vary across different games so you need eight per game. If you have four games you can have four different arrays but you might as well organize them into one:

struct mystruct
{
int a,b;  
};

mystruct s[8][4];

It's easier to use input_pullup and wire the buttons to ground, at least in terms of less components.

All, I have had a lot of success with this thanks to the help given above.

A couple of points first on my thinking. As the library of bmp files is just a static one, where depending on the IF argument it just calls up the particular bimap wither directly by filename or the position in the array, I just made one file PitsBMP.h to cover all. That is attached to a subsequent post

I used the pullup argument as that seemed the simplest

As a result, I made a test with a sketch that used one OLED connected by i2C, and a four position rotary switch,. which worked fantastically for one OLED display

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

// set pins
const int buttonPin1 = 7;                 // Pin1's pushbutton
const int buttonPin2 = 8;                 // Pin2's pushbutton
const int buttonPin3 = 9;                 // Pin3's pushbutton
const int buttonPin4 = 10;                 // Pin4's pushbutton

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);


 
void setup() {
  Serial.begin(115200);
  pinMode(7, INPUT_PULLUP);
  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
 
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;);
  }
  
}
 
void loop() {
  //delay(2000); // Pause for 2 seconds
 
  // Clear the buffer.
  display.clearDisplay();
  
  // Draw bitmap on the screen
  if (digitalRead(buttonPin1) == LOW) {
  display.drawBitmap(0, 0, image_data_bits5, 128, 64, 1);
   
  }
  else
  if (digitalRead(buttonPin2) == LOW) {
  display.drawBitmap(0, 0, image_data_bits2, 128, 64, 1);
   
  }
  else
  if (digitalRead(buttonPin3) == LOW) {
  display.drawBitmap(0, 0, image_data_bits3, 128, 64, 1);
  
  }
  else
  if (digitalRead(buttonPin4) == LOW) {
  display.drawBitmap(0, 0, image_data_bits4, 128, 64, 1);
  
  }
    display.display();
  
}

However when I tried to use the multiplexer to connect to multiple OLED’s I tried splicing in the multiplexer script, and use the IF arguments to define what each OLED shows. However despite using i2C scan to check the correct identification of the multiplexer (it shows as the correct address), I am not getting anything displayed on the (independently tested) OLED screens. It compiles and loads fine, just doesn’t show anything on the screens.

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

// set pins
const int buttonPin1 = 8;                 // Pin1's pushbutton
const int buttonPin2 = 9;                 // Pin2's pushbutton
const int buttonPin3 = 10;                 // Pin3's pushbutton
const int buttonPin4 = 11;                 // Pin4's pushbutton


#define TCAADDR 0x70
void tcaselect (uint8_t i) {
  if (i > 7) return;

  Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();
}

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);



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

  const unsigned char* Bitmaps[] = {  //array of pointers to PROGMEM
  image_data_bits1, image_data_bits2, image_data_bits3, image_data_bits4, image_data_bits5
  };

  pinMode(8, INPUT_PULLUP);
  pinMode(9, INPUT_PULLUP);
  pinMode(10, INPUT_PULLUP);
  pinMode(11, INPUT_PULLUP);

  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;);


  }
  // Clear the buffer.
  display.clearDisplay();

  // Draw bitmap on the screen
  if (digitalRead(buttonPin1) == LOW) {
    tcaselect(0);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[1], 128, 64, 1);


    tcaselect(1);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[2], 128, 64, 1);


    tcaselect(2);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[3], 128, 64, 1);


    tcaselect(3);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[4], 128, 64, 1);


  }

  else if (digitalRead(buttonPin2) == LOW) {
    tcaselect(0);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[2], 128, 64, 1);


    tcaselect(1);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[3], 128, 64, 1);


    tcaselect(2);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[4], 128, 64, 1);


    tcaselect(3);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[5], 128, 64, 1);
  }
  else if (digitalRead(buttonPin3) == LOW) {

    tcaselect(0);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[3], 128, 64, 1);


    tcaselect(1);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[4], 128, 64, 1);


    tcaselect(2);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[5], 128, 64, 1);


    tcaselect(3);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[1], 128, 64, 1);

  }
  else if (digitalRead(buttonPin4) == LOW) {

    tcaselect(0);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[4], 128, 64, 1);


    tcaselect(1);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[5], 128, 64, 1);


    tcaselect(2);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[1], 128, 64, 1);


    tcaselect(3);    //multiplex the required OLED
    display.drawBitmap(0, 0, Bitmaps[2], 128, 64, 1);
  }

}
void loop() {
  delay(2000); // Pause for 2 seconds
  display.display();


}

I tried with the array as per th eposted sketch and also by directly referencng the bmp files like in the working sketch above, but neither worked

If anyone is able to identify any glaring errors in the sketch I would be grateful, as I am at the limit of my sketch skills!

Cheers

Les

Just tried to put in the PitsBMP.h file, too big - is there another way to post the .h file?

In the meantime, these are the headers of the .h file so that you can see the references

static char const unsigned PROGMEM image_data_bits1[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  ***** 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};

static char const unsigned PROGMEM image_data_bits2[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  *****
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};


static char const unsigned PROGMEM image_data_bits3[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
***** 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  };
  
  
  static char const unsigned PROGMEM image_data_bits4[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
****** 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
};

 static char const unsigned PROGMEM image_data_bits5[] = {
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
 *****, 
  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
};

Cheers

Les

Shouldn't there be a wire.begin in setup?

Hi WildBill - the working multiplexed sketch I have used before, that statement is not in there - I assume the

Wire.beginTransmission(TCAADDR);
  Wire.write(1 << i);
  Wire.endTransmission();

part does that, although I am not as good at these things as you all!

I also noted that I had omitted this part in the void setup, but it makes no difference

for (int i = 0; i < 7; i++) {
    tcaselect(i);
    display.begin();
  }

Les