Go Down

Topic: Cursor position after lcd.print() and lcd.scrollDisplayLeft() (Read 3053 times) previous topic - next topic

rwiens

If I do this:
Code: [Select]

lcd.setCursor(15,0);
    for (chrdCnt=1; chrdCnt<chrdLen; chrdCnt++) {
       lcd.print(chords[chrdCnt]);
       delay(1000);
       lcd.scrollDisplayLeft();
    }


I get what I want (scroll one character to the left and print the new character at position 15,0)

But if I do this:

Code: [Select]

    for (chrdCnt=1; chrdCnt<chrdLen; chrdCnt++) {
       lcd.setCursor(15,0);  
       lcd.print(chords[chrdCnt]);
       delay(1000);
       lcd.scrollDisplayLeft();
    }


I don't get anything displayed.  

If I do an lcd.print at col 15, does the cursor then advance to col 16 (which doesn't exist), only to be moved back to col 15 with the lcd.scrollDisplayLeft() ?  If that is the case, why would explicitly resetting the cursor to col 15 every time cause a problem (never mind that it does not seem to be necessary)?



floresta

#1
Feb 04, 2013, 10:47 pm Last Edit: Feb 04, 2013, 10:50 pm by floresta Reason: 1
I'm not sure what you are trying to accomplish but I think it may be similar to the fourth animated example on this page: --> http://www.geocities.com/dinceraydin/lcd/commands.htm.

I think you can implement this with what is called 'autoscroll()' in Arduinoese although I haven't tried it.

You haven't told us what size display you are using, but column 16 does indeed exist as far as the LCD controller is concerned.  If you have a 16x2 display then columns above 16 are hidden, but they do exist.  Any characters that you 'print' to those hidden locations will be revealed when you shift (the correct term for scroll) the display.


Don

rwiens

Thanks.  I am using a 16x2.  Ultimately I am reading 2 lines from a file on an SD card, one for chords and one for lyrics, and want to scroll them like a karaoke display.

I played with autoscroll and it seems to work to.  I just wanted to understand why explicitly setting the cursor to col 15 every time didn't seem to.

While we're at it, I am also experiencing a phenomenon where the 27th character I print to the lcd ends up on the second line.  Here is the code after initialization of the SD card (autoscroll is on):

Code: [Select]

chrCnt = 1;
    while (myFile.available()) {
      nextChar = myFile.read();
      while (nextChar != '\r') {
          chords[chrCnt] = nextChar;
          chrCnt++;
          nextChar = myFile.read();
      } 
      chrdLen = chrCnt;
      lcd.setCursor(15,0);
      for (chrdCnt=1; chrdCnt<chrdLen; chrdCnt++) {
          lcd.print(chords[chrdCnt]);
          delay(1000);
     }

floresta

#3
Feb 05, 2013, 04:58 am Last Edit: Feb 05, 2013, 05:07 am by floresta Reason: 1
Quote
and want to scroll them like a karaoke display.

Sorry, I am culturally deprived.  Would that be like the operation of the display in the link I mentioned above?

Quote
While we're at it, I am also experiencing a phenomenon where the 27th character I print to the lcd ends up on the second line.

If you really want to find out what is going on then follow the LCD Addressing link at http://web.alfredstate.edu/weimandn.  Make sure you read the information about the LCD Controller Memory, the information about the 40 x 2 LCD, and the information about the 20 x 2 LCD before you try to figure out the 16x2.

Don

rwiens

Yes what I am trying to accomplish is like example #4 except without the visible cursor, and each character gets printed at col 15 before it gets scrolled (in the example they are printing the character at col 7 or 8).

Quote

If you really want to find out what is going on then follow the LCD Addressing link at http://web.alfredstate.edu/weimandn.

That was very helpful in understanding the guts of things, although I had assumed (perhaps incorrectly) that the LiquidCrystal library would take care of the sausage making, so to speak.

I was particularly excited to see that the first line of memory ends on 27, since that is the point at which my display seems to print the next character on the 2nd line, until I realized that it was 0x27, not decimal 27.

In any case, it gives me some place to start and some things to think about.

rwiens

Don,

Using your explanation, I would expect that setting the cursor to (15,0) and then starting to write my string, I would write 25 characters (1 visible and 24 'invisible') and the 26th would appear at position (0,1).  However, my understanding is that using autoscroll or scrolldisplayleft moves the cursor position each time (i.e. after the print/write, the cursor goes to 16,0 but then gets decremented back to 15,0) so the 'wrap' should never happen.

In my case, it does wrap on the 27th character (haven't figured out where I lost 1 yet!), but starts at position (7,1).  It would seem that the scrolling is not, in fact, changing the cursor position.  I tried to do that explicitly (set the cursor to 15,0 each time I write) but that got me some other weirdness.

In searching for other solutions, I came across a number of posts that seem to indicate the 'scroll' functions often yield unexpected results.  Also, there was mention that setcursor is really pointing to a memory location, and that sometimes that doesn't correspond to the physical display location you think it does.

Have you seen any of these phenomena before?  Do you use the lcd library that ships with the Arduino IDE, or are there 'better' ones out there?

floresta

I haven't done much with display shifting but let me try to explain what is happening.

After clearing the screen (which happens during the LCD initialization) the counter that keeps track of memory addresses is set to 0x00.  Then, the first ASCII character code that you send to the display is stored at that address and subsequent character codes are sent to sequential addresses after that one.  The sequence normally increases but you can change that if you want. You can also change the address so things start other than at address 0x00.

Each of the memory addresses is associated with a specific screen location so, when you store the ASCII code for a character in a memory address the character itself appears at the location specified for that memory address.

When you set the cursor to (15,0) the library uses what it knows (or should know) about your display to convert this into a memory address.  For (15,0) on a 16x2 display the memory address is 0x0F.

If the display is shifted left once then the memory address associated with a particular screen location is one number higher than it was before.  You could also say that the screen location associated with a particular memory address is one location to the left of where it was before. 

This means that the character that you put in memory location 0x0F now moves left since that address is now associated with (14,0).  The address counter has automatically incremented to 0x10 and location (15,0) is now associated with that new address so the next character will appear right where you expect it.

As long as you don't try to reset the cursor things should work as expected (until you fill up the screen).  I don't know what will happen if you do try to reset the cursor because I have not explored the library to see if the author has accounted for the fact that the relationship between memory addresses and screen locations has changed.  I rather expect that she didn't since you report 'some other weirdness'.

I do not use the LCD library that ships with the Arduino IDE (or any other library either).  I like to know what is going on.  Libraries have their place, they permit microcomputer neophytes to do things that they couldn't otherwise do and they permit professional coders to crank out code rapidly and efficiently.  I am neither a neophyte nor a professional coder and I prefer to work without using libraries.


Don

bperrybap

rwiens,
This peaked my interest as I initially also expected the same behavior you expected.
So when in doubt, just go look at the code.
Then all becomes obvious.

The scrollDisplayLeft() sends the hd44780 command:
LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT
or
0x10 | 0x8 | 0x0
or 0x18
which is hd44780 command
Cursor/Display shift with S/C = 1, R/L = 0
which is moves the existing display to the left by
changing the base address of where the display fetches characters.
scrollDisplayLeft() does not alter the cursor position.

The next part is where the things are not so obvious.
setCursor() sends the hd44780 command:
(LCD_SETDDRAMADDR | (col + row_offsets[row])
or
0x80 |  (col + row_offsets[row])
This will set the cursor position to an absolute address.
It is not dependent on the display position.

So what you are seeing is that column 15 appears to move, when in fact
what is really happening is that column 15 is staying the same and the display
window is changing.

In order to do what you want, all you need to do set the initial cursor position
and then not set the cursor position between updates.
Something like:
Code: [Select]
lcd.setCursor(15,0);   
for (chrdCnt=1; chrdCnt<chrdLen; chrdCnt++) {

        lcd.print(chords[chrdCnt]);
        delay(1000);
        lcd.scrollDisplayLeft();
     }


This will allow the cursor position (ram address) to continue to bump
as the character is written and then you can scroll it to the left between
each update.

I tried it and it does work.

--- bill


floresta

#8
Feb 12, 2013, 02:06 am Last Edit: Feb 12, 2013, 02:08 am by floresta Reason: 1
Quote
In order to do what you want, all you need to do set the initial cursor position and then not set the cursor position between updates.

I guess that is essentially the same as "As long as you don't try to reset the cursor things should work as expected (until you fill up the screen).

Quiz:  What do you expect to happen when you do fill up one line of the screen?


Quote
... and then you can scroll it to the left between each update.

I would expect that the use of lcd.autoscroll() would remove the need to do this, but then again things do not always work out the way you expect.

Don

rwiens

#9
Feb 12, 2013, 04:05 am Last Edit: Feb 12, 2013, 04:14 am by rwiens Reason: 1
Thanks guys.

Bill, I did in fact look at the library and saw the same stuff you did but wasn't entirely sure how to interpret it.  Your explanation is helpful, although I would need to spend some more time with the 44780 documentation to really understand it (I am not a c++ guy, either).

Don do you have any example sketches for LCD control that don't use the LiquidCrystal library?  I would like to see what the 'raw' commands look like.  I also have the tendancy to want to understand things at the lowest level, but have to trade that off with how much time it takes to get that understanding.  I am not a neophyte coder, per se, but am pretty new to Arduino and anything c++ish

I'm still not clear on why my 27th character ends up in the middle of the 2nd line, but it sounds like that is irrelevant since one way or the other I will need to figure out when I have written 40 characters to the first line and then start shifting all of the RAM one position to the left (my strings are typically 25-50 characters long and I am essentially trying to display them one after another so I have basically an 'endless' string).  As a matter of fact, I might just start writing the first character to the 40th position and then start shifting.  My only question is whether I will be able to loop through 40 positions (x2 lines) fast enough.

Richard

floresta

#10
Feb 12, 2013, 05:06 am Last Edit: Feb 12, 2013, 05:09 am by floresta Reason: 1
Quote
That was very helpful in understanding the guts of things, although I had assumed (perhaps incorrectly) that the LiquidCrystal library would take care of the sausage making, so to speak.

Before I forget (again) I think that I may have something for you along these lines.  A while back one of our forum contributors was dealing with 40x4 displays which are essentially two 40x2 displays in the same package.  While he was developing his liquidcrystal440 library he also did some work on the timing (since he had some incredibly out-of-spec displays) and also on the line wrapping.  The library is not restricted to 40x4 displays, it works with the smaller ones as well.  That original library has evolved into LiquidCrystal1.0 and to get a copy start here:--> http://code.google.com/p/liquidcrystal440/ and follow the Downloads link to get to the latest version.

Quote
Don do you have any example sketches for LCD control that don't use the LiquidCrystal library?

I do almost all of my work in assembly language but I know have some LCD stuff written for the pre 1.0 versions of the Arduino IDE around here somewhere since that's what I sent John when he was working on his liquidcrystal440 library.  I'll look for it.

Quote
My only question is whether I will be able to loop through 40 positions (x2 lines) fast enough.

I hope you understand that the 2 lines will inherently shift at the same time.  You can get around this with programming so it's is not a deal killer.

You might want to experiment by writing a 'normal' string of about ten characters to the display and then send at least 100 shift left commands, with a pause between each so you can watch what is going on.  You may be surprised at the result.


Don

bperrybap


 My only question is whether I will be able to loop through 40 positions (x2 lines) fast enough.

"fast enough" is a relative term.
How fast do you need to update the display? How often? How many cycles are used by other stuff?

The supplied LiquidCrystal library can update a full 16x2 display around 87 times per second or in around 11.5ms
If you switch to fm's LiquidCrystal library replacement,
it can update a full 16x2 display around 300 times per second or in around 3.3ms

The key to keeping the display updates fast and avoiding flicker is to avoid using lcd.clear() and lcd.home()
Those commands are quite slow.
With fm's library you can update the entire 16x2 display faster than time it takes lcd.clear() to execute.

You may want to consider managing a shadow display buffer in RAM.
Fill it in the way you want the display to look. Then, slam out the buffer to the display.
You can manage the shadow buffer anyway you like.
Either creating a full shadow buffer of all the display ram that you index into to create the scrolling effect
or just have the local buffer represent what will be displayed on the lcd.
I would think that even the supplied LiquidCrystal display should be more than fast enough to
do what you need.

--- bill


rwiens

Quote

How fast do you need to update the display? How often? How many cycles are used by other stuff?


I haven't figured out the exact speed (and it will actually change depending on the content) of the scroll but I would say at the fastest I need to shift at about 60ms (i.e. a character goes all the way from col 15 to col 0 in 1s).  The question is whether I could read and re-write all 80 characters in that time.  Sounds like the fm LiquidCrystal library replacement will at least update the display quickly enough (where do I find it?).

Quote

I hope you understand that the 2 lines will inherently shift at the same time. 


This is exactly what I am trying to accomplish.

Quote

You might want to experiment by writing a 'normal' string of about ten characters to the display and then send at least 100 shift left commands, with a pause between each so you can watch what is going on.  You may be surprised at the result.


I did some experimentation along these lines and did get unexpected results.  One thing I thought about was trying to read the memory pointer from the display controller to see what was happening.

Quote

You may want to consider managing a shadow display buffer in RAM.


I assume you are talking about the Arduino RAM?  The more I think about it, the more that seems like the easiest solution, although now I am curious about understanding what is actually happening in the display controller.

Thanks again for all your help.

floresta

Quote
I did some experimentation along these lines and did get unexpected results.


Just so we are on the same page here ....
(1) what did you do (in terms of programming)?
(2) what results did you get?
(3) what results did you expect?


Don

bperrybap


Quote

How fast do you need to update the display? How often? How many cycles are used by other stuff?


I haven't figured out the exact speed (and it will actually change depending on the content) of the scroll but I would say at the fastest I need to shift at about 60ms (i.e. a character goes all the way from col 15 to col 0 in 1s).  The question is whether I could read and re-write all 80 characters in that time.  Sounds like the fm LiquidCrystal library replacement will at least update the display quickly enough (where do I find it?).


60ms is a LONG time to a micro-controller.
Keep in mind, the times I quoted are to update the entire 16x2 display.
Doing this:
lcd.setCursor(0,0);
lcd.write(char); // repeated 16 times
lcd.setCursor(0,1);
lcd.write(char); // repeated 16 times.

All that gets done in 11.5ms on the standard library or 3.4ms using fm's library

( https://bitbucket.org/fmalpartida/new-liquidcrystal/wiki/Home )
To write an individual character to the display or position the cursor takes:
338us with the standard LiduidCrystal library or 98us with fm's library.


You don't need to re-write 80 characters.
All you need to do is write the 32 characters visible on the display.

In looking at your timing and doing some math:
You are wanting to scroll characters from col 15 to col 0
that is 16 "moves" in 1 second that means each move needs to happen in
1/16 of second or 62.5ms.
The standard LiduidCrystal libraray can update all 32 characters on the display
in 11.5ms and fm's library can udpate all 32 in 3.5ms.

When using the standard library that means you use
11.5ms out of your 62.5ms budget. Which means that
updating the display uses about 18% of the CPU available in your timing interval
which means you still have 72% of the CPU left over to do all your other stuff
like reading information from the SD card etc.
While fm's library would reduce that budget to just under 6%
my gut feeling is that based on what you have said you want to do
the standard LiquidCrystal library should be capable of doing what you want
even when updating the full 16x2 display each time you need to do a move/animation.



Quote

You might want to experiment by writing a 'normal' string of about ten characters to the display and then send at least 100 shift left commands, with a pause between each so you can watch what is going on.  You may be surprised at the result.


I did some experimentation along these lines and did get unexpected results.
One thing I thought about was trying to read the memory pointer from the display controller to see what was happening.


The memory pointer increases (assuming left to right) each time a character is written.
The memory pointer is set to an absolute address when setCursor() is called.


Quote

You may want to consider managing a shadow display buffer in RAM.


I assume you are talking about the Arduino RAM? 

Yes, just fill in your buffer and then write it to the display.
You can update the entire display, which is every single character position on a 16x2 display
in 11.51ms (87 times per second) using the standard library or in 3.35ms (~300 times per second)
If you shadow the full LCD ram, you can make things shift by simply changing the index
of where you start grabbing characters from memory.
Also if you use a local RAM buffer you will be able to shift the two lines independently.



Go Up