Using both rows on an LCD screen

I am working on a project involving a 16x2 LCD screen that uses an i2c driver. I am struggling to get the output to be displayed on the second row once the first row is fully occupied. When the first row is full, any output just does not get printed, however, it appears in the serial monitor. I am not very familiar with the liquidcrystal_i2c library
Basically what the project does is convert morse code into text. I used https://github.com/DeviNoles/Morse_Code_Youtube/blob/main/morsebuzz.ino for the code and made some minor changes like removing the buzzer.
Any ideas?
The code:

#include <LiquidCrystal_I2C.h>
#include <Wire.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

int led = 8;

int buttonState = 0;
bool lastButtonState = false;
int startPressed = 0;
int endPressed = 0;
int holdTime = 0;
String buff = "";

void setup() {
  lcd.begin();
  Serial.begin(9600);
  pinMode(led, OUTPUT);
}

void loop() {
  buttonState = digitalRead(led);

  if (buttonState == LOW) {
    if ((millis() - endPressed) % 65536 > 500) {
      if (buff != "") {
        Serial.println(retBuf());
        clearBuf();
        lastButtonState = true;
      }
    }
    if ((millis() - endPressed) % 65536 > 1500) {
      if (lastButtonState == true) {
        Serial.println("SPACE HERE");
        lcd.print(" ");  // Print a space on the LCD
        lastButtonState = false;
      }
    }
  } else if (buttonState == HIGH) {
    startPressed = millis();
    updateState();
  }
}

void updateState() {
  while (digitalRead(led) == HIGH) {
    endPressed = millis();
  }

  holdTime = endPressed - startPressed;
  Serial.println(holdTime);

  if (holdTime < 500) {
    Serial.println("DIT");
    buff = buff + ".";
  } else if (holdTime >= 500) {
    Serial.println("DAH");
    buff = buff + "-";
  }
}

String retBuf() {
  return morseToChar(buff);
}

String morseToChar(const String &morse) {
  static String characters[] = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.", "....", "..", ".---",
                                "-.-", ".-..", "--", "-.", "---", ".--.", "--.-", ".-.", "...", "-",
                                "..-", "...-", ".--", "-..-", "-.--", "--..",
                                "-----", ".----", "..---", "...--", "....-", ".....", "-....", "--...", "---..", "----."};

  for (int k = 0; k < sizeof(characters) / sizeof(characters[0]); k++) {
    if (characters[k] == morse) {
      char decodedChar;
      if (k < 26) {
        decodedChar = (k + 'A');
      } else if (k < 36) {
        decodedChar = (k - 26 + '0');
      } else {
        return "ERROR"; // Morse code does not represent symbols or special characters in this example.
      }
      lcd.print(decodedChar);
      return String(decodedChar);
    }
  }

  return "ERROR";
}

void clearBuf() {
  buff = "";
}

Welcome to the forum

You will have full control of where data is printed on the LCD if you use the setCursor() function. It allows you to specify the row and column that the next thing printed will be placed in

1 Like

basically, what you're doing now is assuming that since the LCD is happily auto-updating the cursor position as you print to it, then after you've printed to the 16th position, first row, the LCD should 'know enough' to put your next printed character at first position, second row. Some LCD library may do that for you, not sure, but some won't. Generally, as @UKHeliBob suggested, it's best to expressly locate the LCD position before most/every print.
For your purposes right now, you could simply keep track of how many characters you've printed, and move the cursor directly to second row, first column after the 16th character.

However, what will you do after #32?

if you don't control the cursor after the top line is full, characters end up on line 3. since you have only 2 lines, you don't see them. that's how the chip works. (then you go to the second line and then the fourth line)

check this code which prints the line number in every col position without managing the cursor.

you'll see that the 2s end up on the third line

click to see the code
// LCD MANAGEMENT WITH https://github.com/duinoWitchery/hd44780/tree/master
#include <Wire.h>
#include <hd44780.h>                       // main hd44780 header
#include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header
hd44780_I2Cexp lcd;
const int LCD_COLS = 20;
const int LCD_ROWS = 4;

void setup() {
  int result = lcd.begin(LCD_COLS, LCD_ROWS);
  if (result) {
    Serial.print("LCD initialization failed: ");
    Serial.println(result);
    hd44780::fatalError(result);
  }

  lcd.setCursor(0, 0);

  for (int r = 0; r < LCD_ROWS; r++)
    for ( int l = 0; l < LCD_COLS; l++)
      lcd.print(r);
}

void loop() {}

after the 32 i want to clear the screen and then the following text will appear

I didn't quite understand this part of your code.
You define a pin with the name LED; int led = 8;
Then define that it will be output; pinMode(led, OUTPUT);
And then read the state of the pin; buttonState = digitalRead(led);
How will this pin change from HIGH to LOW if it is an output, and you do not use digitalWrite() at any time?
Can you explain me?

In the original code it was like this:
int buzzer = 8;
pinMode (buzzer, INPUT);
buttonState = digitalRead(buzzer); // read the button input

To do that, you need to be counting characters, so it should be easy to, after #16, do the setcursor to the second row, first position.
That should suffice, as far as your display concerns.

1 Like

Have a global counter variable such as

int cursorLocation = 0;

Right after each lcd.print(); increment the counter and test for its location. If it's 16, setCursor(0,1), if it's 32, setCursor(0,0); and reset counter to 0.

lcd.print(something);
++cursorLocation;
If (cursorLocation = 16) setCursor(0,1);
If (cursorLocation = 32) 
{
setCursor(0,0);
cursorLocation = 0;
}
1 Like

you are assuming that something was only occupying ONE character... it depends on what something was..

lcd.print("Hello"); would need to move the cursor by 5 positions (and you might have overflown the line then)

with GitHub - duinoWitchery/hd44780: Extensible hd44780 LCD library print() returns the number of char that were printed, so you could know after the fact what happened...

that library has extension for lineWrap too

So true. Thanks for catching that. I'm going to rethink this

Any class that derives from the Print class does that :wink:

true indeed

If all you need is line wrapping then I would recommend using use the hd44780 library.
It has examples for how to use it by calling the lineWrap() api function.
The hd44780 library i/o class for your display is hd44780_I2Cexp.
I would recommend that you spend at least a few minutes on the hd44780 wiki for the library and the hd44780_I2Cexp i/o class to get a feel for the library.
The library is fully LiquidCrystal and LCD API 1.0 compatible.
hd44780 library wiki

It is available in the IDE library manager.

--- bill

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.