LCD displays text sent by serial monitor after pressing a button

Hello to everyone,

I'm a master student in Interaction design and I'm a beginner in Arduino field, but I really want to improve my knowledge in it as much as possible... And I need of you!

I'm developing a simple project with an LCD screen (16x2) connected to a push button, where I can send a message to the display typing on the serial monitor and the message is displayed for 10 sec after that the button has been pressed. After these 10 seconds, the display turns itself off automatically and I can send a new message to display on it and so on!

This is the code that I'm using to display text on the LCD through the Arduino sketch (it works):

#include <LiquidCrystal.h>

#define LCD_LIGHT_PIN A4
const int buttonPin = 8;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int buttonState = 0;

void setup() {
// Setup the number of columns and rows:
lcd.begin(16, 2);
lcd.noDisplay();

// Set the button pin as an input:
pinMode(buttonPin, INPUT);

// Set the LCD display backlight pin as an output:
pinMode(LCD_LIGHT_PIN, OUTPUT);

// Turn off the LCD backlight:
digitalWrite(LCD_LIGHT_PIN, LOW);
}

void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH)
{
// Print some text to the LCD:
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Hello");
lcd.setCursor(0, 0);
lcd.print("world");
// Turn the backlight on:
digitalWrite(LCD_LIGHT_PIN, HIGH);

// Display the text on the LCD.
lcd.display();

// Wait for 10 seconds and then turn off the display and backlight.
delay(10000);
lcd.noDisplay();
digitalWrite(LCD_LIGHT_PIN, LOW);
}
}

This is the modified code that I'm trying to use to send message through the serial monitor but it doesn't works:

#include <LiquidCrystal.h>

#define LCD_LIGHT_PIN A4
const int buttonPin = 8;
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
int buttonState = 0;

void setup(){
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
lcd.noDisplay();

pinMode(buttonPin, INPUT);

pinMode(LCD_LIGHT_PIN, OUTPUT);

digitalWrite(LCD_LIGHT_PIN, LOW);

// initialize the serial communications:
Serial.begin(9600);
}

void loop()
{
// when characters arrive over the serial port...
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());
}
}

{
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH)
{
if (Serial.available()) {
// wait a bit for the entire message to arrive
delay(100);
// clear the screen
lcd.clear();
// read all the available characters
while (Serial.available() > 0) {
// display each character to the LCD
lcd.write(Serial.read());

digitalWrite(LCD_LIGHT_PIN, HIGH);

lcd.display();

delay(10000);
lcd.noDisplay();
digitalWrite(LCD_LIGHT_PIN, LOW);

}
}
}
}
}

Now, my question is: how can I write properly the modified code? I need to use the serial monitor to send the message on the screen and not to type what I want to read on the arduino sketch.

Hoping to have been clear,
thanks in advance

Edoardo

Edoardo
please repost your code with the markup. LIKE THIS:

[code]
    // YOUR CODE HERE
[/code ] //<<== REMOVE BLANK SPACE

Done! :slight_smile:

Here it is the code that I'm trying to make works... but it didn't! Anyone might help me?!?

#include <LiquidCrystal.h>

#define LCD_LIGHT_PIN A4
const int buttonPin = 8;  
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  
int buttonState = 0;

void setup(){
    // set up the LCD's number of columns and rows: 
  lcd.begin(16, 2);
  lcd.noDisplay();
  
  pinMode(buttonPin, INPUT);

    pinMode(LCD_LIGHT_PIN, OUTPUT);

   digitalWrite(LCD_LIGHT_PIN, LOW);
  
  // initialize the serial communications:
  Serial.begin(9600);
}

void loop() 
{
  // when characters arrive over the serial port...
  if (Serial.available()) {
    // wait a bit for the entire message to arrive
    delay(100);
    // clear the screen
    lcd.clear();
    // read all the available characters
    while (Serial.available() > 0) {
      // display each character to the LCD
      lcd.write(Serial.read());
    }
  }


{  
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH)
  {
       if (Serial.available()) {
    // wait a bit for the entire message to arrive
    delay(100);
    // clear the screen
    lcd.clear();
    // read all the available characters
    while (Serial.available() > 0) {
      // display each character to the LCD
      lcd.write(Serial.read());

       digitalWrite(LCD_LIGHT_PIN, HIGH);

       lcd.display();

       delay(10000);
    lcd.noDisplay();
    digitalWrite(LCD_LIGHT_PIN, LOW);
    
  
    }
  }
}
}
}

Here it is the code that I'm trying to make works... but it didn't!

What does it do or not do that is wrong ?

Actually what I'm trying to satisfy it is send a message on the lcd through the serial monitor. But when I type into the serial monitor text box and I press "send"... nothing appears on my lcd! :neutral_face:

In the code below I got a if statement about buttonState and and if about Serial.available, is it correct to have this two if statement one after the another or that's not possible? Do I need something in between?

{  
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH)
  {
       if (Serial.available()) {
    // wait a bit for the entire message to arrive
    delay(100);
    // clear the screen
    lcd.clear();
    // read all the available characters
    while (Serial.available() > 0) {
      // display each character to the LCD
      lcd.write(Serial.read());

       digitalWrite(LCD_LIGHT_PIN, HIGH);

       lcd.display();

       delay(10000);
    lcd.noDisplay();
    digitalWrite(LCD_LIGHT_PIN, LOW);
    
  
    }
  }
}
}

is it correct to have this two if statement one after the another or that's not possible?

That is perfectly possible and you could even combine them together like this

if (buttonState == HIGH && Serial.available()) {

In the code you posted you seem to be trying to read the serial data twice. Once at the start of loop() when the LCD display is turned off, then later when the button is pressed but by then there will be no serial data to read.

What I want to achieve it something like:

-send a message through the serial monitor on the lcd
-the lcd gets the message but it is still turned off
-when the push button is pressed the lcd turns on and shows up the message for x seconds
-later on this x seconds the lcd is turned off automatically again

You told me that there is no serial data to read, what does it means? I want that the data that is going to be read is what has been sent to the serial monitor

You told me that there is no serial data to read, what does it means?

It means that when you try to read the serial data for the second time (after pressing the button) the serial data has already been read.

Try reading the serial input and printing it on the LCD with nothing else in the program. You have a section of code that does this already.

 // when characters arrive over the serial port...
  if (Serial.available()) {
    // wait a bit for the entire message to arrive
    delay(100);
    // clear the screen
    lcd.clear();
    // read all the available characters
    while (Serial.available() > 0) {
      // display each character to the LCD
      lcd.write(Serial.read());
    }
  }

Do this with the LCD enabled. Does it work ?
If so then do it with the LCD disabled. Then, when the button is pressed enable the LCD. There is no serial data to read at this point because it has already been read and displayed.

Thank you very very very much for your time and for the code improvements! Really appreciate it! This evening I gonna try what you suggest me and I'll tell you if it works or not :slight_smile:

Edoardo

As I suggested, get the basics working then you can move on. Let us know your results.

Finally I found time to try to work on it! Now I can send messages through the serial monitor onto the lcd, and when I press the button I can see the message appear. But the problem is that the characters are displayed one after the other, and not all the text in once. I mean: if I type a simple "Hello" and I send it onto the lcd, when I press the button, the screen displays first the "h" after a bit "e" after a bit the "l" and so on! And furthermore I cannot use the second row of the lcd (it is a 16,2 screen), I can just send messages on the first line.

My questions are:
How can I display the whole text onto the lcd in once?
How can I use the second row of the screen?

This is the sketch that I got:

//Turning ON/OFF the LCD 

#include <LiquidCrystal.h>

#define LCD_LIGHT_PIN A4
const int buttonPin = 8;  
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  
int buttonState = 0;


void setup() {  
   lcd.begin(16, 2);
   Serial.begin(9600);
  lcd.noDisplay();

   pinMode(buttonPin, INPUT);

    pinMode(LCD_LIGHT_PIN, OUTPUT);

   digitalWrite(LCD_LIGHT_PIN, LOW);
   
   
}

void loop() {  
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH)
  {
       
  // when characters arrive over the serial port...
  if (Serial.available()) {
    // wait a bit for the entire message to arrive
    delay(1000);
    // clear the screen
    lcd.clear();
    // read all the available characters
    while (Serial.available() > 0) {
      // display each character to the LCD
      lcd.write(Serial.read());
    

       digitalWrite(LCD_LIGHT_PIN, HIGH);

       lcd.display();

       delay(1000);
    lcd.noDisplay();
    digitalWrite(LCD_LIGHT_PIN, LOW);
    
  
  }
}}}

Thanks in advance again for your time :wink:

the screen displays first the "h" after a bit "e" after a bit the "l" and so on!

Is each character arriving with a 1 second interval by any chance ? The sort of thing that might be caused by

delay(1000);

for instance.

Try Auto Formatting (Ctrl/T) to get rid of the }}} and you might be able to see what is going on.

Yes it is, each character arrives with 1 sec interval! But the problem is: whether I change the delay in a shorter one (i.e. delay 100), also the light of the lcd depends from that delay and I cannot see anything on the screen cause the light goes on and off to fast.
How can I set up a longer delay for "life" light of the screen and one for get the text in once?

thanks for the suggestion of Auto Formatting!

The problem is that the delay(1000) is inside the while (Serial.available()) loop. Why not put all the available characters on the LCD before enabling the display then delaying if you want to ?

I had hoped that formatting the code so that you could see what was in each code block.

I did as you advice me and it's perfectly working! Now the lcd get the whole text in once. Super thank you very much! :slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile: :slight_smile:

Now, other issue! How can I get text on the second row automatically? I mean, if I type more than 16 characters, how the display can move to the second row automatically?!?

if I type more than 16 characters, how the display can move to the second row automatically?!?

I don't know if you can do it automatically but by counting the number of characters received and displayed you can use lcd.setCursor() to move to the second line at the right point.

I digged a lot about lcd.setCursor on internet and I also tried hundred of option in order to make the screen working on both 2 lines, but nothing happened!

What I got is something like:

int charactersPrinted = 0;
while (Serial.available() > 0) {
  lcd.write(Serial.read());
  charactersPrinted++;
  if (charactersPrinted == 16) {
    // move to the second line
  }
}

but I cannot understand how I could display text on the second line after the 16th character! What I want to have is that, after the 16th character, the 17th appears on the second row! What I might do to move on the new line?

In your trials of hundreds of options did you come a cross the setCursor() method of the LCD library ?

Try this

byte lcdCurrentColumn = 0;
byte lcdCurrentLine = 0;
while (Serial.available() > 0)
{
  lcd.setCursor(lcdCurrentColumn, lcdCurrentLine);
  lcd.write(Serial.read());
  lcdCurrentColumn++;
  if (lcdCurrentColumn == 16)
  {
    lcdCurrentLine++;
    lcdCurrentColumn = 0;
  }
}

I changed the name of some variables to make it more obvious what is going on.

Oh woooow yes it's running now! As you did is quite clear! :o

There is only one more problem and is that the lcd.clear() doesn't work! After that I send a message on the lcd and it come on second row... it's just goes forward on that row without restart on the first row!

Is it a problem of lcd.clear in the wrong place? Or I need to any value to restart the cursor somewhere? :cry:

Right now this is my code:

#include <LiquidCrystal.h>

#define LCD_LIGHT_PIN A4
const int buttonPin = 8;  
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  
int buttonState = 0;
byte lcdCurrentColumn = 0;
byte lcdCurrentLine = 0;


void setup() {  
  lcd.begin(16, 2);
  lcd.setCursor(0,0);
  lcd.setCursor(1,0);
  Serial.begin(9600);
  lcd.noDisplay();

  pinMode(buttonPin, INPUT);

  pinMode(LCD_LIGHT_PIN, OUTPUT);

  digitalWrite(LCD_LIGHT_PIN, LOW);


}

void loop() {  
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH)
  {

    // when characters arrive over the serial port...
    if (Serial.available()) {
      // wait a bit for the entire message to arrive
      delay(100);
      // clear the screen
      lcd.clear();

      // read all the available characters
      while (Serial.available() > 0) {


        lcd.setCursor(lcdCurrentColumn, lcdCurrentLine);
        lcd.write(Serial.read());
        lcdCurrentColumn++;
        if (lcdCurrentColumn == 16)
        {
          lcdCurrentLine++;
          lcdCurrentColumn = 0;

        }
      }

      digitalWrite(LCD_LIGHT_PIN, HIGH);

      lcd.display();
      delay(5000);

      lcd.noDisplay();


      digitalWrite(LCD_LIGHT_PIN, LOW);


    }
  }
}

I tried several attempt with the setCursor example in the library as well, but nothing happened!

You need to reset lcdCurrentColumn and lcdCurrentLine to zero before starting to display a second or subsequent message.