LCD module and AVR

91 posts / 0 new
Last post
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is an 'entry mode' command that lets you select whether to shift the cursor or the display, and if you shift the display, whether it shifts left or right. If you want it to act like a crt, the cursor should shift, not the display, and it should increment (move to the right) unless you want it to print arabic, which goes to the left.

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I follow Carl's advice to write only one caracter at line 0x80 and it was sucessefully drawn.

But with this issue i can say that i really dont understand datasheets!!

In the small datasheet of my LCD module the start address is 0x00 for the first line and 0x40 for the second! :S

Can somebody explain me why? And... how can i trust a datasheet if she tells me something that is wrong?

Another thing i realized with the experiment is that i need to LCD_PutCmd(LINE+numberOfCharacteresToBeWritten) to have a string written.

My entry mode i defined it as increment mode and entire shift off (what is this one related with?).

Another problem is that i can write a string in the first line and in the second.

But if try to write booth it doesnt work:

#define LINE1 0x80
#define LINE2 0xC0

const char BANNER_1[] = {"Control: 100"};
const char BANNER_2[] = {"Value: 127"};

LCD_PutCmd (LINE1+strlen(BANNER_1));
LCD_PutString (BANNER_1);
LCD_PutCmd (LINE2+strlen(BANNER_2));
LCD_PutString (BANNER_2);

The result is each case separetly is correct. The result of both lines instructions is 00 in the first line....

Any tips?

Thx

Nuno

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sinosoidal wrote:
I follow Carl's advice to write only one caracter at line 0x80 and it was sucessefully drawn.

But with this issue i can say that i really dont understand datasheets!!

In the small datasheet of my LCD module the start address is 0x00 for the first line and 0x40 for the second!

But by the datasheet that you provided, DB7 must be set to gain access to the address counter. There are 7 data bit address lines, DB6:DB0. The 8th data bit, DB7, is used to select between CGRAM and DDRAM. When CGRAM, DB7, is set to logic 0, the address counter of the custom characters is being selected. When DDRAM, DB7 is set to logic 1, DDRAM the DDRAM address counter is being use to select the internal character generator. CGRAM is used to select the memory store where "Custom Built" characters are stored. DDRAM is the character generator that the display uses to display its "Built-In" character set.

If DB6:DB0 (127 possible characters) are used as the CGRAM OR DDRAM address counter and the first character position on line 1 is 0x00 then the data to select that position using the default display characters must be 0x80 because, DB7 must be set to logic 1 to enable the default character generator set.

So, if line 1 starts at 0x00 then, line 1 position 0 becomes:

 0x00
+0x80
------
 0x80

That is why 0x80 is used for line1:position 0.

And, if line 1 starts at 0x40 then line 2 position 0 becomes:

 0x40
+0x80
------
 0xC0

That is why 0xC0 is used for line2:position 0.

By the datasheet you provided.

Attachment(s): 

Carl W. Livingston, KC5OTL
microcarl@roadrunner.com

"There are only two ways to sleep well at night... be ignorant or be prepared."

The original Dragon Slayer !

Long live the AVR!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

sinosoidal wrote:
Another thing i realized with the experiment is that i need to LCD_PutCmd(LINE+numberOfCharacteresToBeWritten) to have a string written.

My entry mode i defined it as increment mode and entire shift off (what is this one related with?).

Another problem is that i can write a string in the first line and in the second.

But if try to write booth it doesnt work:

#define LINE1 0x80
#define LINE2 0xC0

const char BANNER_1[] = {"Control: 100"};
const char BANNER_2[] = {"Value: 127"};

LCD_PutCmd (LINE1+strlen(BANNER_1));
LCD_PutString (BANNER_1);
LCD_PutCmd (LINE2+strlen(BANNER_2));
LCD_PutString (BANNER_2);

Nuno

No! It is:

LCD_PutCmd (LINE1 + Offset);
LCD_PutString (BANNER_1);
LCD_PutCmd (LINE2 + Offset);
LCD_PutString (BANNER_2);

String length is determined by the fact that the character strings are inherently NULL terminated by the compiler when they are assigned to the array when it was defined - at least in ImageCraft ICCAVR they are.

The format for

LCD_PutCmd (LINE1 + 3);

is:

LCD_PutCmd (StartinPosition + Offset);

IT IS NOT

LCD_PutCmd (StartingPosition + CharacterCount);

If this is the case, you have either changed my LCD_PutCmd (); function or, your compiler doesn't handle string terminations to the C standard.

Carl W. Livingston, KC5OTL
microcarl@roadrunner.com

"There are only two ways to sleep well at night... be ignorant or be prepared."

The original Dragon Slayer !

Long live the AVR!!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok. Definitly. I don't know how to read datasheets!

Well. Its seems all clear now!

About that other issue about strlen. It isnt having that behaviour. Now that i got back to this it was not working.

The first thing i tried was to take off that +strlen and put a 0 offset.

Its working perfectly.

Maybe something like the entry set was not defined yet and after the long power out it was now initialized with that.

I just got to thank you all for the incredible patient!

Thx!!!

Best regards,

Nuno

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi again,

I'm trying to adapt carl's code to use only port. In this case, only PORTD.

I have the pins 0,1,2 and 3 connected to DB4,DB5,DB6 and DB7.

The pins 4, 5 and 6 are connected to RS,RW and E.

The code i'm using is the following. I'm just trying to initialize for now. Maybe my problem is the bit operations. I'm still very confused about it.

The actual behaviour is the first line filled with black squares and the cursor blinking at the third square. If i program it again, the blinking cursor jumps one time to the right.

#define F_CPU 1000000
#include 
#include 

// Define LCD Register Select as PORTD, 0x10;
#define LCD_RS 4
// Define LCD Read/Write as PORTD, 0x20; 
#define LCD_RW 5
// Define LCD Enable as PORTD, 0x40; 
#define LCD_E 6 

// DISPLAY ON, 2 LINE MODE
#define   PWR_CMD1   0x20
#define   PWR_CMD2   0x20
#define   PWR_CMD3   0xC0

// DISPLAY ON, CURSOR ON, BLINK ON
#define   DL_CMD1   0x00
#define   DL_CMD2   0xF0

// CLEAR DISPLAY COMMAND      
#define CLR_DSP1 0x00
#define CLR_DSP2 0x10

// ENTRY MODE SET
#define ENT_MOD1 0x00
#define ENT_MOD2 0x60

#define LINE1 0x80
#define LINE2 0xC0

#define NULL 0x00

const char BANNER_1[] = {"Control: 100"};
const char BANNER_2[] = {"Value: 127"};

void LCD_Delay (unsigned long int d);
void LCD_IO_INIT (void);
void LCD_INIT (void);
void LCD_PutCmd (char);
void LCD_PutChar (char);
void LCD_PutString (const char *);

void main (void) {
	DDRB = 0xFF;
	PORTB = 0xFF;

	LCD_IO_INIT ();
	LCD_INIT ();

	/*
	LCD_PutCmd (LINE1);
	LCD_PutString (result);
	LCD_PutCmd (LINE2);
	LCD_PutString (BANNER_2);
	*/
}

void LCD_Delay (unsigned long int d) {
    unsigned long int n;
    for (n = 0; n < d; n++);
}

void LCD_IO_INIT (void) {
    DDRD = 0xFF; // PORTD is the LCD DATA AND CONTROL LINES
    PORTD = 0x00;
    PORTD |= (1<<LCD_RS);
	PORTD |= (1<<LCD_E);
	LCD_Delay (500); // Wait for the up LCD to power up         
}

void LCD_INIT (void) {
	LCD_PutCmd (PWR_CMD1);
	LCD_PutCmd (PWR_CMD2);
	LCD_PutCmd (PWR_CMD3);

	_delay_us(40);
	
	LCD_PutCmd (DL_CMD1);
	LCD_PutCmd (DL_CMD2);

	_delay_us(40);
	
	LCD_PutCmd (CLR_DSP1);
	LCD_PutCmd (CLR_DSP2);

	_delay_ms(2);

	LCD_PutCmd (ENT_MOD1);
	LCD_PutCmd (ENT_MOD2);

    LCD_Delay (500); // Wait for the LCD to boot up   
}
 
void LCD_PutCmd (char c) {
  PORTD &= ~(1<<LCD_RS);
  LCD_Delay (5); // Wait for the proper setup time to respond to the RS control line 
  LCD_PutChar(c);
  LCD_Delay (5); // Wait for the proper setup time to respond to the command being applied
  PORTD |= (1<<LCD_RS);
}

void LCD_PutChar (char c) {
    PORTD |= (1<<LCD_E);
    LCD_Delay (5); // Wait for the proper setup time to respond to the E pulse   
    PORTD = c;
    LCD_Delay (5); // Wait for the proper setup time to respond to the character being applied
    PORTD &= ~(1<<LCD_E);
}
 
void LCD_PutString (const char *p) {
    char n = NULL; // Pointer position counter.
    while (p[n] != NULL) // Keep sending data until the NULL character is found.
         LCD_PutChar(p[n++]);
}
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Back to 4 bit mode... we went thru this a couple days ago.... the putchar routine that used to put all 8 bits now is two subroutines.. put hi nib of c out on the hi bits, and another sub to put lo nib of c out on the hi bits... involves anding c with 0f and f0 and shifting.... I dont see that you've added that part to Carl's 8 bit program, so need to go look for a 4 bit example to port over....

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
Back to 4 bit mode... we went thru this a couple days ago.... the putchar routine that used to put all 8 bits now is two subroutines.. put hi nib of c out on the hi bits, and another sub to put lo nib of c out on the hi bits... involves anding c with 0f and f0 and shifting.... I dont see that you've added that part to Carl's 8 bit program, so need to go look for a 4 bit example to port over....

Ohh.... ok... But the initialization is not being done correctly. Before write anything to the module i need a correct initialization.

Can you see anything wrong beside that?

Thx

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

One or several of the first instructions you send to the display is not correct.

When the display powers up it is in 8-bit mode.

So the display wants to se all instructions up to, and including, the one that sets it in 4-bit mode as 8-bit instructions. (Your code sends all instructions as 8-bit instructions, by sending them as two consecutive nibbles. That will not work).

How is this possible in 4-bit mode?, you ask. Well, as the low nibble of these instructions are "don't care" then what you need is to send only the high nible of these instructions - the low nibble of the LCD is unconnected (or maybe tied to ground) and will be read by the display as zeroes).

So you need to follow the sequence below (and I am following the official init sequence, as documented in Hitachis 44780 data sheet - it might be that Carls code does not follow that sequence to the letter):

1. Wait at least 15 ms
2. Send the high nibble of a Function Set instruction
3. Wait at least 4.1 ms
4. Send the high nibble of a Function Set instruction
5. Wait at least 0.1 ms (100 us)
6. Send the high nibble of a Function Set instruction
7. Send the high nibble of a Function Set instruction for 4-bit interface
It is at his point the 4-bit interface becomes interactive. From now on you send complete 8-bit instructions as twop consecutive nibbles, high nibble first.
8. Send a Function Set instruction, 4-bit interface, and N and F bits set to your liking.
9. Send a Display Off
10. Send a Display Clear instruction
11. Send a Entry Mode Set instruction
And then finally
12. Send a Display On instruction

The document that I am referencing is in this thread: http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=116409#116409, in the file 99rtd006d2.zip, which contains a PDF by the same name. The 4-bit init sequence is on p 46.

Also, as a "preview" I attach a small test program for 4-bit interface and the avr-gcc compiler. It was not my intention to let this out in public just yet as it is intended for a LCD tutorial I am working on, but it might help you move forward. You may use it on the condition that you supply me with any feedback on it that you have. Really! I mean it - you get it in return for being my giunea-pig. If you don't try it out at all I would like to know that too. I have tried it on a ATmega88 and it worked flawlessly for me. I think you will find that the comments in the code should clarify what you will need to change for it to fit your connection of the display. Only one thing that might be akward: You have to have the 4 data bits (DB4..DB7) on the 4 high pins of a port, but I don't think that this will be a problem. If you really need them on the low bits of a port then I can hlp you with this in the week-end. You will also find that all instruction names and signals are in close resemblace with their names in the data sheet I am referring to.

Also, please note that I in no way am saying that Carls code is not working. On the contrary, I am quite sure that it is. View my code merely as as an alternative test.

Hope this helps!

Attachment(s): 

"Some questions have no answers."[C Baird] "There comes a point where the spoon-feeding has to stop and the independent thinking has to start." [C Lawson] "There are always ways to disagree, without being disagreeable."[E Weddington]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi,

It works perfectly. I gave a light look across all the code and i have some doubts that i would like to put you.

Not now because i need to sleep. But tomorow! If you are available to answer them, of course! :)

Thx,

Nuno

Pages