Storing multiple "pointers" (???) to bitmaps in an array

In my project, I need to have multiple bitmaps to display on an OLED and I was wondering if you could do something like (probably incorrect code):

int bitmap[]={bitmap_1, bitmap_2, bitmap_3};

while bitmap_1, bitmap_2 and bitmap_3 are in bitmaps.h and later on in the program I could call something like (without code tags so I can use bold):

display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, bitmap[0], LOGO_WIDTH, LOGO_HEIGHT, 1);

Is this achievable?

It sounds like a 2 dimensional array is what you need

How would I use it for my purpose?

Domnulvlad:
How would I use it for my purpose?

Each row of the array holds a bitmap
Each bitmap holds an array of bytes

Need to display the third bitmap ?
Set the array index to [2][0] and start reading bytes until you have read them all for the bitmap

Need to display the seventh bitmap ?
Set the array index to [6][0] and start reading bytes until you have read them all for the bitmap

and so on

I'm very sure I'm doing something wrong (chopped off a lot of numbers so I could post it)

static const unsigned char PROGMEM bitmapper[][3] = {
  
  {
    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
  }
  , 
  {
    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
  }
  ,
  {
    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
  }
  
}
ERROR: too many initializers for 'const unsigned char [3]'

Changed it to

static const unsigned char PROGMEM bitmapper[][1024] = {

(i counted 16x64 so 1024 chars) and tried

display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, bitmapper[0][], LOGO_WIDTH, LOGO_HEIGHT, 1);

but it's throwing a weird error

expected ',' or ';' before 'int'

and highlighting the wrong line of code, but before it, in the console there is

error: expected primary-expression before ']' token

pointing to the second opened bracket in "bitmapper[0][]".

I don't know where to go.

You must explicitly specify the length of BOTH dimensions. As in, you need to provide numbers within both sets of brackets ([]).

static const unsigned char PROGMEM bitmapper[][3]

The first dimension is the number of rows in the array and the second is the number of columns. I assume that you can see why you got the "too many initializers" error

i counted 16x64 so 1024 chars

You might like to review the number of rows and columns in the array

I don't know where to go.

Please post a complete program and the full error messages

Power_Broker:
You must explicitly specify the length of BOTH dimensions. As in, you need to provide numbers within both sets of brackets ([]).

Are you sure ?

code (very bad, posted question on how to make it more compact on Project Guidance):

#include <Bounce2.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "bitmaps.h"

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)

#define LOGO_HEIGHT   64
#define LOGO_WIDTH    128

#define sw      5
#define outputA 6
#define outputB 7

#define VCC 8

//////////////////////////////////////////
int noOfMenus = 3;
//////////////////////////////////////////

int counter = 0 ;
int aState      ;
int aLastState  ;
int lastSw      ;
int lastCounter ;
int currentSw   ;
int oldValue;
int x = 1;

bool drewDisplayMenu = false;
bool firstTimeDisplay = true;
bool pressedFirstTimeDisplay = false;
bool releasedFirstTimeDisplay = true;

bool drewSettingsMenu = false; /////////// settings
bool firstTimeSettings = true;
bool pressedFirstTimeSettings = false;
bool releasedFirstTimeSettings = true;


bool drewPlaceholderMenu = false;



bool ignoreEncoder = false;
//bool cleared = false;

Bounce debouncer = Bounce();

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

void setup() {
  pinMode (outputA,   INPUT);
  pinMode (outputB,   INPUT);
  pinMode (sw, INPUT_PULLUP);

  pinMode (VCC, OUTPUT);
  digitalWrite(VCC, HIGH);

  debouncer.attach(sw);
  debouncer.interval(5); // interval in ms

  Serial.begin (9600);

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

  aLastState = digitalRead(outputA);

  display.display();
  display.clearDisplay();
  display.display();
}

void loop() {

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Button debouncing with Bounce2

  debouncer.update();
  int button = debouncer.read();

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Encoder algorythm

  if (ignoreEncoder == false) {
    aState = digitalRead(outputA); // Reads the "current" state of the outputA
    // If the previous and the current state of the outputA are different, that means a Pulse has occured
    if (aState != aLastState) {
      // If the outputB state is different to the outputA state, that means the encoder is rotating clockwise
      if (digitalRead(outputB) != aState) {
        counter ++;
      } else {
        counter --;
      }
    }
  }

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Calculating menu position

  int counterer = counter / 2;

  if (counterer % noOfMenus == noOfMenus - noOfMenus) { /////////////////////////////////// settings & subSettings

    drewDisplayMenu = false;
    drewPlaceholderMenu = false;

    drawSettingsMenu();

    if (button == HIGH) {
      releasedFirstTimeSettings = true;
    }

    if (button == LOW && firstTimeSettings == true && releasedFirstTimeSettings == true) {
      drawSubSettings(counterer);
      pressedFirstTimeSettings = true;
    }

    if (button == HIGH && pressedFirstTimeSettings == true) {
      drawSubSettings(counterer);
      firstTimeSettings = false;
    }

    if (button == LOW && firstTimeSettings == false) {
      drewSettingsMenu = false;
      firstTimeSettings = true;
      pressedFirstTimeSettings = false;
      releasedFirstTimeSettings = false;
      ignoreEncoder = false;
    }
  }

  if (counterer % noOfMenus == noOfMenus - noOfMenus + 1 || counterer % noOfMenus == noOfMenus - noOfMenus - 1) { /////////////////display & subDisplay
    drewSettingsMenu = false;
    drewPlaceholderMenu = false;

    drawDataDisplayMenu();

    if (button == HIGH) {
      releasedFirstTimeDisplay = true;
    }

    if (button == LOW && firstTimeDisplay == true && releasedFirstTimeDisplay == true) {
      drawSubDisplay(counterer, analogRead(A0));
      pressedFirstTimeDisplay = true;
    }

    if (button == HIGH && pressedFirstTimeDisplay == true) {
      drawSubDisplay(counterer, analogRead(A0));
      firstTimeDisplay = false;
    }

    if (button == LOW && firstTimeDisplay == false) {
      drewDisplayMenu = false;
      firstTimeDisplay = true;
      pressedFirstTimeDisplay = false;
      releasedFirstTimeDisplay = false;
      ignoreEncoder = false;
    }
  }

  if (counterer % noOfMenus == noOfMenus - noOfMenus + 2 || counterer % noOfMenus == noOfMenus - noOfMenus - 2) {
    drewSettingsMenu = false;
    drewDisplayMenu = false;

    drawPlaceholderMenu();


  }

  if (drewDisplayMenu == true && drewSettingsMenu == true) {
    drewDisplayMenu = false;
    drewSettingsMenu = false;
  }

  aLastState  =    aState; // Updates the previous state of the outputA with the current state
  lastCounter = counterer;
  lastSw      =     button;
  oldValue = button;

  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Optional debug

  //Serial.println(value);

}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// Drawing functions

void drawSettingsMenu(void) {
  if (!drewSettingsMenu) {
    display.clearDisplay();
    display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, settingsMenu, LOGO_WIDTH, LOGO_HEIGHT, 1);
    display.display();
    drewSettingsMenu = true;
  }
}

void drawSubSettings(int currentCycle) {

  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(WHITE);
  drawTitle("SETTINGS", 0);
  setRows(0, 2);
  display.print("On cycle #");
  display.println(currentCycle);
  display.display();

  ignoreEncoder = true;

}

void drawDataDisplayMenu(void) {
  if (!drewDisplayMenu) {
    display.clearDisplay();
    display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, dataDisplayMenu, LOGO_WIDTH, LOGO_HEIGHT, 1);
    display.display();
    drewDisplayMenu = true;
  }
}

void drawSubDisplay(int currentCycle, int inputData) {

  display.clearDisplay();

  display.setTextSize(1);
  display.setTextColor(WHITE);
  drawTitle("DATA DISPLAY", 0);
  setRows(0, 2);
  display.println(inputData);
  display.display();

  ignoreEncoder = true;

}

void drawPlaceholderMenu(void) {
  if (!drewPlaceholderMenu) {
    display.clearDisplay();
    //display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, placeholderMenu, LOGO_WIDTH, LOGO_HEIGHT, 1);
    display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, bitmapper[0][0], LOGO_WIDTH, LOGO_HEIGHT, 1);
    display.display();
    drewPlaceholderMenu = true;
  }
}

void drawTitle(String title, int height)
{
  int w = (6 * title.length()) - 1; // on normal font size, characters are 5 x 7 pixels
  display.setCursor((127 - w) / 2, height);
  display.println(title);
}

void setRows (int column, int row) {
  int height = map(row, 0, 7, 0, 56);
  display.setCursor(column, height);
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// End of program

bitmaps.h won't fit, attached

errors won't fit, attached

bitmaps.h (37.8 KB)

errors.txt (2.55 KB)

rotary_encoder_detect_change:22:1: error: expected ',' or ';' before 'int'

 int noOfMenus = 3;

 ^~~

You left the last ; off in the bitmaps.h file, the compiler is treating this line as a continuation of that file.

rotary_encoder_detect_change:246:142: error: no matching function for call to 'drawBitmap(int16_t, int16_t, const unsigned char&, int, int, int)'

     display.drawBitmap((display.width() - LOGO_WIDTH ) / 2, (display.height() - LOGO_HEIGHT) / 2, bitmapper[0][0], LOGO_WIDTH, LOGO_HEIGHT, 1);

                                                                                                                                              ^

the reference to bitmapper[0][0] refers to a single char, you should use bitmapper[0] to refer to the entire 1024 char bitmap image.

static const unsigned char PROGMEM bitmapper[3][3072] = {

This is wrong. This is declaring an array composed of 3 groups of 3072 char each. Each of your bitmap images is composed of 1024 char, so you needs to declare 3 groups of 1024 char each:

static const unsigned char PROGMEM bitmapper[3][1024] = {

This stores three 1024 char bitmap images in PROGMEM, with the images referenced as bitmapper[0], bitmapper[1], and bitmapper[2].

Thanks a real lot, david_2018! This solved everything.

The first error with the " expected ',' or ';' " is quite common, and confuses a lot of people, because the error is generally not with the line that the compiler flags, but with a previous line of code. In your case it was in a separate file. After a bit of coding you get used to things like that and know where to start looking.