Running Text on a 16x2 LCD

I am a bit confused, for there is no software thread in this new forum. So I try it here ...

I am looking for a software snipet which displays running text in the following matter:

  1. 1 Line: Write char by char until 16 chars. Go to the 2. line

  2. 2.Line: Write char by char until 16 chars. Wait a seccond.

    1. Line: clear line 1 and copy line 2 into line 1
    1. Line: clear line 2 .Write char by char until 16 chars. Wait a seccond.

Repeat 3. and 4. until message end.

I was looking and didnt find something comparable.

Help or code would appriciated.

Thanks

You have those examples on: File > Examples > LiquidCrystal

Also check LiquidCrystal440.h.
There you have a lot of examples for that kind of animations.

Staedtler:
Also check LiquidCrystal440.h.
There you have a lot of examples for that kind of animations.

Thanks for your help. I am half way through programming it by myself, but now I will first have a look at the library.

Al the best

No code was found so I wrote it by myself. It is not good "C"-code but it works. Here is the snippet:

char line2[16] = " ";
int ii = 0;

void LcdClearLine(int r)
{
  lcd.setCursor(0,r);
  for (ii = 0; ii < 16; ii = ii + 1) {
    lcd.print(" ");
  }
}

void sendmsg(char *str)
{
  while (*str) {
    if (col < 16) { 
      col = col++;
      line2[col] = toupper(*str);
      send(toupper(*str++)) ;
    }
    else{
      col = 0;
      if (row == 0) {
        row = 1; 
      }
      else
      { 
        LcdClearLine(0);
        lcd.setCursor(col,0);    
        for (ii = 1; ii < 17; ii = ii + 1) {
          lcd.print(line2[ii]);   
          line2[ii] = ' ';   
        }
        LcdClearLine(1);
      } 
      lcd.setCursor(col,row);
    }
  }
}

Of course comments are welcome.

Not bad! I would do the same if I needed scrolling text. I don't so I wrote some code that takes input by pressing up an down buttons to cycle through all possible inputs. Enter to confirm :slight_smile: I also made a text input area where you use left and right to move cursor around and you can type in messages like hello all. But it takes some time since the input is character by character and I spent a lot of time pressing the up and down buttons to get different letters. It's included in my Morse code in/output program on my blog.

@qliudr
You can be sure that I had a closer look to your source code. Very fine but it took some time to understand it 8), but I didn't manage until now to get it running on my configuration (different shield etc. ) But I will try even more.

What I took as an inspiration from your project is the use of the buttons. My shield can only show 16x2 characters and that is not enough for a tweet. So the next step will be a double array 16x10 so that I can keep the whole message and after morse output I can scroll with the keys through the message.
You can see the scrolling lines on my http://hajos-kontrapunkte.blogspot.com/2011/02/morsetweeter-v-08.html.

LeseLaster:
No code was found...

I don't understand, there is a lot examples inside the LiquidCrystal440.h example.

Here is some...

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); // replace with your PIN configuration

int nRows = 2; // n of LCD's rows
int nColumns = 16; // n of LCD's columns

void setup() {

        lcd.clear();
        lcd.begin(nColumns, nRows); // 16 ROWS / 2 LINES
        
}



void loop() {


	//======setCursor===
	// loop from ASCII 'a' to ASCII 'z':
	lcd.home();        
	int thisLetter = 'a';
    // loop over the rows:
    for (int thisRow = 0; thisRow < nRows; thisRow++) {
		// loop over the columns:
		for (int thisCol = 0; thisCol < nColumns; thisCol++) {
			// set the cursor position:
			lcd.setCursor(thisCol,thisRow);
			// print the letter:
			lcd.print(thisLetter, BYTE);
			thisLetter++;
			if (thisLetter > 'z') thisLetter = 'a';
			delay(100);
		}
    }
  
  
  
  
  
	
	//========Autoscroll:  -- my arch nemesis !
	lcd.clear();
	// set the cursor to (0,0):
	lcd.setCursor(0, 0);
	// print from 0 to 9:
	lcd.print("Autoscroll");
	for (char thisChar = '1'; thisChar < '9'; thisChar++) {
		lcd.print(thisChar);
		delay(100);
	}
	
	// set the cursor to (nColumns,1):
	lcd.setCursor(0,1);
        lcd.print("Autoscroll");
	// set the display to automatically scroll:
	lcd.autoscroll();
	
	
	// print from 0 to 9:
	for (int thisChar = 0; thisChar < 10; thisChar++) {
		lcd.print(thisChar);
		delay(100);
	}
	// turn off automatic scrolling
	lcd.noAutoscroll();
if (nRows>2) {
	//========Autoscroll:  -- my arch nemesis !

	// set the cursor to (0,0):
	lcd.setCursor(0, nRows-2);
	// print from 0 to 9:
	lcd.print("Autoscroll");
	for (char thisChar = '1'; thisChar < '9'; thisChar++) {
		lcd.print(thisChar);
		delay(100);
	}
	
	// set the cursor to (nColumns,1):
	lcd.setCursor(0,nRows-1);
        lcd.print("Autoscroll");
	// set the display to automatically scroll:
	lcd.autoscroll();
	
	
	// print from 0 to 9:
	for (int thisChar = 0; thisChar < 10; thisChar++) {
		lcd.print(thisChar);
		delay(200);
	}
	// turn off automatic scrolling
	lcd.noAutoscroll();
}	


  
}

You are right of course. But I wanted to push up the second line on the first and continue to write on the second line. So I had to erase the first, copy the second to the first, erase the 2. and continue to write on the second.

Why make complicated things easy ? :smiley:

Anyway I found some other useful code.

Thanks anyway.

LeseLaster:
@qliudr
You can be sure that I had a closer look to your source code. Very fine but it took some time to understand it 8), but I didn't manage until now to get it running on my configuration (different shield etc. ) But I will try even more.

You could, you know, buy my shield and save the trouble :grin:
It's got clock, eeprom, and GPS besides an onboard buzzer so saves your breadboard.

Nice video. I'm not expert in Morse code, expecially not when I had to translate from Morse into Germain then into English :fearful:

Yes, my code is not the easiest to understand but I built those functions for very different projects and in layers so I can update one particular layer without disturbing the rest. The Morse in and out should be relatively straight-forward. Let me know how your project goes. I'm very happy if my code runs on the other side of the globe 8)

LeseLaster:
I wanted to push up the second line on the first and continue to write on the second line. So I had to erase the first, copy the second to the first, erase the 2. and continue to write on the second....Anyway I found some other useful code

Instead of "finding" some code why not just implement your scheme as you articulated it. I mean, my observation is that the hardware "autoscroll" function hardly ever does what people think it should do, but doing things like you need in software is straightforward.

Maybe something like the following

//
// Simple line-by-line scrolling for LCD with two rows
//
// davekw7x
//
#include <LiquidCrystal.h>

const int NROWS = 2;
const int NCOLS = 16;

LiquidCrystal lcd(7, 6, 5, 4, 3, 2); // Customize for your connections.

void setup()
{
    lcd.begin(NCOLS, NROWS); // This clears the LCD
    lcd.setCursor(0, 1);     // Start on the second row
}

int counter = 1;
void loop()
{
    char buffer[17];

    sprintf(buffer, "  Loop %d: ", counter);
    sendmsg(buffer);
    ++counter;
    for (char alpha = 'a'; alpha <= 'z'; ++alpha) {
        buffer[0] = alpha;
        buffer[1] = '\0';
        sendmsg(buffer);
        delay(300);
    }
    delay(2000);
}


void LcdClearLine(int r)
{
    lcd.setCursor(0,r);
    for (int i = 0; i < NCOLS; i++) {
        lcd.print(" ");
    }
}

char line[NCOLS];
char col;   // The compiler makes sure this is initialized to zero.

void sendmsg(char *str)
{
    while (*str) {
        if (col >= 16) {
            //Serial.println("Scrolling"); // Uncomment for debugging
            // Print the line contents to the first row
            lcd.setCursor(0, 0);
            for (int i = 0; i < NCOLS; i++) {
                lcd.print(line[i]);
            }
            LcdClearLine(1);     // Spaces to second row
            lcd.setCursor(0, 1); // set cursor to beginning of second row
            col = 0;
        }
        line[col] = toupper(*str);
        lcd.print(line[col++]);
        ++str;
    }
}

Regards,

Dave

Footnote:
"quasi-code" for the functionality could be added as comments:

Suppose we have an LCD that has two rows.  Each row has NCOLS
columns.

Here is a way to scroll the way that you indicated

/*
    There is a static array that holds characters of
    the current line:
*/

char line[NCOLS];

/*
    There is a static integer used to keep track of the 
    column position for the next character.  This is
    also used as an index to store the character in
    the array.
*/

int col; // Initialized to zero

/*
    sendmsg gets a pointer to char (the "string pointer")
    For each character in the "string," here's what the function
    does:
    1.
        If the array is full (col equal to NCOLS), it copies the
        contents of the array to the first line of the the LCD and
        clears the second line of the LCD. It sets col to zero

    2.
        It stores the character in the array and prints the char
        to the LCD.

    3.
        It increments the column counter and it increments the "string pointer"

*/

Sometimes I just can't help myself.

.. but you certainly helped another one... :slight_smile:

Thanks for the pseudo-code and the real one. I learned:

  • internal variables,
  • predeclared functions
  • ...

Still have problems with pointer and why you have filled the buffer[17] with buffer[1] = '\0';
I thought that was not needed for the LCD.

No excuse, but I stopped about 15 years ago programming in Smalltalk and Prolog and started now again with C. So going is slow and I learn quicker by example when I am unsure about the syntax.

Again thanks for your help.

LeseLaster:

Sometimes I just can't help myself.

.. but you certainly helped another one... :slight_smile:

Thanks for the pseudo-code and the real one. I learned:

  • internal variables,
  • predeclared functions
  • ...

Still have problems with pointer and why you have filled the buffer[17] with buffer[1] = '\0';
I thought that was not needed for the LCD.

No excuse, but I stopped about 15 years ago programming in Smalltalk and Prolog and started now again with C. So going is slow and I learn quicker by example when I am unsure about the syntax.

Again thanks for your help.

It is because a C string needs to be zero-terminated. Does that ring a bell? If a string is not terminated, the print doesn't know when to stop printing and will continue to print beyond the string and read sections of memory that's totally not string so you will get junk and sometimes freeze up. If you define a string like char a[]="hello"; the compiler helps you attach a zero in the end.

This is the one for whom the bell tolls - it did. :blush:

Thanks liudr - now I try to integrate the modified code into the program and go on until I get the blue screen ]:slight_smile:

Good approach! In the 90s when I was experimenting on 386 assembly i got blue screen (prior to windows there were no blue screen but I intend to use this expression for cpu freeze) very often :slight_smile:

I'm just glad my code is useful to others.

LeseLaster:
...buffer[1] = '\0';

The loop in sendmsg (from your code) uses the zero byte to know when it has reached the end of the "string." That's the way that "normal" C library functions handle these things, and it is a convention followed by C programmers everywhere (well, almost everywhere).

Here's the loop:

    while (*str) {
.
.
.
    ++str;
}

That means that the pointer is incremented each time through the loop. When the pointer reaches the address of the zero byte, the "while" condition fails, and that's the end of the road. The calling function puts a single character at the beginning of the buffer, followed by a zero byte, every time my program called the function. That's just an example. You could put any kind of C-style "string" in the buffer (always terminated by a zero byte).

Regards,

Dave

@davekw7x

Thanks for your explanation. I understood.

My misunderstanding came from the way I wanted to implement the storage of chars. In the first go I wanted /want to use a two dimensional array (matrix) (something like char lines [16] [10]) so that I am able to retrieve a longer text on the display via the buttons on the LCD shield. The control of the matrix should be done by loops. I was not aware that a transition from "normal" array to string was triggered.

Now I see that it is easier to go with strings incl. termination. Oh dear, perhaps I should have stayed with things I know how to handle.

Again thanks for your time and engagement.