NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » Scrolling Text on LCD

January 07, 2010
by omer921
omer921's Avatar

How do I make scrolling text on my LCD using C

January 08, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi omer921,

If you're asking about how we do the text that automatically scrolls around as we have pre-loaded on all the chips, here's the basic code we use to do that. I highly recommend you take some time to play with it and understand each part. I've added a bunch of comments as clues. Here goes:

// Variable to hold our current scroll offset.
int8_t scrollPos=0;

// Variable to iterate through the 20-wide LCD screen.
uint8_t i;

// This is our actual string, longer than the LCD width,
// stored in program memory (flash).
const char *linetwo = PSTR(" Your NerdKits hardware is OK!       ");

// This calculates its width once.
// (For the string above, linetwolen = 37)
uint8_t linetwolen = strlen_P(linetwo);

// Main loop.
while(1) {
  // Move to the 2nd line of the LCD.
  lcd_line_two();

  for(i=0; i<20; i++) {
    // For each of the 20 columns of the LCD display,
    // we want to write a particular character from the 
    // string to be scrolled.
    // Specifically, for column i (0..19), we want to write 
    // the (scrollPos+i) character of the string as we shift it around.
    // But we take (scrollPos+i) MOD linetwolen to allow us to 
    // "wrap around".
    // Calculate the right character number ((scrollPos+i)%linetwolen)
    // and add this to the linetwo variable, essentially moving forward
    // in memory by that many bytes.
    // Then read it from program memory (pgm_read_byte).
    // Finally, write it out to the LCD (lcd_write_data).
    lcd_write_data(pgm_read_byte(linetwo + ((scrollPos+i)%linetwolen)));
  }

  // Shift to the left by one position.  When we get to having 
  // shifted by the entire length fo the string, then reset back to zero.
  scrollPos = (scrollPos + 1) % linetwolen;

  // Delay about 1/5th of a second before re-displaying.
  delay_ms(200);
}

Also, note that the % operator means "do integer division and only return the remainder", so for example 40%37=3 (because 40 divided by 37 is 1+3/37, so the remainder is 3). We use it in the code above in two important places. Hope the comments help make it clear!

Mike

January 08, 2010
by omer921
omer921's Avatar

When I try to compile it it says:

initialload.c:2: error: expected '=', ',', ';', 'asm' or 'attribute' before 'scrollPos' initialload.c:5: error: expected '=', ',', ';', 'asm' or 'attribute' before 'i' initialload.c:9: warning: implicit declaration of function 'PSTR' initialload.c:9: warning: initialization makes pointer from integer without a cast initialload.c:9: error: initializer element is not constant initialload.c:13: error: expected '=', ',', ';', 'asm' or 'attribute' before 'linetwolen' initialload.c:16: error: expected identifier or '(' before 'while' make: *** [initialload.hex] Error 1

January 12, 2010
by avr
avr's Avatar

mrobbins, thanks for posting that information.

I was wondering recently how you achieved this - now all I have to do is understand it :)

January 12, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi avr,

Thanks -- glad to help :-)

omer921,

You need to put this code into the basic framework we've provided of includes / main function / etc.

Mike

January 12, 2010
by omer921
omer921's Avatar

Thank you so much i just had to fix the while(1){ and put it in the right place.

January 12, 2010
by Farmerjoecoledge
Farmerjoecoledge's Avatar

Why Me?

This is what I put up with.Look at the first error And the second error it made itself '' ,say what?

I totally forgot what Nothing to be done for 'all' means. All I did was copy the above code and added the #includes.

I think I need a different toolchain.

January 13, 2010
by Farmerjoecoledge
Farmerjoecoledge's Avatar

What? what do you mean it only scrolls one line! :) diy strikes again!

February 24, 2011
by bl00513
bl00513's Avatar

HI, I wouold really like to see source code for a simple scrolling lcd display. I have tried adapting this code above into the initialload.c, but my C skills have not quite developed enough to allow me to do this. Every time I try to compile I get "initialload.c:56: error: expected declaration or statement at end of input make: *** [initialload.hex] Error 1 " I am unsure if I am coding incorrectly, or if I am required to modify the make file as I add code to the original source. C is pretty new to me, so I would love whatever help you can offer.

February 25, 2011
by SpaceGhost
SpaceGhost's Avatar

bl00513, could you copy then paste your complete code here? This will give us a better indication of what is wrong with the code, and how you should change it.

Please be sure to highlight (select) the portion of your post that contains your code, then click the "Indent Selection as Code Block" button (seen below the "Preview" and "Post" buttons). This will post your code with the lines numbered and in a much easier to read format. You will know if you've done it right when you click "Preview" before posting your message with your code.

Dave

February 25, 2011
by Ralphxyz
Ralphxyz's Avatar

re: "Scrolling text" have you searched the forum, this has been a common thread.

Rick also posted his excellant code example that along with Mike's explanation certainly answers a lot of questions.

Ralph

February 25, 2011
by bl00513
bl00513's Avatar

This is what I have for my main. I know it is probably very incomplete, but I really do not know where to go from here. Thank you in advance for your help! // initialload.c // for NerdKits with ATmega168 // mrobbins@mit.edu

#define F_CPU 14745600

#include <stdio.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

// PIN DEFINITIONS:
//
// PC4 -- LED anode

int main() {
  // Variable to hold our current scroll offset. 
int8_t scrollPos=0;

// Variable to iterate through the 20-wide LCD screen. 
uint8_t i;

// This is our actual string, longer than the LCD width, 
// stored in program memory (flash). 
const char *linetwo = PSTR(" Your NerdKits hardware is OK!       ");

// This calculates its width once. 
// (For the string above, linetwolen = 37) 
uint8_t linetwolen = strlen_P(linetwo);

// Main loop. 
while(1) { 
  // Move to the 2nd line of the LCD. 
  lcd_line_two();

  for(i=0; i<20; i++) { 
    // For each of the 20 columns of the LCD display, 
    // we want to write a particular character from the  
    // string to be scrolled. 
    // Specifically, for column i (0..19), we want to write  
    // the (scrollPos+i) character of the string as we shift it around. 
    // But we take (scrollPos+i) MOD linetwolen to allow us to  
    // "wrap around". 
    // Calculate the right character number ((scrollPos+i)%linetwolen) 
    // and add this to the linetwo variable, essentially moving forward 
    // in memory by that many bytes. 
    // Then read it from program memory (pgm_read_byte). 
    // Finally, write it out to the LCD (lcd_write_data). 
    lcd_write_data(pgm_read_byte(linetwo + ((scrollPos+i)%linetwolen))); 
  }
February 25, 2011
by SpaceGhost
SpaceGhost's Avatar

You are very close!

But after line #17, don't forget to

   // fire up the LCD
    lcd_init();
    FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
    lcd_line_two();

and after line #51, you still need to

  // Shift to the left by one position.  When we get to having
  // shifted by the entire length fo the string, then reset back to zero.
  scrollPos = (scrollPos + 1) % linetwolen;

then, this next line

  delay_ms(200);

controls the speed of the scrolling text. And, don't forget to close that with a

}

and finish your program with

  return 0;
}

Let us know if this works for you or you are still having trouble. I'm still pretty green with this stuff too, hope I was able to help!

Dave

February 26, 2011
by bl00513
bl00513's Avatar

Awesome, thanks to everyone's help I was able to compile with no errors! Now I am trying to expand upon this to produce more than one scrolling line. Here is what I've got:

// initialload.c
// for NerdKits with ATmega168
// mrobbins@mit.edu

#define F_CPU 14745600

#include <stdio.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

// PIN DEFINITIONS:
//
// PC4 -- LED anode

int main() {
  // LED as output
  DDRC |= (1<<PC4);

  // turn on LED
  PORTC |= (1<<PC4);

  // fire up the LCD
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

  //holds our current scoll offest
  int8_t scrollPos2=0;
  int8_t scrollPos1=0;
  //Variable to iterate through the 20-wide LCD screen
  uint8_t i;

  //Where the actual string is defined per line
  const char *lineone = PSTR(" test test test test one two three ");
  const char *linetwo = PSTR(" Your nerdkits software is OK!     ");

  //this calculates its width
  uint8_t lineonelen = strlen_P(lineone);
  uint8_t linetwolen = strlen_P(linetwo);

  //Main loop for scrolling
  while(1) {
  //move to 2nd line of lcd
  lcd_line_one();
  lcd_line_two();

  for(i=0; i<20; i++) {
  lcd_write_data(pgm_read_byte(lineone + ((scrollPos1+i)%lineonelen)));
  lcd_write_data(pgm_read_byte(linetwo + ((scrollPos2+i)%linetwolen)));

  }

 //shift characters left one position each loop and ultimately back to 0
 scrollPos2 = (scrollPos2 + 1) % linetwolen;
 scrollPos1 = (scrollPos1 + 1) % lineonelen;

 //adds a delay
 delay_ms(200);
 }
 return 0;
 }

Although it will build/make without any trouble, the lcd only displays jumbled text. I think that it may have something to with lines 50 & 51, but I don't know enough to be sure or how to correct it. I tried excluding these statement and it simply caused the text to jumble on all 4 rows of the lcd instead of just two. I would appreciate any insight you guys have. Thanks again for the help; I am really learning!

February 26, 2011
by bl00513
bl00513's Avatar

UPDATE: I got the jumbled text problem fixed; however, my display is one lines two and four. I will post my code below... What am I doing wrong here?

// initialload.c
// for NerdKits with ATmega168
// mrobbins@mit.edu

#define F_CPU 14745600

#include <stdio.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

// PIN DEFINITIONS:
//
// PC4 -- LED anode

int main() {
  // LED as output
  DDRC |= (1<<PC4);

  // turn on LED
  PORTC |= (1<<PC4);

  // fire up the LCD
  lcd_init();
  FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
  lcd_home();

  //holds our current scoll offest
  int8_t scrollPos2=0;
  int8_t scrollPos1=0;
  //Variable to iterate through the 20-wide LCD screen
  uint8_t i;
  uint8_t i2;

  //Where the actual string is defined per line
  const char *lineone = PSTR(" The Current Temperature Is ");
  const char *linetwo = PSTR(" Your nerdkits software is OK!     ");

  //this calculates its width
  uint8_t lineonelen = strlen_P(lineone);
  uint8_t linetwolen = strlen_P(linetwo);

  //Main loop for scrolling
  while(1) {
  //move to 1st and 2nd line of lcd
  lcd_line_one();
  lcd_line_two();

  for(i=0; i<20; i++) {
  lcd_write_data(pgm_read_byte(lineone + ((scrollPos1+i)%lineonelen)));

  }

  for(i2=0; i2<20; i2++) {
  lcd_write_data(pgm_read_byte(linetwo + ((scrollPos2+i2)%linetwolen)));
  }

 //shift characters left one position each loop and ultimately back to 0
 scrollPos2 = (scrollPos2 + 1) % linetwolen;
 scrollPos1 = (scrollPos1 + 1) % lineonelen;

 //adds a delay
 delay_ms(350);
 }
 return 0;
 }
February 27, 2011
by SpaceGhost
SpaceGhost's Avatar

Look this over to see how I got two separate lines of text to scroll on lines one & two of the LCD -

#define F_CPU 14745600

#include <stdio.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"
int main() {
    // fire up the LCD
    lcd_init();
    FILE lcd_stream = FDEV_SETUP_STREAM(lcd_putchar, 0, _FDEV_SETUP_WRITE);
    lcd_line_two();

// Variable to hold our current scroll offset.
int8_t scrollPos=0;

// Variable to iterate through the 20-wide LCD screen.
uint8_t i;

// This is our actual string, longer than the LCD width,
// stored in program memory (flash).
const char *lineone = PSTR(" First message scrolls on line one   ");
const char *linetwo = PSTR(" Second message scrolls on line two  ");

// This calculates width once.
// (For the strings above, linetwolen = 37)
uint8_t lineonelen = strlen_P(lineone);
uint8_t linetwolen = strlen_P(linetwo);

// Main loop.
while(1) {

  lcd_line_one();

  for(i=0; i<20; i++) {

    lcd_write_data(pgm_read_byte(lineone + ((scrollPos+i)%lineonelen)));
  }

  scrollPos = (scrollPos + 1) % lineonelen;

  delay_ms(300);

  lcd_line_two();

  for(i=0; i<20; i++) {

    lcd_write_data(pgm_read_byte(linetwo + ((scrollPos+i)%linetwolen)));
  }

  scrollPos = (scrollPos + 1) % linetwolen;

  delay_ms(300);

 }

  return 0;
}

I believe that you tried to use more variables than you needed - for instance, this integer

int8_t scrollPos=0;

that Mike used in his code snippet is used for both lines of scrolling text in the example I just posted. Also, I noticed that you used

  uint8_t i;
  uint8_t i2;

for unsigned integers, when one would suffice for the arithmetic and comparisons of the statements

  for(i=0; i<20; i++)

that I used twice in the code I posted, for each line that I wanted to have scrolling.

Basically I believe that since we want both lines on the LCD to do pretty much the same thing, it is okay (at least in this program) to use the same formula with the same variable...

If I'm not explaining it right or I'm off base on something, PLEASE someone jump in to correct me! I've been wrong here (okay, and a lot of other places too :) ) before... I don't mind being corrected - best way for me to learn too. I'm just theoreticizing most of what I've said - and I still have my n00by-ness to fall back on to explain my mistakes, lol.

bl00513, another thing that might perhaps help is to note how I tried to keep relative things together... For the most part I just copied and pasted sections of code that made the first line scroll, then edited that to become the code that made the second line scroll. lcd_line_one(); stuff is with lcd_line_one();, same as lcd_line_two(); stuff. I noticed right off that you had these two grouped together... Not sure how (of if) that would work, didn't try it. Plus, in my opinion it should be easier to follow along and try to interpret, troubleshoot, etc. when you can keep as many things as possible together. Sometimes the simplest way of doing things is the best way, I like to believe.

Again, if I've said anything here that is goofy or not explained quite right someone please step in and correct me!

Dave

February 27, 2011
by bl00513
bl00513's Avatar

Hey Dave, this makes sense! I thought I may be off on declaring a second set of vairables, but I was unsure. I'll play around with this code, and thanks a lot for all of your help!

-Ben

March 20, 2011
by hariharan
hariharan's Avatar

hey, Can I know what does const mean? And also why u need a variable called i?

March 20, 2011
by Ralphxyz
Ralphxyz's Avatar

Try reading a book on C programming. Or take some of the Programming courses on the web.

Try to understand what the "const" does, where is it used. If const defines a variable, what does that mean about that variable?

I'll give you a hint, often terms in programming languages use abbreviations of terms like in "Constant" as in not changing.

You use a variable called "i" usually to "increment". If you are looking at a for statement what do you think that i++ does?

Or what happens to the i each time you run through the loop? Literally you could call that variable anything you wish even "increment".

Ralph

March 20, 2011
by hariharan
hariharan's Avatar

thanks very much. i think i++ increases the value by one. where do you think i can get a good C tutorial without much cost?

March 20, 2011
by hariharan
hariharan's Avatar

i did not understand how these two lines work.

lcd_write_data(pgm_read_byte(linetwo + ((scrollPos+i)%linetwolen)));  
}    
 scrollPos = (scrollPos + 1) % linetwolen;
March 20, 2011
by Noter
Noter's Avatar

Here is a good tutorial on the C language:

http://www.crasseux.com/books/ctutorial/index.html#Top

and here's another:

http://www.cprogramming.com/begin.html

The % is the modulus operator and it returns the remainder of a divide operation. So if you did 20/3 the integer answer is 6. If you instead did 20%3 the answer is the remainder which is 2.

March 20, 2011
by Ralphxyz
Ralphxyz's Avatar

Your welcome, it's probable better to think of i++ "incrementing" (by one). If you think increases, well increases by how much?

You can start learning C at http://www.cprogramming.com/ but there are hundreds of locations.

re: "how these two lines work"

Break them down, in fact you could/should write them down in a outline.

lcd_write_data() Now I wonder what this will do. Oh hey I bet some data is going to get written down somewhere probable to the LCD.

Now variable names are not always literal but one can "usually" make a good guess.

So it looks like line two is involved and then they are are doing some Modulus (%) math on scrollPos+1 and the length of line two. I can see where doing position on a line might require knowing the line length.

So do you understand Modulus math? Here ya go I googled Modulus but of course I knew what the % meant.

scrollPos ends up being the whole number of scrollPos + 1 divided by linetwolen.

There that's how they work maybe someone who actually knows what they are doing will jump in and make corrections.

Often times you will not need to know how things work, as long as they work, you can just use them.

You have to start to learn how things work when they don't.

Ralph

Post a Reply

Please log in to post a reply.

Did you know that interrupts can be used to trigger pieces of code when events happen? Learn more...