Problems With a LCD Keypad Shield and a Relay Shield on Arduino Mega

Hello,

I’ve been working on a project of mine in which a user selects a certain number using a LCD Keypad Shield, and when “Select” is pressed, the code reads the number and switches on two relays for a certain amount of time. What I had trouble with was getting the relays to not switch on until btnSelect is pressed. I put the if statements under the case btnSelect, but when I run the code the LCD goes unresponsive for a short while. Can someone help me? Thank you in advance for any help.

#include <LiquidCrystal.h>

unsigned char relayPin[2] = {30,31};
// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int myCounter = 0;
int upperLimit = 5;
int lowerLimit = 1;

int lcd_key     = 0;
int adc_key_in  = 0;
#define btnUP     1
#define btnDOWN   2
#define btnSELECT 4
#define btnRIGHT  3
#define btnLEFT   5
#define btnNONE   0

// read the buttons
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor 
  // my buttons when read are centered at these values: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  if (adc_key_in < 50)   return btnRIGHT;  
  if (adc_key_in < 250)  return btnUP; 
  if (adc_key_in < 450)  return btnDOWN; 
  if (adc_key_in < 650)  return btnLEFT; 
  if (adc_key_in < 850)  return btnSELECT; 
}

void setup()
{
  int i;
  lcd.begin(16, 2);              // start the library
  lcd.setCursor(0,0);
  lcd.print("Select an option"); // print a simple message
  {
    pinMode(relayPin[i],OUTPUT);
  }
}

void loop()
{
  {
  lcd.setCursor(9,1);            // move cursor to second line "1" and 9 spaces over
  lcd.setCursor(0,1);            // move to the begining of the second line
  lcd_key = read_LCD_buttons();  // read the buttons
  int count = 1;
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
  case btnUP:
    {

     myCounter ++; 
    if (myCounter > upperLimit) myCounter = upperLimit;
      lcd.print("One more      ");
      lcd.setCursor(14,2);
      lcd.print(myCounter);
      delay(1000);
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
  case btnDOWN:
    {

      myCounter --;
   if (myCounter < lowerLimit) myCounter = lowerLimit;
      lcd.print("One less    ");
      lcd.setCursor(14,2);
      lcd.print(myCounter);
      delay(1000);
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
  case btnSELECT:
    {
      lcd.print("Good choice!    ");
      delay(1000);
      lcd.setCursor(0,2);
      lcd.print("            ");
       if (myCounter == 1)
    {
      digitalWrite(relayPin[myCounter],HIGH);
      delay(6000);
    }
  if (myCounter == 2)
    {
      digitalWrite(relayPin[myCounter],HIGH);
      delay(6500);
    }
  if (myCounter == 3);
    {
      digitalWrite(relayPin[myCounter],HIGH);
      delay(7000);
    } 
  if (myCounter == 4);
    {
      digitalWrite(relayPin[myCounter],HIGH);
      delay(7500);  
    }
  if (myCounter == 5);
    {
      digitalWrite(relayPin[myCounter],HIGH);
      delay(8000);
    }
    digitalWrite(relayPin[myCounter],LOW);
      break;
    }
  case btnRIGHT:
    {
      lcd.print("");
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
  case btnLEFT:
    {
      lcd.print("");
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
 
   }
  }
}

Hi BetaTeam!

When you say that "the LCD goes unresponsive for a short while", that is because of the delay function that you are using.

I don't understand very well what you are trying to do. Do you really want that every relay only had closed a certain amount of time that is different for every relay? I don't get the point of that. If is that, there are better ways to do it other than with delay function.

EDIT: After I wrote the answer I realise one thing. You only have 2 relays relayPin[2] = {30,31}; but the choices that you have are 6 (form 0 to 5)! Other thing that I don't understand is:

int myCounter = 0;
(...)
int lowerLimit = 1;

You start the myCounter with 0 but next you define the lowerLimit whith 1! For me, it don't makes sense.

Other thing that I don't understand is the reason for:

  int count = 1;

Thank you for the response!

I now realize that I need to only set the delay on the relays (so they stay on for a certain amount of time). I am only running two relays, both of which are open for the same amount of time. Additionally, the part about 6 relays was a part of the code for the LCD display, so it can be ignored. I set the initial counter at 0 just so the user would see the counter pop up (just a personal preference). The int count = 1; was also a part of code I accidentally left in there :sweat_smile: Also, would you mind showing me a better way than the delay function? And finally, do I have the if statements in the right place?

Thank you for all of your insight,

BetaTeam

I don’t like the idea of initial counter, but is OK.

For now you could keep the delays because I think the problem with the lack of response of the system may be other than that. Notice that you only have 2 relays (an so, an array of 2 positions) but you are using digitalWrite form 1 to 5! This is a big problem that can cause the Arduino to Reset.

So for now, what I would do is:

void loop()
{
  {
  lcd.setCursor(9,1);            // move cursor to second line "1" and 9 spaces over
  lcd.setCursor(0,1);            // move to the begining of the second line
  lcd_key = read_LCD_buttons();  // read the buttons
  int count = 1;
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
  case btnUP:
    {

     myCounter ++; 
    if (myCounter > upperLimit) myCounter = upperLimit;
      lcd.print("One more      ");
      lcd.setCursor(14,2);
      lcd.print(myCounter);
      delay(1000);
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
  case btnDOWN:
    {

      myCounter --;
   if (myCounter < lowerLimit) myCounter = lowerLimit;
      lcd.print("One less    ");
      lcd.setCursor(14,2);
      lcd.print(myCounter);
      delay(1000);
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
  case btnSELECT:
    {
      lcd.print("Good choice!    ");
      delay(1000);
      lcd.setCursor(0,2);
      lcd.print("            ");
      if (myCounter >= 1 && myCounter <= 2)
      {
          digitalWrite(relayPin[myCounter-1],HIGH);
          if (myCounter == 1) {
              delay(6000);
          }
          else if (myCounter == 2) {
              delay(6500);
          }
          digitalWrite(relayPin[myCounter-1],LOW);
    }
    break;
    }
  case btnRIGHT:
    {
      lcd.print("");
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
  case btnLEFT:
    {
      lcd.print("");
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
 
   }
  }
}

Thank you for your response!

Thank you for point out my digitalWrite! I am trying to have 5 different delays for the relay to be set and I just plugged it in there. So can you guide me on how I would go about switching both relays on for the same time, but the time varying between 5 different values? Here’s my code with your additions:

#include <LiquidCrystal.h>

unsigned char relayPin[2] = {
  30,31};
// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int myCounter = 0;
int upperLimit = 5;
int lowerLimit = 1;

int lcd_key     = 0;
int adc_key_in  = 0;
#define btnUP     1
#define btnDOWN   2
#define btnSELECT 4
#define btnRIGHT  3
#define btnLEFT   5
#define btnNONE   0

// read the buttons
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor 
  // my buttons when read are centered at these values: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  if (adc_key_in < 50)   return btnRIGHT;  
  if (adc_key_in < 250)  return btnUP; 
  if (adc_key_in < 450)  return btnDOWN; 
  if (adc_key_in < 650)  return btnLEFT; 
  if (adc_key_in < 850)  return btnSELECT; 
}

void setup()
{
  lcd.begin(16, 2);              // start the library
  lcd.setCursor(0,0);
  lcd.print("Select an option"); // print a simple message
}

void loop()
{
  {
    lcd.setCursor(9,1);            // move cursor to second line "1" and 9 spaces over
    lcd.setCursor(0,1);            // move to the begining of the second line
    lcd_key = read_LCD_buttons();  // read the buttons
    switch (lcd_key)               // depending on which button was pushed, we perform an action
    {
    case btnUP:
      {
        myCounter ++; 
        if (myCounter > upperLimit) {
          myCounter = upperLimit;
        }
        lcd.print("One more      ");
        lcd.setCursor(14,2);
        lcd.print(myCounter);
        delay(1000);
        lcd.setCursor(0,2);
        lcd.print("            ");
        break;
      }
    case btnDOWN:
      {
        myCounter --;
        if (myCounter < lowerLimit) {
          myCounter = lowerLimit;
        }  
        lcd.print("One less    ");
        lcd.setCursor(14,2);
        lcd.print(myCounter);
        delay(1000);
        lcd.setCursor(0,2);
        lcd.print("            ");
        break;
      }
    case btnSELECT:
      {
        lcd.print("Good choice!    ");
        delay(1000);
        lcd.setCursor(0,2);
        lcd.print("            ");
        if (myCounter >= 1 && myCounter <= 5)
        {
          digitalWrite(relayPin[1 && 2],HIGH);
          if (myCounter == 1) {
            delay(6000);
          }
          else if (myCounter == 2) {
            delay(6500);
          }
          else if (myCounter == 3) {
            delay(7000);
          }
          else if (myCounter == 4) {
            delay(7500);
          }
          else if (myCounter == 5) {
            delay(8000);
          }
          digitalWrite(relayPin[1 && 2],LOW);
        }
        break;
      }

    case btnRIGHT:
      {
        lcd.print("");
        lcd.setCursor(0,2);
        lcd.print("            ");
        break;
      }
    case btnLEFT:
      {
        lcd.print("");
        lcd.setCursor(0,2);
        lcd.print("            ");
        break;
      }

    }
  }
}

This line:

digitalWrite(relayPin[1 && 2],HIGH);

don’t do what you expect it do.

Change this (and the one that writes a LOW in the same pin), by:

      if (myCounter >= 1 && myCounter <= 2)
      {
          digitalWrite(relayPin[myCounter-1],HIGH);
      }
      if (myCounter >= 1 && myCounter <= 2)
      {
          digitalWrite(relayPin[myCounter-1],LOW);
      }

Look that I write myCounter - 1. This is because in C language the arrays index starts at 0 and they go to number_of_elements - 1. So, in your case you only have 2 elements, so you can only access the element 0 and the element 1. If you try to access other elements, strange errors may appear. Trying to access the element 1 && 2 is the same that accessing always the element 1. That’s because you are doing a logical operation between 1 and 2.

Thanks for your response!

I want to specify that myCounter is not supposed to be an element, it is displayed on the screen as a number. I need five different options. I need the code to read what the counter is, and switch both pins to be on for the specific delay. There are five delays that need to be accessed. I'm sorry if I don't understand what you're saying, and thank you for your help.

So, you need that the 2 relay switch on for any option that you select (any myCounter), and then the only difference form one option to another is the time that the 2 relays are on?
If yes, you only need to do:

        if (myCounter >= 1 && myCounter <= 5)
        {
          digitalWrite(relayPin[1],HIGH);
          digitalWrite(relayPin[2],HIGH);

          switch (myCounter) {
               case 1:
                    delay(6000);
                    break;
              case 2:
                   delay(6500);
                   break;
             case 3:
                   delay(7000);
                   break;
             case 4:
                   delay(7500);
                   break;
            case 5:
                   delay(8000);
                   break;
          }
          digitalWrite(relayPin[1],LOW);
          digitalWrite(relayPin[2],LOW);
        }

Okay, I tried the code but it didn’t work. I tried using pinMode this time and would this work?

#include <LiquidCrystal.h>

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int myCounter = 0;
int upperLimit = 5;
int lowerLimit = 1;

int lcd_key     = 0;
int adc_key_in  = 0;
#define btnUP     1
#define btnDOWN   2
#define btnSELECT 4
#define btnRIGHT  3
#define btnLEFT   5
#define btnNONE   0

// read the buttons
int read_LCD_buttons()
{
  adc_key_in = analogRead(0);      // read the value from the sensor 
  // my buttons when read are centered at these values: 0, 144, 329, 504, 741
  // we add approx 50 to those values and check to see if we are close
  if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
  if (adc_key_in < 50)   return btnRIGHT;  
  if (adc_key_in < 250)  return btnUP; 
  if (adc_key_in < 450)  return btnDOWN; 
  if (adc_key_in < 650)  return btnLEFT; 
  if (adc_key_in < 850)  return btnSELECT; 
}

void setup()
{
  lcd.begin(16, 2);              // start the library
  lcd.setCursor(0,0);
  lcd.print("Select an option"); // print a simple message
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
}

void loop()
{
  {
  lcd.setCursor(9,1);            // move cursor to second line "1" and 9 spaces over
  lcd.setCursor(0,1);            // move to the begining of the second line
  lcd_key = read_LCD_buttons();  // read the buttons
  switch (lcd_key)               // depending on which button was pushed, we perform an action
  {
  case btnUP:
    {

     myCounter ++; 
    if (myCounter > upperLimit) myCounter = upperLimit;
      lcd.print("One more      ");
      lcd.setCursor(14,2);
      lcd.print(myCounter);
      delay(1000);
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
  case btnDOWN:
    {

      myCounter --;
   if (myCounter < lowerLimit) myCounter = lowerLimit;
      lcd.print("One less    ");
      lcd.setCursor(14,2);
      lcd.print(myCounter);
      delay(1000);
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
  case btnSELECT:
    {
      lcd.print("Good choice!    ");
      if (myCounter >= 1 && myCounter <= 5)
        {
          digitalWrite(2,HIGH);
          digitalWrite(3,HIGH);

          switch (myCounter) {
               case 1:
                    delay(6000);
                    break;
              case 2:
                   delay(6500);
                   break;
             case 3:
                   delay(7000);
                   break;
             case 4:
                   delay(7500);
                   break;
            case 5:
                   delay(8000);
                   break;
          }
          digitalWrite(2,LOW);
          digitalWrite(3,LOW);
        }
  
      delay(1000);
      lcd.setCursor(0,2);
      lcd.print("            ");
    break;
    }
  case btnRIGHT:
    {
      lcd.print("");
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
  case btnLEFT:
    {
      lcd.print("");
      lcd.setCursor(0,2);
      lcd.print("            ");
      break;
    }
 
   }
  }
}

Yes, you must use the pinMode function to select that the pin is an output.

Thank you,

Where should I put the pinMode? In the void Setup, void Loop, or at the beginning of the code?

Yes, you should select de pinMode to be OUTPUT in the setup() function. Like you have in the last code:

void setup()
{
(...)
  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
}

This was one of the problems. I never understand (before you point that) that you don't do the for cycle in the first program:

void setup()
{
  int i;
  lcd.begin(16, 2);              // start the library
  lcd.setCursor(0,0);
  lcd.print("Select an option"); // print a simple message
  {
    pinMode(relayPin[i],OUTPUT);
  }
}