LCD Sub-Menu Functions with 4x20 OLED?

Greetings!

Son and I would like to implement a simple menu system on our Arduino to control various LED's for the upcoming Holiday season! We were hoping to do something similar to this:

LCD

And the On and Off functionality such as:

LCD2

We plan on using a keypad to have an UP, DOWN, ENTER, and MAIN MENU button. So far, most of the research done uses a generic character display but we would like to step up a notch and use a 4x20 OLED character display! :sunglasses: The main difference is that the LiquidCrystal library may not be compatible with this display.

Instead, the display writes characters using commands. Here is an example of this:

/****************************************************
*      PINOUT: Arduino Uno -> Character OLED        *
****************************************************/
// The 8 bit data bus is connected to PORTD 0-7 of the Arduino Uno
// The 4 bit data bus is connected to PORTD 4-7 of the Arduino Uno

#define E_Pin 10
#define R_W   9
#define R_S   8

unsigned char mode = 4; // 4 = 4-Bit parallel  
                        // 8 = 8-Bit Parallel

/****************************************************
*                 Text Strings                      *
****************************************************/

char const text1[] = ("       Display      ");
char const text2[] = ("   International    ");
char const text3[] = ("   CHARACTER TEST   ");

char const text4[] = ("   4-Bit Parallel   ");
char const text5[] = ("   8-Bit Parallel   ");

char const text6[] = ("ABCDEFGHIJKLMOPQRSTU");
char const text7[] = ("VWXYZabcdefghijklmno");
char const text8[] = ("pqrstuvwxyz123456789");
char const text9[] = (" <(' ')> || <(' ')> ");

/****************************************************
*               Function Commands                   *
****************************************************/

//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//  4-bit / 8-bit 6800 Parallel Interface 
//-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

void latch()                  // command to latch E  
{                           
  digitalWrite(E_Pin, HIGH);  
  delay(1);
  digitalWrite(E_Pin, LOW); 
  delay(2);
}

void command(char i)
{
  switch(mode)
  {
    case 4: PORTD = i;
            digitalWrite(R_S, LOW);    // Command
            digitalWrite(R_W, LOW);    // Write
            latch();                   // Latch upper 4 bits
            i = i<<4;                  // shift 4 bits
            PORTD = i;                 // Take lower 4 bits
            latch();                   // Latch lower 4 bits
            break;
            
    case 8: PORTD = i;
            digitalWrite(R_S, LOW);    // Data
            digitalWrite(R_W, LOW);    // Write
            latch();                   // Latch 8 bits
            break;           
  }
}

void data(char i)
{
  switch(mode)
  {
    case 4: PORTD = i;
            digitalWrite(R_S, HIGH);              // Data
            digitalWrite(R_W, LOW);               // Write
            latch();                              // Latch upper 4 bits
            i = i<<4;                             // shift 4 bits
            PORTD = i;                            // Take lower 4 bits
            latch();                              // Latch lower 4 bits
            break;
            
    case 8: PORTD = i;
            digitalWrite(R_S, HIGH);              // Data
            digitalWrite(R_W, LOW);               // Write
            latch();                              // Latch 8 bits
            break;           
  }
}

/****************************************************
*                  Display Functions                *
****************************************************/

void clear_screen(){                    // clear display 
 command(0x01);
}

void ret_home(){                        // Return to home position
 command(0x02); 
}


void disp1(){                 // DISPLAY TEXT
  clear_screen();
  ret_home();                 // First Line
  for( int i = 0; i< 20; i++){
    data(text1[i]);
  }
  command(0xc0);              // Second Line
  for (int i = 0; i<20; i++){
    data(text2[i]);
  }
  command(0x94);              // Third Line
  for( int i = 0; i< 20; i++){
    data(text3[i]);  
  }
  command(0xD4);              // Fourth Line
  for (int i = 0; i<20; i++){
    switch(mode){
      case 4:data(text4[i]);
             break;
      case 8:data(text5[i]);
             break;
    }
  }
}


void disp2(){                 // DISPLAY TEXT
  clear_screen();   
  ret_home();                 // First Line
  for( int i = 0; i< 20; i++){
    data(text6[i]);  
  }
  command(0xc0);              // Second Line
  for (int i = 0; i<20; i++){
    data(text7[i]); 
  }
  command(0x94);              // Third Line
  for( int i = 0; i< 20; i++){
    data(text8[i]);   
  }
  command(0xD4);              // Fourth Line
  for (int i = 0; i<20; i++){
    data(text9[i]);  
  }
}

/****************************************************
*              Initialization Routine               *
****************************************************/

void init1(){
  digitalWrite(E_Pin, LOW);
  delay(300);  

  switch(mode)
  {
  case 4:command(0x28);      //Enable 4-Bit Mode
         delay(5);
         break;
  case 8:command(0x38);      //Enable 8-Bit Mode
         delay(5);
         break;
  }
  command(0x08);             //Display OFF
  delay(2);
  command(0x01);             //Clear Display
  delay(2);
  command(0x06);             //Entry Mode set
  delay(2);
  command(0x02);             //Return Home
  delay(2);
  command(0x0C);             //Display ON
  delay(2);
}

/*****************************************************
*           Setup Function, to run once              *
*****************************************************/

void setup() {
  DDRD = 0xFF; // Enable pins on PORT D as outputs
  DDRB = 0xFF; // Enable pins on PORT B as outputs
  init1();
  delay(100);
}

/*****************************************************
*           Loop Function, to run repeatedly         *
*****************************************************/

void loop() {
  disp1();
  delay(2500);
  disp2();
  delay(2500);
}

How can we implement this type of menu functionality using this display? Any example code would be greatly appreciated!

the code you have posted uses a 4bit / 8bit parallel interface.
To me this seems pretty uncommon for modern OLED-display.
Though I don't know it.
Did you flash the posted code to your Arduino Uno and the demo-code was successfully showing

       Display      
   International    
   CHARACTER TEST   
   4-Bit Parallel   
   8-Bit Parallel   
ABCDEFGHIJKLMOPQRSTU
VWXYZabcdefghijklmno
pqrstuvwxyz123456789
 <(' ')> || <(' ')> 

I have doubts but maybe I'm wrong.

best regards Stefan

I do apologize for not including the display. It is a NHD-0420CW-AB3 that uses the US2066 driver!

We plan on using a keypad with the keypad library connected to the digital pins of the UNO. This will allow for an UP, DOWN, ENTER, and MAIN MENU button

This is a display for which you asked some days ago in a different thread.
Again I ask
Did you flash the posted code to your Arduino Uno and the demo-code was successfully showing the characters?

Did you change to an Arduino Mega to be able to use the library provided by the manufacturer?
best regards Stefan

Yep, the demo code works fine on it. We want to try it on the UNO first then if all else fails, we'll go to the Mega

If the demo-code works on the uno your own menu will work too.
The only difference between the demo-code and your code are different textes = other letters and a different number of textes.

Go ahead and modify the demo-code so that one of your textes will be shown on the display

As a next step I recommend to use the SafeString-library instead of direct arrays of chars, because the SafeString-library offers more comfort for concanating strings.

You can install the SafeString library with the library manager of the Arduino-IDE

We will try that but we haven't seen a good example for the menu structure. We want to mimic the functionality in those gifs above.

Sure But you should learn how the most basic principle works.
creating a similar functionality like in the animated gifs is done by manipulating the basic strings that were used in the demo-code.

And this is the reason why it is important to understand how the strings themself work

We have a good grasp on how the strings work and the functions that are called to show them, but switching between them seems to be the greater issue and how to keep track of where the pointer is

I will put you on a test.

In the gifs all text starts in the second columm.
The first columm is reserved to showing the arrow
What do you think how can the arrow be added into the first columm?
What is the basic principle to make the arrow visible in the second line?
then jump the arrow to the third line?

write some lines of code that demonstrate that

Something like:

/****************************************************
*                 Text Strings                      *
****************************************************/

char const text1[] = (">     Display       ");
char const text2[] = ("   International    ");
char const text3[] = ("   CHARACTER TEST   ");

char const text4[] = ("      Display       ");
char const text5[] = (">   International   ");
char const text6[] = ("   CHARACTER TEST   ");

char const text7[] = ("      Display       ");
char const text8[] = ("    International   ");
char const text9[] = (">  CHARACTER TEST   ");

As you scroll, you call those different strings. Of course, you need the for loop functions as well in the setup() area

This works but there is a more efficient way of doing it.
Your version would require two versions of each line
one line with the arrow , one line without arrow

This can be done by modifying a String ( or an array of char)

what is the difference between

char const text1[] = (">     Display       ");
char const text2[] = ("   International    ");
char const text3[] = ("   CHARACTER TEST   ");

and

char text1[] = (">     Display       ");
char text2[] = ("   International    ");
char text3[] = ("   CHARACTER TEST   ");

One isn't a const

and this means the content of this variable is changeable at program runtime
How does the line of code look like to replace the space of the first columm with the ">"-symbol?

Not really sure. How?

make a quick guess!
After that I will show it

void disp1(){                 // DISPLAY TEXT
  
  for( int i = 0; i< 20; i++){
    data(text1[i]);
  }

?

This sends the whole 20 characters to the display

For replacing the space in the first columm with the ">"-symbol
you code

assign the text with the space

char text2[] = ("   International    ");

for replacing the Space in the first columm

char text2[0] = '>'; // overwrite character stored in array-element with indes 0 with >

after that send modified text new to display
.
.
.
"deleting the >-symbol > is done with the same principle

char text2[0] = ' '; // overwrite character stored in array-element with indes 0 with a space

after that send modified text new to display

Ah, this way you don't need to make a new set of strings just for that one character?

Yes