How To Scroll String Only On Second Line Using 2x16 LCD?

This is a duplicate from my question posted on arduino.stackexchange! I don’t want to make anyone anger for posting only a link.

I’m trying to scroll a string in the second row of the LCD while letting the string on the first row stay intact. I use Serial to run that part of the code as you can see. It work at first but when I try to make it run again it doesn’t display anything on the second row.

I borrowed the code from :

http://code.nishantarora.in/arduino-lcd-projects/src/3f10686e7464665c5c59d7be772c00af7a4a93e8/scrollOneLine/scrollOneLine.ino?at=master

And I made some changes:

// include the library
#include <LiquidCrystal.h>

// init the lcd display according to the circuit
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);

// it's a 16x2 LCD so...
int screenWidth = 16;
int screenHeight = 2;

String line1;
String line2;

int stringStart, stringStop = 0;
int scrollCursor = screenWidth;

String CompleteString;
String stringArray[] = {"s=Plane", "i=Car", "h=Boat", "u=Rocket", "d=Jet",  "p=Submarine", "l=Truck", "b=Bicycle", "m=Skate", "enter=Train"};

String string1 = "String";

int countMovement=0;
int arraylimit = 9;

void setup() {

   lcd.begin(screenWidth,screenHeight);
   Serial.begin(9600);

}

void loop(){

   char ser = Serial.read();

   if ( ser == 'c' ) {  
     CompleteString="";

     for (int i = 0 ; i <= arraylimit; i++) {
        CompleteString += stringArray[i] + " "; // Convert String Array To Single String
     }

     roop(string1,CompleteString);
  }

}

void roop(String line1, String line2) {

  countMovement = 0;

  while ( ( countMovement ) < (line2.length() + screenWidth )  ) {

     lcd.setCursor(scrollCursor, 1);
     lcd.print(line2.substring(stringStart,stringStop));
     lcd.setCursor(4, 0); // 1 = word eat array of words very cool
     lcd.print(line1);
     delay(300);
     lcd.clear();

     if(stringStart == 0 && scrollCursor > 0){
        // Serial.println(scrollCursor);     
        scrollCursor--;
        stringStop++;
     } else if (stringStart == stringStop){
        stringStart = stringStop = 0;
        scrollCursor = screenWidth;
     } else if (stringStop == line1.length() && scrollCursor == 0) {
        stringStart++;
     } else {
       stringStart++;
       stringStop++;
     }

     countMovement++;

  }

  lcd.setCursor(4, 0);
  lcd.print(line1);

}

From what I can see using Serial as debugging is that the problem resides in the function “roop” and in specific the line:

if(stringStart == 0 && scrollCursor > 0){

It seems that the statement is being pass on and so it doesn’t move the string as it’s suppose to. I could be wrong but placing a Serial call in there yields no result the second time the function is called but the first time it did.

Any help would be much appreciated! And I know the community will be grateful too since it’s difficult from what I can see in post to achieve this and make it autonomous so that no big modifications needs to be done.

Don’t use Strings, use C strings, less memory and issues down the road.

How long will the text be?

I made this a while back, Im not sure if it what your looking for but give it a try.
Note the library, change the parts to allow it to work on your LCD.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#define N_CHARS  ((sizeof(MessageOut)/sizeof(MessageOut[0]))-1)
#define N_CHARS2  ((sizeof(MessageOut2)/sizeof(MessageOut2[0]))-1)
LiquidCrystal_I2C lcd(0x20,20,4);  // set the LCD address to 0x20 for a 16 chars and 2 line display

char MessageOut[21];
char MessageOut2[21];
  
int index = 19, index2 = 0;
unsigned long oldTime = 0, oldTime2 = 0;

void setup()
{
  lcd.init();                      // initialize the lcd  
  lcd.backlight();
}

void loop() 
{
  setHeadingRight("Hello", 0, 1000); // message, row, duration
  setHeadingLeft("Welcome", 1, 500);
}

void setHeadingRight(char * msg, byte row, unsigned long duration) 
{
  strncpy(MessageOut, msg, sizeof(MessageOut));
  if(millis() - oldTime > duration) // check the difference of the current time "millis()" to the previous time "oldTime" against the duration you want.
  {
    oldTime = millis(); // update oldTime with the current time
    if(index >= 0) // make sure the index does not go under 0
    { 
      index--; // decrecment index by 1
      for (int i = 0; i < N_CHARS; i++) // this part here displays the message on the display
      {
        lcd.setCursor(i,row); // set the column to show the element in the array
        if(index == N_CHARS) index = 0; // set index back to 0 if the index has reached the arrays max size.
        
        if(MessageOut[index++] != NULL) // if the element @ index is anything but NULL, show it.
          lcd.print(MessageOut[index-1]);
        else 
          lcd.print(' '); // if the element @ index is NULL, display a space.  	
      }
    }
    else index = 19; // if index is less than 0, then set it back to 19
  }
}

void setHeadingLeft(char * msg, byte row, unsigned long duration2) 
{
  strncpy(MessageOut2, msg, sizeof(MessageOut2));
  if(millis() - oldTime2 > duration2)
  {
    oldTime2 = millis();
    if(index2 < 20) // check to see if index2 is under the array max size
    {
      index2++; // increment index
      for (int i = 0; i < N_CHARS2; i++) // same as above
      {
        lcd.setCursor(i,row);
        if(index2 == N_CHARS2) index2 = 0;
        
        if(MessageOut2[index2++] != NULL)
          lcd.print(MessageOut2[index2-1]);
        else 
          lcd.print(' ');	
      }
    }
    else index2 = 0; // otherwise set it back to 0
  }
}

Awesome Bro! I'll give it a shot and thanks for the explanation. I'll mess up with your code and post the results :grin:

Keep in mind the text has a size limit of 20 characters, anymore and it will go beyond the array size.

I haven't worked out how to do larger strings.

It work! The limit for “MessageOut” and “MessageOut2” is around 70 char until the largest message overlaps the other row.

I used this:

 char * stringd = {"s=Plane i=Car h=Boat u=Rocket d=Jet p=Submarine"}; // More bllcrp

I know a constant is better for a fixed integer but for testing im using that. So if I send or read a message larger than the “70” char then everything goes wrong. I can create an “IF” statement and use “int total = strlen(Serialstringd)” to get the size and add a header at the end to determine a continuous character display or there is no point on doing that? I mean splitting the values received over serial. It is better to simply wait for the first string to finish before sending another message?