Major Work- 2x16 LCD Shield 'select' button and arduino code problem

Hello,
I’ve been looking online for awhile now, and I just can’t seem to figure out how to set a function for the ‘select’ button on the 2x16 LCD Shield (connected to an Arduino Uno). I have tried a number of codes from similar projects, altering them to suit mine, but it doesn’t do what I tell it to do. *Note I have also attempted doing one myself.

My end goal is for the user to press ‘select’ (on the LCD) which will allow the ultrasonic sensor (US) to measure the distance from its placement on the wall (e.g 40cm, above the bathtub’s top edge) to the bottom of the empty bathtub. The code will then take away that 40cm + another 10cm (as an overflow barrier) equalling 50cm in total, revealing the maximum depth (for example 60cm- which equals the distance from the bottom of the bathtub to 10cm from the top). The arduino now knowing the distance, will minus the height/depth the user sets for their water height (e.g 35cm) from the maximum depth measurement (60cm).

The simple calculation would be something like this 60cm (maximum depth) - 35cm (distance set by user) = 25cm (which is the gap, between the water’s surface/level (35cm) and the 10cm mark before the top).

The code below shows some of my work, however I’d need some help altering the code to fit want I stated above.

Code:

// include the library code:
#include <LiquidCrystal.h>
#define echoPin 1
#define trigPin 2
#define solenoidPin 3
#define buttonsPin A0
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 8, en = 9, d4 = 4 , d5 = 5, d6 = 6, d7 = 7;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(3, OUTPUT); // connected to S terminal of Relay
  pinMode(A0, INPUT);
}
void loop() {
  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  lcd.setCursor (1, 1); // put your setup code here, to run once:
  lcd.setCursor (0, 0);
  // Print a message to the LCD.
  delay (250);
  lcd.setCursor (0, 0);
  lcd.print("Maximum Distance:");
  lcd.setCursor(1, 1);
  lcd.print("(Hold Select)");
  delay (2000);
  lcd.clear ();
  lcd.setCursor(1, 0);
  lcd.print("Wait till the");
  lcd.setCursor (1, 1);
  lcd.print("screen clears");
  delay (1200);
  int x;
  x = analogRead (0);
  lcd.setCursor(10, 1);
  if (x < 800) {
    lcd.clear ();
    delay (10000);
    Serial.println(x, DEC);
  }
    // Ultrasonic sensor function
    float duration, distance;
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    duration = pulseIn(echoPin, HIGH);
    distance = (duration / 2) * 0.0344;
  }

or this code which is used to set a minimum height (50) before the solenoid/relay shuts off.

#define echoPin 1
#define trigPin 2
#define solenoidPin 3
 
void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(3, OUTPUT); // connected to S terminal of Relay 
}

void loop() {
  float duration, distance;
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) * 0.0344;
  
  if (distance >= 550 || distance <= 50){
    Serial.print("Distance = ");
    Serial.println("Off");
    digitalWrite(solenoidPin, LOW); // turn relay off

  }
  else {
    Serial.print("Solenoid On Distance = ");
    Serial.print(distance);
    Serial.println(" cm");;
    digitalWrite(solenoidPin, HIGH); // turn relay on 

  }
  delay(500); 

Please supply a link to the actual LCD board you are using.

Usually, press buttons/switches are digital, either a 1 or 0 read with digital read, but if the instructions for the board say use an analogue pin, because they do some form of manipulation of all the switches, that’s fine, but some documentation would help.

In the meantime, don’t worry about testing if < 800, just print the value you get. Try it for each button, and combinations of buttons.

Hey, here the link to the LCD Shield: https://www.jaycar.com.au/arduino-compatible-2-x-16-lcd-controller-module/p/XC4454

I’m not quite sure if it specifies, but please take a look.

Thank you for that.

The board is designed to sit on top of an Arduino Uno, that way all the connections are done automatically, otherwise you need to connect all the pins manually. The up/down/left/right/select buttons are connected to a voltage divider, the output of which is connected to analog pin 0.

Write a simple routine to read the button keys (not the reset key, it will reset the Uno) and display the value on the console or LCD. Differences in resistors voltages can affect the readings. When you know what values you get, you can work from there.

Make sure you’re not using any pins already in use by the LCD, or the serial port.
Pulse in routine returns an unsigned long, not a float.

Hopefully that’s a start

Hey, yes I highly appreciate your answer, but I’m still a little confused when you were talking about ‘writing a simple routine to read the button keys’. Do I need to change anything in my code to get the values? Could you please give an example.

I have said do not use pins already in use for other purposes.

Yet you are with
Serial.begin(9600);

All Arduino boards have at least one serial port (also known as a UART or USART): Serial. It communicates on digital pins 0 (RX) and 1 (TX) as well as with the computer via USB. Thus, if you use these functions, you cannot also use pins 0 and 1 for digital input or output.

Write down all the pins on the Arduino, and then write beside them what is connected to them. That includes all digital and analog pins used by LCD, and the serial port.

Once you have that you can work out where to connect the sensor. There is no point trying to fix the code, which is pretty close, until you get the connections right.

If you don’t already have it find a reference manual for the LCD.

2 Likes

One of the benefits of open source hardware is that the documentation of a board maker can be used with boards from other makers. This is a link to a what I think is a compatible board to the one you using, with links to documentation.

https://core-electronics.com.au/lcd-keypad-shield-for-arduino.html

1 Like

Hey I was able to set the LCD so I can enter in a value, and save it.

#include <LiquidCrystal.h>

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


int a = 0; //used for moving the cursor left or right. 

byte numbr[4];  // This will hold 4 bytes, and if global, will init to all zeros
byte indx;  //This will hold an index to the array. If global, it will init to 0
int enteredValue;  // this will hold the final value entered

void setup() {
  lcd.begin(16, 2);
  lcd.setCursor(0,0);
  lcd.print("Enter Height");

  lcd.setCursor(0,1);
  lcd.print("in cm:");
  
}

void loop() {

  int x;  
  x = analogRead (0);
  lcd.setCursor(a,1);

  
  if (x < 60) {
   //right button
   if (indx < 3 ) { 
     indx++;
     a++;
   }
  
  
  }
  else if (x < 200) {
  //up button
   if (numbr[indx] < 90 ) {
     numbr[indx]++;
     lcd.setCursor(7,1);
    lcd.print(numbr[indx]);
   
   }

    
  }
  else if (x < 400){
  //down button
    if (numbr[indx] > 0 ) {
    numbr[indx]--;
    lcd.setCursor(7,1);
    lcd.print(numbr[indx]);
    }

  }
   else if (x < 600){
   //left button
     if (indx > 0) {
     indx--;
     a--;
     }

     
  }
  else if (x < 800){
//want to use this to save the value and move onto another function. 
enteredValue = 0;
   for (int i = 0; i < 4; i++) {
     enteredValue = (enteredValue * 10) + numbr[i];

    lcd.clear();                                             
    lcd.setCursor(3,0);
    lcd.print("Value saved");
    delay(2000);
    

  }
  }
  
  delay(100);

Working from the code, is there anyway that allows the ultrasonic sensor to read the set value and stop the solenoid/relay module at that point. In my previous code (below), I was able to stop it when the distance exceeded the maximum and minimum heights.

#define echoPin 1
#define trigPin 2
#define solenoidPin 3
 
void setup() {
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(3, OUTPUT); // connected to S terminal of Relay 
}

void loop() {
  float duration, distance;
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) * 0.0344;
  
  if (distance >= 550 || distance <= 50){
    Serial.print("Distance = ");
    Serial.println("Off");
    digitalWrite(solenoidPin, LOW); // turn relay off

  }
  else {
    Serial.print("Solenoid On Distance = ");
    Serial.print(distance);
    Serial.println(" cm");;
    digitalWrite(solenoidPin, HIGH); // turn relay on 

  }
  delay(500); 
}

You still have the same errors in your distance sensor code.

  1. pulseIn returns an unsigned long, not a float. Refer to
    https://www.arduino.cc/reference/en/language/functions/advanced-io/pulsein/

  2. You are still using pin 1 for two different purposes. It is hard-wired to the serial port, which you send your debug/progress messages on, and as the echo pin on the distance sensor. You must move the distance sensor to a different pin

You can merge the two routines. Take the definitions and setup from the distance sensor routine, and merge it with the definitions and setup from the key routine, and the loop code from the distance sensor before the final curly brace in the key routine.

Adjust the delays as required so you don’t sit waiting unnecessarily.

Also check the print statements in the distance sensor routine. Some of them are not printing the data.

2 Likes

I’ve adjust the code to all the things you’ve said. I haven’t tested to see if it’ll stop the solenoid when the desired height is inputted, but I’ll let you know the results.
Nevertheless, does the code still look incorrect to you?

#include <LiquidCrystal.h>
#define echoPin 2
#define trigPin 3
#define solenoidPin 7
 

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


int a = 0; //used for moving the cursor left or right. 

byte numbr[4];  // This will hold 4 bytes, and if global, will init to all zeros
byte indx;  //This will hold an index to the array. If global, it will init to 0
int enteredValue;  // this will hold the final value entered

void setup() {
  lcd.begin(16, 2);
  lcd.setCursor(0,0);
  lcd.print("Enter Height");

  lcd.setCursor(0,1);
  lcd.print("in cm:");
  
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(3, OUTPUT); // connected to S terminal of Relay
  
}

void loop() {

  int x;  
  x = analogRead (0);
  lcd.setCursor(a,1);

  
  if (x < 60) {
   //right button
   if (indx < 3 ) { 
     indx++;
     a++;
   }
  
  
  }
  else if (x < 200) {
  //up button
   if (numbr[indx] < 90 ) {
     numbr[indx]++;
     lcd.setCursor(7,1);
    lcd.print(numbr[indx]);
   
   }

    
  }
  else if (x < 400){
  //down button
    if (numbr[indx] > 0 ) {
    numbr[indx]--;
    lcd.setCursor(7,1);
    lcd.print(numbr[indx]);
    }

  }
   else if (x < 600){
   //left button
     if (indx > 0) {
     indx--;
     a--;
     }

     
  }
  else if (x < 800){
//want to use this to save the value and move onto another function. 
enteredValue = 0;
   for (int i = 0; i < 4; i++) {
     enteredValue = (enteredValue * 10) + numbr[i];

    lcd.clear();                                             
    lcd.setCursor(3,0);
    lcd.print("Value saved");
    delay(2000);
    
  }
  }
  
  delay(100);
  
  unsigned long duration, distance;
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) * 0.0344;
  
  if (distance >= 550 || distance <= 50){
    Serial.print("Distance = ");
    Serial.println("Off");
    digitalWrite(solenoidPin, LOW); // turn relay off

  }
  else {
    Serial.print("Solenoid On Distance = ");
    Serial.print(distance);
    Serial.println(" cm");;
    digitalWrite(solenoidPin, HIGH); // turn relay on 

  }
  delay(100); 
}

You have the solenoid using the same pin as the LCD. Pin 7.

I really can’t stress enough that you need to write down the pins on the board, on a sheet of paper and then what is attached to it. It can prevent clouds of ugly blue smoke and serious damage to your boards.

I won’t say the code is pretty, but if it works, and you understand it in a month’s time, then it’s good enough. Practice and experience make it a whole lot easier.

Also note I gave you links to sites. There is a lot of good information available, for free, on the web. Heaps on the arduino.cc website about Arduino specifics, and places like the tutorials section here.

But you have your first programs running, hopefully without blowing anything. Keep at it and most of all have fun. :stuck_out_tongue_winking_eye:

1 Like

Hey I have my final code here, I’ve adjusted the solenoid pin so that it’s in the correct spot, on both the code and physical device. However, when I set the height and hit the ‘select’ key, it does doesn’t turn the solenoid off when the distance say off, or the solenoid on when the distance reads a measurement.

*Edit- It is now not taking the set value (or height) into account, it is reading above the set height.

#include <LiquidCrystal.h>
#define echoPin 2
#define trigPin 3
#define solenoidPin 11
 

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


int a = 0; //used for moving the cursor left or right. 

byte numbr[4];  // This will hold 4 bytes, and if global, will init to all zeros
byte indx;  //This will hold an index to the array. If global, it will init to 0
int enteredValue;  // this will hold the final value entered

void setup() {
  lcd.begin(16, 2);
  lcd.setCursor(0,0);
  lcd.print("Enter Height");

  lcd.setCursor(0,1);
  lcd.print("in cm:");
  
  Serial.begin (9600);
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  pinMode(3, OUTPUT); // connected to S terminal of Relay
  
}

void loop() {

  int x;  
  x = analogRead (0);
  lcd.setCursor(a,1);

  
  if (x < 60) {
   //right button
   if (indx < 3 ) { 
     indx++;
     a++;
   }
  
  
  }
  else if (x < 200) {
  //up button
   if (numbr[indx] < 90 ) {
     numbr[indx]++;
     lcd.setCursor(7,1);
    lcd.print(numbr[indx]);
   
   }

    
  }
  else if (x < 400){
  //down button
    if (numbr[indx] > 0 ) {
    numbr[indx]--;
    lcd.setCursor(7,1);
    lcd.print(numbr[indx]);
    }

  }
   else if (x < 600){
   //left button
     if (indx > 0) {
     indx--;
     a--;
     }

     
  }
  else if (x < 800){
//want to use this to save the value and move onto another function. 
enteredValue = 0;
   for (int i = 0; i < 4; i++) {
     enteredValue = (enteredValue * 10) + numbr[i];

    lcd.clear();                                             
    lcd.setCursor(3,0);
    lcd.print("Value saved");
    delay(200);
    
  }
  }
  
  delay(100);
  
  unsigned long duration, distance;
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
 
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  duration = pulseIn(echoPin, HIGH);
  distance = (duration / 2) * 0.0344;
  
  if (distance >= 550 || distance <= 5){
    Serial.print("Distance = ");
    Serial.println("Off");
    digitalWrite(solenoidPin, LOW); // turn relay off

  }
  else {
    Serial.print("Solenoid On Distance = ");
    Serial.print(distance);
    Serial.println(" cm");;
    digitalWrite(solenoidPin, HIGH); // turn relay on 

  }
  delay(100); 
}

Where is the solenoid pin set to output?

Is this line in the setup meant to be it?
pinMode(3, OUTPUT); // connected to S terminal of Relay

Yea thanks I changed it. I also changed the delay from 200 to 20.

    lcd.clear();                                             
    lcd.setCursor(3,0);
    lcd.print("Value saved");
    delay(20);

The only problem is, that the value/height set, only lasts a few seconds, before it reads below the measurement again. Can I changed that so it lasts for around 5 minutes?

If the loop is running too fast, just adjust the appropriate delay. Maximum delay is about 4 billion milliseconds. 5 minutes is 300000 milliseconds.
(5 * 60 * 1000) minutes times seconds per minute times 1000 milliseconds per second.

I can’t seem to figure out where I place that.
Is it near

//want to use this to save the value and move onto another function. 
enteredValue = 0;
   for (int i = 0; i < 4; i++) {
     enteredValue = (enteredValue * 10) + numbr[i];

or

  }
  delay(200); 
}

from the code.

It’s the last one, just before the closing } on the loop function.

  }
  delay(300000); 
}

When I do that it slows the whole function down.