Homemade Arduino Mega LCD Shield

I guys!

just to show you my last LCD Shield

Arduino Mega LCD Shield par DIY Effixe, sur Flickr

it has a 16x2 LCD + 4 push buttons.

project is downloadable in fritzing/projects/

this will help me to develop one project i'm working on : a semi automatic system for developing analog camera films.
diyautolab.blogspot.com (in french)

Now i have to work on a menu, i just read some post about a new way to do it, the phi-menu, i think the creator is may be there... :blush:

Nice work!

Here is something you may be interested in:

My user interface library, which includes menus, lists, input numbers, dialogs etc.

The library can use as many as 6 buttons or as few as 1 buttons (with an auto button to scroll among selections automatically)

BTW, I saw some resistors with the buttons. You can use the internal pull-up resistors to save 4 resistors on the board.


Reading this thread, I decided to do a brief comparison of phi-prompt and m2tklib. There are (of course) some visual differences. phi-prompt is optimized for character LCD, which leads to more compact menues (m2tklib has been written with graphics lcds in mind, but also supports character LCDs). From a programming perspective phi-prompt offers high level menues while m2tklib follows more a "build our own menu" concept. So to say, it is a use-case driven vs. brick based approach. From that perspetive i would say, that it probably could take a little bit more time for a software developer to get used to m2tklib (although i also tried to give a lot of examples)

liudr, correct me if i am wrong here...


Oliver,Thanks for the comparison. I am trying to add more flexibility in the next release so a menu can be constructed in SRAM and displayed, and add some more simple elements to further simplify how to construct a menu for beginners while retaining the elaborate versions for more experienced users.

Thank you Liudr!
your phi prompt looks very interesting for my project! i'll try to adapt it to my needs.

about my resistors, you're probably right because i don't know what you are talking about :cold_sweat:, like i said, i'm noob with arduino. I'll make some research to learn how pull-up resistors works.
And by the way, i don't really care in this particular project to have 4 resistors on my board.

thank you dude.

Some info on pull-up resistors

Some info on pull-up resistors


ok, so if i understand correctly,
i have to declare my input pin that has a push button as an input and set it to high and use it as an input.


  1. connect pin x to button, button to gnd
  2. in setup do pinMode(x,input);
  3. in setup do digitalWrite(x,HIGH); //This actually doesn't write to a pin, but rather sets a register value to enable the internal pull-up resistor so when the button is not connecting pin x to ground, the pull-up resistor connects pin x to 5V.

Ok, thank you Liudr, i will use this for my final project.

come back to my main subject, i have tried to use your phi_prompt but something goes wrong.
Did you know where i have to copy your .h libraries in osx? when i compile the program, i have an error that tells me that he didn't find libraries.

The phi prompt library needs to reside inside arduino0022/sketches/libraries/phi_prompt/phi_prompt.cpp and phi_prompt.h

The library also needs the phi_buttons library to support its button sensing, which you can download from the same site. Same way to store the library in its folders under libraries inside sketches.

If you used pull-cown resistor, you will need to do
phi_buttons button1(buttonpin,HIGH);
I used internal pullup so my setting was LOW logic

Let me know if you have more questions.

thank you Liudr,
Ok, now compile/upload works fine.
I define my pins for my shield but it doesn't work fine. Firsts letters works well, i can read the beginning of credits but LCD is blinking and never stop on a statement, text is scrolling.

I have only 4 buttons, so i think, i have to define in defs.h (#define use_4_btn) and define ID pins to btn_u, btn_d, btn_b and btn_a (b and a are for validation, right?).

what else do i have to do?

edit :
I have tried your program to sense buttons, and serial monitor display all values without pushing any buttons. is this because i have resistors on my board and didn't use internal pull-up?

edit 2 :
ok, i'm an idiot... i change values of buttons of LOW to HIGH, and it works!!!!!

thank you very much for your time.

ps: i don't know if you've seen it but i have post my code in the french section of the forum.

it's not working perfectly and it was not finished but that is what i need but programing it is the most difficult part for me.

Awesome! I really like how you were updating as you go and yes if you designed your buttons to connect input to ground and enabled internal pullup resistors, your logic (HIGH for no push and LOW for push) will be just the opposite to what you have right now, which is LOW for no push and HIGH for push.

Withe the 4 button setting, the up and down are what scrolls everything, and left is acting as escape and right as enter.

I'll try to read your code in French and see if I can find any mistakes. I find it most difficult to read code in a language I can't read since I can memorize the names of the variables and end up referring back to the variable definitions all the time. So maybe use more consonants among French, English, and Spanish, etc. to name variables and functions so more people (especially native English readers or English as second language readers) can easily read them.

i think you will find a lot of mistakes in my code... (and it is not really finished, this is only a part of a function of my project)
by the way, there is only few words in french in my code. ok, comments are in french and few variables like :
Choix mean choice
Type_Dev mean what kind of development will be used.
AfficheMenu is like PrintMenu
PresseBouton is PressButton

and i think that's all for now.

i will try to apply your advice by translating in english my variables and functions.

so, go back to your code, i have work to do to update it to my needs.

Great, now I know a few more French words! I'll definitely read the code and tell you what I think on this thread.

As for my code, go ahead and modify it. Please keep the original credits if a large part of the code remains original.

Great, now I know a few more French words! I'll definitely read the code and tell you what I think on this thread.

As for my code, go ahead and modify it. Please keep the original credits if a large part of the code remains original.

i'm happy to help!

for sure, if i use your a large part, i will keep credits! don't worry.

Just moved the code over to this thread so everyone can read the code. So far that is some progress. You should use "#" button to include code, not quote button:

DEVUINO AutoLab: developpement semi-automatique de photos
MAJ : 18/09/2011

 Aruino Mega LCD Shield for DIY Jobo Atl by Effixe
  The circuit:
 LCD :
 * LCD RS pin to digital pin 48
 * LCD Enable pin to digital pin 46
 * LCD D4 pin to digital pin 44
 * LCD D5 pin to digital pin 42
 * LCD D6 pin to digital pin 40
 * LCD D7 pin to digital pin 38
 * LCD R/W pin to ground

  4 push buttons
  Button 01 (prev) to digital pin 41
  Button 02 (next) to digital pin 39
  Button 02 (exe) to digital pin 43
  Button 02 (cancel) to digital pin 37

// Chargement des fonctions

#include <LiquidCrystal.h> // Ecran LCD

// création du caractère °
  byte degree[8] = {

// Identification des boutons du LCD Arduino Mega
const int B_Prev = 41;
const int B_Next = 39;
const int B_Exe = 43;
const int B_Cancel = 37;


// Initialisation du LCD
LiquidCrystal lcd(48, 46, 44, 42, 40, 38); //Arduino Mega Shield

// Etat des boutons  
int B_Prev_State=0;
int B_Next_State=0;
int B_Exe_State=0;
int B_Cancel_State=0;

// Affichage du LCD
char * V_LCD_L1="BIENVENUE";
char * V_LCD_L2="DEVUINO V0.6";

int V_Menu=0; // Position dans le menu
int V_Choix=0; // Position actuelle du choix
int V_Choix_Max=2; // Choix max. dans un menu
int Type_Dev = 0; //Type de dev à effectuer
int Temperature = 20;

void setup () {
   // Vitesse de transfert avec le port serie
  lcd.createChar(0, degree); // création du caractère spécial °

  // Parametres des boutons
  pinMode(B_Prev, INPUT);
  pinMode(B_Next, INPUT);
  pinMode(B_Exe, INPUT);
  pinMode(B_Cancel, INPUT);

  // Message d'accueil
  lcd.begin(16,2);  //initialisation affichage LCD 16x2 lignes

  while(Type_Dev == 0){

void loop() {
lcd.print("Dev : "); //debug test


void AfficheMenu(int V_Menu) {
  // Enumeration de tous les menus et du nombre de choix que chacun propose
  switch (V_Menu) {
    case 0:V_LCD_L1="DEV   |C41|E6|NB"; V_Choix_Max=2;  break;
    case 1:V_LCD_L1="Temp.  |20|25|38"; V_Choix_Max=2;  break;
    case 11:V_LCD_L1="DEV   C41 @ 20"; V_Choix_Max=1;  break;
    case 12:V_LCD_L1="DEV   C41 @ 25"; V_Choix_Max=1;  break;
    case 13:V_LCD_L1="DEV   C41 @ 38"; V_Choix_Max=1;  break;
    case 2:V_LCD_L1="Dev    E6 @ 38"; V_Choix_Max=0;  break;
    case 3:V_LCD_L1="Type  Custom|STD";V_Choix_Max=2;  break;
    case 32:V_LCD_L1="Stand Dev N&B";V_Choix_Max=1;  break;
    case 31:V_LCD_L1="Temp.  + | -";V_Choix_Max=0;  break;
  // Affichage du menu en cours  
  if (V_Menu == 2){lcd.write(0);lcd.print("C");delay(2000);if (B_Exe_State==HIGH){Type_Dev = V_Menu;}}
  if (V_Menu == 11){lcd.write(0);lcd.print("C");delay(2000);if (B_Exe_State==HIGH){Type_Dev = V_Menu;}}
  if (V_Menu == 12){lcd.write(0);lcd.print("C");delay(2000);if (B_Exe_State==HIGH){Type_Dev = V_Menu;}}
  if (V_Menu == 13){lcd.write(0);lcd.print("C");delay(2000);if (B_Exe_State==HIGH){Type_Dev = V_Menu;}}
  if (V_Menu == 31){lcd.print(Temperature);lcd.write(0);lcd.print("C");ChoixTemperature();}

void AfficheChoix(int V_Choix) {

  // Enumeration de toutes les possibilites de choix (3 cas)
  switch (V_Choix) {
    case 0:V_LCD_L2="*      ";break;
    case 1:V_LCD_L2="   *   ";break;
    case 2:V_LCD_L2="      *";break;
  // Affichage du choix en cours



void PresseBouton() {
    B_Prev_State = digitalRead(B_Prev);
    B_Next_State = digitalRead(B_Next);
    B_Exe_State = digitalRead(B_Exe);
    B_Cancel_State = digitalRead(B_Cancel);

    if (B_Prev_State==HIGH) { // Précédent
      if (V_Choix>0) {      
    if (B_Next_State==HIGH) {  //  Suivant
        if (V_Choix<V_Choix_Max) {
    if (B_Exe_State==HIGH) { // Execute
       if (V_Menu<40){
       V_Choix = 0;

   if (B_Cancel_State==HIGH) { // Cancel
       V_Choix = 0;

  void ChoixTemperature(){
   while (B_Exe_State==LOW){
    if (B_Next_State==HIGH) {

   if (B_Prev_State==HIGH) {

Ok, thanks.

is my code clear for you? maybe you want some explanations.

I want to have a choice between 3 types of developing process.
C41, E6 and NB
In C41, i will have choice in 3 temperatures of process 20°C / 25°C / 38°C
in E6, no choice, only 38°C
In NB, Stand Developement and a customs values Temperature and Time.

thats it for my needs for now.

later i will need to create a deeper menu, with many others functions like access to draining pumps (7 pumps), set offset temperature... and maybe later how to access to some data logged on a SD card...

Thanks for describing the purpose of the code to me. Definitely helpful when reading through it.

Here's what I'm seeing from the code, correct me if I make mistakes:

There are 4 buttons, prev, next, exe (run) and cancel.

You print the menu with AfficheMenu(V_Menu) and print the choice (using a * symbol) with AfficheChoix(V_Choix). You use something like " * " on line 2 to indicate what is selected. You print a few selectable things on line 1. so a typical screen shot looks like this, right?

DEV   |C41|E6|NB

In some menus there are as many as three selectable items and in some there are only 1 so the V_Choix_Max determines how many selectable items there are (0-2 represents 1-3 choices you can make), right?

To be continued...

you have totally understand my code and what i want to do.

Yes V_Choix_Max is the maximum choice for the variable.
V for Variable, Choix for Choice and Max for Max ^^

DEV   |C41|E6|NB

Yes! that is what is print on the first picture of the topic and that is what i need.

i think that my code will be inappropriate in future versions, i only have 3 positions for the * symbol and it will not fit perfectly with words longer than 3 characters... I don't know yet how to manage it.
I have a second issue, my function PresseBouton() (press button listener) is too fast, i have to gently and quickly press my button to move one step, if you hold down it for a long period, it will execute and pass to the next step too quickly. (Am i understandable?)
i'm sorry for my english, it's not my native language.

Ok, the Pressbutton() was not right. You should not be waiting with delay. Instead, do a while loop

  //sense all buttons
  //if a button is pressed, set that button as pressed and break out of the loop

The way to sense button press is to store the button status and then read new status and compare with old, if the old is no push and the new is push, the register as pressed. Then old status becomes push. You didn't store the old button status so you can't tell a button is pressed technically.