LiquidCrystal440 two cursors

Hi,

I have here a 4x27 LCD with two HD4478 controllers. For this I'm using the Liquidcrystal440 library.
If I set cursor "on" or "blinking", I see two cursors. This is actually ok because of the two controllers.
But I would like to see only one of them. At the moment I set lcd.cursor() then I lcd.setCursor() to the
other controller, set lcd.noCursor() and then lcd.setCursor() back to where I want to have the cursor.

Does anybody have a more "elegant" method to do this? I was thinking of a method like cursor(1) and cursor(2)
for the two controllers but I have no clue how to do it.

Hermann

I took a quick look at the LiquidCrystal440 source code and the setCursor routine includes a step with the comment "//turn off cursor on chip we are leaving". So it looks as if the author at least attempted to achieve the effect that you desire. I personally do not use a visible cursor and there's a good chance that the author does not either. If this is the case he may not have thoroughly tested that part of the setCursor routine and it may not be working as he intended.

You could also go to the project home at Google Code Archive - Long-term storage for Google Code Project Hosting. and start an 'Issue' or perhaps contact the author. He frequents this forum (although I haven't seen him recently) and he may spot this thread and respond. If you don't get a response in a day or so I can send him an Email and rattle his cage.

Don

Thanks Don,

I´ll do that.

Hermann

it has been a long time since I looked at the code. I tried to test thoroughly on a 40x4 LCD but I think the only blinking cursor test I did was this:

	//====== Turn on the blinking cursor:
    lcd.clear();
    lcd.setCursor(0,nRows-1);
    lcd.print("Blinking Cursor");
    lcd.blink();
    delay(1000);
	// Turn off the blinking cursor:
    lcd.noBlink();
    delay(1000);
    lcd.setCursor(0,0);
    lcd.print("Blinking Cursor");
    lcd.blink();
    delay(1000);
	// Turn off the blinking cursor:
    lcd.noBlink();
    delay(1000);

As Don noted I put this into setCursor:

void LiquidCrystalFast::setCursor(uint8_t col, uint8_t row)         // this can be called by the user but is also called before writing some characters.
{
	if ( row > _numlines ) {
		row = _numlines-1;    // we count rows starting w/0
	}
	_y = row;
	_x = col;
	_setCursFlag = 0;                                                 //user did a setCursor--clear the flag that may have been set in write()
	int8_t high_bit = row_offsets[row] & 0x40;                        // this keeps coordinates pegged to a spot on the LCD screen even if the user scrolls right or
	int8_t  offset = col + (row_offsets[row] &0x3f)  + _scroll_count; //left under program control. Previously setCursor was pegged to a location in DDRAM
	//the 3 quantities we add are each <40
	if (offset > 39) offset -= 40;                                    // if the display is autoscrolled this method does not work, however.
	if (offset < 0) offset += 40;
	offset |= high_bit;
	if (_chip != (row & 0b10)) noCursor();  //turn off cursor on chip we are leaving
	_chip = row & 0b10;                     //if it is row 0 or 1 this is 0; if it is row 2 or 3 this is 2
	command(LCD_SETDDRAMADDR | (byte) offset );
}

It will probably be the weekend before I can really look at it.

As I said, it will be a few days before I can really look at this. I wonder if what I need is to add another line under:

if (_chip != (row & 0b10)) noCursor();  //turn off cursor on chip we are leaving

to turn off the blinking cursor.

I am not entirely sure I fully understand the problem you are seeing; it might help to post a little of the code that shows the problem

I am not entirely sure I fully understand the problem you are seeing; it might help to post a little of the code that shows the problem

John:
I don't have any 40x4 displays but there's nothing different about them than running two 20x4 displays in parallel with separate 'E' lines. Each display has a cursor which indicates where the next character will be displayed. If you load up the data lines with the ASCII code for a character and pulse both 'E' lines then the character will appear on both displays (or on both halves of the 40x4 display). If you only pulse one of the 'E' lines then the character will appear on the corresponding display and that cursor will advance to the next location. The cursor will remain where it was on the other display.

For the normal use of a 40x4 display and if you are going to have a visible cursor you really want only one of them visible, the one that you intend to use next. All your software is (apparently) doing right now is determining which of the displays to use next without blanking the other cursor. From the comment I quoted it looks like you thought about the problem but didn't implement it.

Don

This illustrates exactly why I want to see (preferably a small snippet of) code that does not work.

i believe that I correctly turn off the standard cursor, but neglect to turn off the blinking cursor and I THINK that is what was described.

Don does not think I correctly turn off the standard cursor and he THINKS that is what was described.

Fumbling around trying to guess what the described problem is without the code may result in me changing something without fixing your issue.

I have much of the solution done. I used this test code:

// cursor tests--see if cursor correctly turned off as we leave second chip, mainly
        lcd.clear();
        lcd.noCursor();
        int i=0;
        while (i<nRows*2) {
        lcd(0,i%4)<<"no cursor"<<i;
        i++;
        delay(500);
        }
        delay(4000);
        
        lcd.clear();
        lcd.cursor();
        i=0;
        while (i<nRows*2) {
        lcd(0,i%4)<<"cursor"<<i;
        i++;
        delay(500);
        }
        delay(4000);
        lcd.noCursor();
        
        lcd.clear();
        lcd.blink();
        i=0;
        while (i<nRows*2) {
        lcd(0,i%4)<<"blink"<<i;
        i++;
        delay(500);
        }
        delay(4000);
        lcd.noBlink();
        
        lcd.clear();
        lcd.cursor();
        lcd.blink();
        i=0;
        while (i<nRows*2) {
        lcd(0,i%4)<<"c+b"<<i;
        i++;
        delay(500);
        }
        delay(4000);
        lcd.noCursor();
        lcd.noBlink();        
//end cursor test 1

(I'm using Streaming)

As Don said, I'd never really used cursors and had not thought carefully about them. So the spot where I turned the underline cursor off really should have turned the cursor on on the other chip and I ignored the blinking cursor altogether.

The command to turn the display on or off also resets the cursor flags.

here are the changes to LiquidCrystal.cpp that I've made:

void LiquidCrystal::display() {
	_displaycontrol |= LCD_DISPLAYON;
	commandBoth(LCD_DISPLAYCONTROL | _displaycontrol & 0xfc);   //both chips on, both cursors off
	command(LCD_DISPLAYCONTROL | _displaycontrol);              //selected chip gets cursor on
}

and

void LiquidCrystal::setCursor(uint8_t col, uint8_t row)         // this can be called by the user but is also called before writing some characters.
{
	if ( row > _numlines ) {
		row = _numlines-1;    // we count rows starting w/0
	}
	_y = row;
	_x = col;
	_setCursFlag = 0;                                                 //user did a setCursor--clear the flag that may have been set in write()
	int8_t high_bit = row_offsets[row] & 0x40;                        // this keeps coordinates pegged to a spot on the LCD screen even if the user scrolls right or
	int8_t  offset = col + (row_offsets[row] &0x3f)  + _scroll_count; //left under program control. Previously setCursor was pegged to a location in DDRAM
	//the 3 quantities we add are each <40
	if (offset > 39) offset -= 40;                                    // if the display is autoscrolled this method does not work, however.
	if (offset < 0) offset += 40;
	offset |= high_bit;
	if (_chip != (row & 0b10)) 	command(LCD_DISPLAYCONTROL | _displaycontrol & 0xfc);;  //turn off cursors on chip we are leaving
	_chip = row & 0b10;																//if it is row 0 or 1 this is 0; if it is row 2 or 3 this is 2
	command(LCD_DISPLAYCONTROL | _displaycontrol);									//turn on cursor on chip we moved to
	command(LCD_SETDDRAMADDR | (byte) offset );
}

Stylistically 0xfc should get changed; the underline and blink cursor are in bits 0x01 and 0x02 and are defined symbolically in LiquidCrystal.h

so far I have just run the 40x4 through the test code. The one thing I see is that the underline cursor now is left on at the end of the first time through the loop of tests. That may be the desired behavior, I'm inclined to think that it is.

the nice surprise as I actually coded this is that I did not need another RAM location to keep track of cursor flags.

I will get the full test done on all the LCDs over the next few days; I doubt there will be surprises. then I can zip and post the code. It would be nice to know that this solves your problem.

I posted updated code at Google Code Archive - Long-term storage for Google Code Project Hosting.

it is slightly different from what I posted yesterday, mainly:

LiquidCrystal.h defines LCD_CURSORS_MASK to replace 0xfc and for improved efficiency the command to turn the cursor on for the selected chip is only executed when moving to a new chip:

void LiquidCrystal::setCursor(uint8_t col, uint8_t row)         // this can be called by the user but is also called before writing some characters.
{
	if ( row > _numlines ) {
		row = _numlines-1;    // we count rows starting w/0
	}
	_y = row;
	_x = col;
	_setCursFlag = 0;                                                 //user did a setCursor--clear the flag that may have been set in write()
	int8_t high_bit = row_offsets[row] & 0x40;                        // this keeps coordinates pegged to a spot on the LCD screen even if the user scrolls right or
	int8_t  offset = col + (row_offsets[row] &0x3f)  + _scroll_count; //left under program control. Previously setCursor was pegged to a location in DDRAM
	//the 3 quantities we add are each <40
	if (offset > 39) offset -= 40;                                    // if the display is autoscrolled this method does not work, however.
	if (offset < 0) offset += 40;
	offset |= high_bit;
	if (_chip != (row & 0b10)) 	{
		command(LCD_DISPLAYCONTROL | _displaycontrol & LCD_CURSORS_MASK);  //turn off cursors on chip we are leaving
		_chip = row & 0b10;																//if it is row 0 or 1 this is 0; if it is row 2 or 3 this is 2
		command(LCD_DISPLAYCONTROL | _displaycontrol);									//turn on cursor on chip we moved to
	}
	command(LCD_SETDDRAMADDR | (byte) offset );
}

Thanks for finding the error and helping me improve the code!

Hello guys,

I was away for a few days and only saw your answers today.

There is not much to say about the source code.
I just set the cursor to a certain position and set blink on.
lcd.setCursor(10,2);
lcd.blink();

Then I see a blinking cursor at position 10,2 and at the last position in the upper part of the display.
Later I set lcd.noBlink(); and the cursor in the lower part disappears but the cursor in the upper part stays on.

I didn't test the normal (underscore) cursor...
Tonight I will test the changes in your code and will report back.

Thanks!
Hermann

It works!!

Thanks a bunch John!

Hermann

Again, thank YOU for helping improve the code!