Scroll text on LCD

Hi

I don;t remember to whom should i pay credit to the function the puts long string on the display.

I used it and it looks good but i cannot find how to limit the display to one or two round of dscrolling the test and go further with main program.

Help would be appreciated

Moshiko

LCDwrite2.ino (2.4 KB)

Small code should be posted in the post, not as attachment. You will get a lot more audience because ino files can't be opened on cell phones.

moshiko's code

/* this program shows how to write long text messages on LCD by scrolling*/

// define the chars in one LED line
#define LEDLINE 16  


#include <LiquidCrystal_I2C.h>
#include <Wire.h>  // Comes with Arduino IDE, needed  for I2C communication

/*
 * I2C interface card for LCD, 16 chars 2 line display 
 * I2C interface card connection: GND, Vcc 5v, SDA to pin A4, SCL to pin A5
 * LCD_I2c adrees 0x3F
*/
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address





// define scrolling speed for two LED lines
const int ledScrollSpeed[2]={445,450};
// define scrolling direction for two LED lines (true means right-to-left scrolling)
const boolean ledScrollDir[2]={true,true};

/////////// function to check position of the character //////////////
char charAt(char *text, int pos)
// scrolling-logic coded here
{
  if (pos<LEDLINE) return ' '; // scroll in
  else if (pos>=LEDLINE && pos<LEDLINE+strlen(text))
    return text[pos-LEDLINE]; // scroll text
  else return ' ';  // scroll out
}

////////////////////////////////////////////////
/* this function scrolles the test on top or botoom line on the LCD
 *  according to the line parameter 
 */
void scroll_text(char *text, byte line)
// scroll the LED lines
{
  long endScrool=millis()+5000;  //test
  char currenttext[LEDLINE+1];
  static unsigned long nextscroll[2];
  static int positionCounter[2]; 
  int i;
  if (millis()>nextscroll[line])
  {
    nextscroll[line]=millis()+ledScrollSpeed[line]; 

    for (i=0;i<LEDLINE;i++)
    currenttext[i]=charAt(text,positionCounter[line]+i);
    currenttext[LEDLINE]=0;    
    lcd.setCursor(0,line);
    lcd.print(currenttext);
    if (ledScrollDir[line])
    {
      positionCounter[line]++;
      if (positionCounter[line]==strlen(text)+LEDLINE) positionCounter[line]=0;
    }  
    else  
    {
      positionCounter[line]--;
      if (positionCounter[line]<0) positionCounter[line]=strlen(text)+LEDLINE-1;
    }  
  }
}
/////////// end of function /////////////////////////////////////////////////

void setup() {
  // put your setup code here, to run once:
  lcd.begin(16,2);
}

void loop() {
  
  // Scroll text in line number 0
   scroll_text("This text is for top line, it is long ",0);
   
  // Scroll text in line number 1
   scroll_text("This on bottom",1);

  // after finish the entire text display i want to continue with code, how?
   
 
}

Keep a counter; when the counter reaches a specified number of 'scrolls', you continue with the rest of the program.

Something like

void loop()
{
  // variable to count number of 'scrolls'; by default initialised to 0
  static byte scrollCount;

  if(scrollCount < 5 )
  {
    scrollCount++;
  
    // Scroll text in line number 0
    scroll_text("This text is for top line, it is long ",0);
   
    // Scroll text in line number 1
    scroll_text("This on bottom",1);

    // nothing else to do
    return;

  }
}

Thanks

but when i added the counter nothing is displayed.

it looks that the main loop is calling the function time after time and this is causing the scroll ,

If i do nothing and just add a delay in the main loop , the entire scrolling is slowed

Moshiko

Sorry, I did not look at the scroll_text function and hence did not realise it is non-blocking.

Change the scroll_text.

////////////////////////////////////////////////
/* this function scrolles the test on top or botoom line on the LCD
    according to the line parameter
*/
bool scroll_text(char *text, byte line)
// scroll the LED lines
{
  long endScrool = millis() + 5000; //test
  char currenttext[LEDLINE + 1];
  static unsigned long nextscroll[2];
  static int positionCounter[2];
  int i;
  if (millis() > nextscroll[line])
  {
    nextscroll[line] = millis() + ledScrollSpeed[line];

    for (i = 0; i < LEDLINE; i++)
      currenttext[i] = charAt(text, positionCounter[line] + i);
    currenttext[LEDLINE] = 0;
    lcd.setCursor(0, line);
    lcd.print(currenttext);
    if (ledScrollDir[line])
    {
      positionCounter[line]++;
      if (positionCounter[line] == strlen(text) + LEDLINE) positionCounter[line] = 0;
    }
    else
    {
      positionCounter[line]--;
      if (positionCounter[line] < 0) positionCounter[line] = strlen(text) + LEDLINE - 1;
    }
  }

  // if scroll was done, return true, if scroll is still in progress return false
  if (positionCounter[line] == 0 || positionCounter[line] = strlen(text) + LEDLINE - 1)
  {
    return true;
  }
  else
  {
    return false;
  }

}
/////////// end of function /////////////////////////////////////////////////

The first line changed to indicate to the compiler that the function will return a bool. The added part at the end indicates to the calling function if one 'scroll' has completed or not.

Next in loop(), test for the return value before incrementing the counter. The code below now uses two counters, one for each line.

void loop() {

  // variable to count number of 'scrolls'; one for each line; by default initialised to 0
  static byte scrollCount[2];

  // Scroll text in line number 0
  if (scroll_text("This text is for top line, it is long ", 0) == true)
  {
    scrollCount[0]++;
  }

  // Scroll text in line number 1
  if (scroll_text("This on bottom", 1) == true)
  {
    scrollCount[1]++;
  }

  // if either scrollCount has not reached the number of scrolls
  if (scrollCount[0] != 5 || scrollCount[1] != 5)
  {
    // nothing else to do
    return;
  }

}

Hi

Well, i tried to copy the function as suggested. made a few attempts to see if it can print the message to LCD even for one time, not to mention several by using the counters.

But all i got was a flashing one character at position 1,0 of the LCD
it is probably my mistake not to mention that the function does not scroll even once.

The truth is that i feel a bit frastrated that i could not resolve the reason myself !!

The first error i got was at the following line of code of the function :

if (positionCounter[line] == 0 || (positionCounter[line] = strlen(text) + LEDLINE - 1))

which disappered when i added the pranteses.

The total scetch is presented herein, no clue how to get forward.

My objective is to read text stored in SD card that might be more than 100 char and than print it on the LCD, slow that people can read and allow to do that several times and move on with the program

will appreciate clues how break the code into chunks I can understand and move further.

P.S. I succeded in writing to the LCD other chunjs of text as suggested in many simple examples

Moshiko

/* this program shows how to write long text messages on LCD by scrolling*/

// define the chars in one LED line
#define LEDLINE 16  


#include <LiquidCrystal_I2C.h>
#include <Wire.h>  // Comes with Arduino IDE, needed  for I2C communication

/*
 * I2C interface card for LCD, 16 chars 2 line display 
 * I2C interface card connection: GND, Vcc 5v, SDA to pin A4, SCL to pin A5
 * LCD_I2c adrees 0x3F
*/
//                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address


// define scrolling speed for two LED lines
const int ledScrollSpeed[2]={445,450};
// define scrolling direction for two LED lines (true means right-to-left scrolling)
const boolean ledScrollDir[2]={true,true};


/////////// function to check position of the character //////////////
char charAt(char *text, int pos)
// scrolling-logic coded here
{
  if (pos<LEDLINE) return ' '; // scroll in
  else if (pos>=LEDLINE && pos<LEDLINE+strlen(text))
    return text[pos-LEDLINE]; // scroll text
  else return ' ';  // scroll out
}

/////////////////////////////////////////////////////////////////




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

void loop() {

  // variable to count number of 'scrolls'; one for each line; by default initialised to 0
  static byte scrollCount[2];

  // Scroll text in line number 0
  if (scroll_text("This text is for top line, it is long ", 0) == true)
  {
    scrollCount[0]++;
  }

  // Scroll text in line number 1
  if (scroll_text("This on bottom", 1) == true)
  {
    scrollCount[1]++;
  }

  // if either scrollCount has not reached the number of scrolls
  if (scrollCount[0] != 5 || scrollCount[1] != 5)
  {
    // nothing else to do
    return;
  }

}

////////////////////////////////////////////////
/* this function scrolles the test on top or botoom line on the LCD
    according to the line parameter
*/
bool scroll_text(char *text, byte line)
// scroll the LED lines
{
  char currenttext[LEDLINE + 1];
  static unsigned long nextscroll[2];
  static int positionCounter[2];
  int i;
  if (millis() > nextscroll[line])
  {
    nextscroll[line] = millis() + ledScrollSpeed[line];

    for (i = 0; i < LEDLINE; i++)
      currenttext[i] = charAt(text, positionCounter[line] + i);
    currenttext[LEDLINE] = 0;
    lcd.setCursor(0, line);
    lcd.print(currenttext);
    if (ledScrollDir[line])
    {
      positionCounter[line]++;
      if (positionCounter[line] == strlen(text) + LEDLINE) positionCounter[line] = 0;
    }
    else
    {
      positionCounter[line]--;
      if (positionCounter[line] < 0) positionCounter[line] = strlen(text) + LEDLINE - 1;
    }
  }

  // if scroll was done, return true, if scroll is still in progress return false
  if (positionCounter[line] == 0 || (positionCounter[line] = strlen(text) + LEDLINE - 1))
  {
    return true;
  }
  else
  {
    return false;
  }

}
/////////// end of function /////////////////////////////////////////////////

Sloppy copy and paste from my side, should be a == instead of =

Will try to make a setup and test.

Reworked the scroll_text a little bit

////////////////////////////////////////////////
/* this function scrolles the test on top or botoom line on the LCD
    according to the line parameter
*/
bool scroll_text(char *text, byte line)
// scroll the LED lines
{
  long endScrool = millis() + 5000; //test
  char currenttext[LEDLINE + 1];
  static unsigned long nextscroll[2];
  static int positionCounter[2];
  int i;
  if (millis() > nextscroll[line])
  {
    nextscroll[line] = millis() + ledScrollSpeed[line];

    for (i = 0; i < LEDLINE; i++)
    {
      currenttext[i] = charAt(text, positionCounter[line] + i);
    }
    currenttext[LEDLINE] = 0;
    lcd.setCursor(0, line);
    lcd.print(currenttext);
    if (ledScrollDir[line])
    {
      positionCounter[line]++;
      if (positionCounter[line] == strlen(text) + LEDLINE) positionCounter[line] = 0;
    }
    else
    {
      positionCounter[line]--;
      if (positionCounter[line] < 0) positionCounter[line] = strlen(text) + LEDLINE - 1;
    }



    // if scroll was done, return true
    if ((ledScrollDir[line] && (positionCounter[line] == 0)) ||
        (!ledScrollDir[line] && (positionCounter[line] == strlen(text) + LEDLINE - 1)))
    {
      Serial.print(line); Serial.print(": "); Serial.println("true");
      return true;
    }

  }
  // if scroll is still in progress return false
  return false;
}
/////////// end of function /////////////////////////////////////////////////

And I adjusted loop() a little

void loop()
{
  static byte scrollCounter[2];

  if (scrollCounter[0] < 5)
  {
    // Scroll text in line number 0
    if (scroll_text("This text is for top line, it is long ", 0) == true)
    {
      scrollCounter[0]++;
      Serial.print("0: "); Serial.println(scrollCounter[0]);
    }
  }

  if (scrollCounter[1] < 5)
  {
    // Scroll text in line number 1
    if (scroll_text("This on bottom", 1) == true)
    {
      scrollCounter[1]++;
      Serial.print("1: "); Serial.println(scrollCounter[1]);
    }
  }


  if (scrollCounter[0] < 5 || scrollCounter[1] < 5)
  {
    return;
  }

  //lcd.clear();

}

There is a bug somewhere; the last iteration of the second line leaves the 'm' on the screen; did not have time to look at that.