Simple LCD code and M48 again!!

Go To Last Post
31 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Freaks,
I have been trying to get my LCD working for a long time. I am using the simplest possible setup. I am using Johann Ekdahl's code as follows:


/* Simple LCD character display module demonstrator using the 4-bit interface. No handling of the busy flag is done - all timing contraints are handled by delay loops.

 * This code should be good to run at up to 8 MHz.
 * Above that you might have to tweak the timing of things including, but not restricted to, the existing delays.

 */


#include 
#include 

/* Here are some defines for the data connections,

 * DB4..7 on the LCD display module. These should be wired

 * up to the four high pins  of any port A..D. You need to alter

 * these to fit your wire up of your display.

 */

#define LCD_DATA_PORT PORTD
#define LCD_DATA_DDR  DDRD


/* Here are some defines for the control connections

 * (RS, R/W and E on the LCD display module). These can be wired

 * to any pins on any port A..D (all to the same port though).

 * You need to alter these to fit your wire up of your display.

 */

#define LCD_CTRL_PORT PORTD
#define LCD_CTRL_DDR  DDRD
#define LCD_RS        2
#define LCD_RW        3
#define LCD_E         4

 

/*

 * YOU SHOULD NOT NEED TO ALTER ANYTHING BEYOND THIS POINT!

 *

 * This holds as long as you have the four data signals

 * connected to the upper 4-bit nibble of the AVR port,

 * and you run at a maximum frequency of 8 MHz.

 */

 

/* Here are some defines for the LCD instructions we'll use.

 */

#define LCD_FUNCTION_SET      0x38 // 0b00110000
#define LCD_FUNCTION_SET_4BIT 0x28 // 0b00101000
#define LCD_DISPLAY_OFF       0x08 // 0b00001000
#define LCD_DISPLAY_ON        0x0F // 0b00001111
#define LCD_DISPLAY_CLEAR     0x01 // 0b00000001
#define LCD_ENTRY_MODE_SET    0x06 // 0b00000110
#define LCD_CURSOR_HOME       0x02 // 0b00000010

 

 

/* LcdSendNibble

 *

 * Sends a 4-bit nibble to the display.

 *

  * Parameters:

 *    uint8_t nibble    The high nibble of of this byte

 *                    is sent to the display.

 * Returns:

 *    nothing

 */

void LcdSendNibble( uint8_t nibble )

 {
   _delay_ms(5);

   // Output upper nibble on the data ports upper bits
   LCD_DATA_PORT = (nibble & 0xF0) | (LCD_DATA_PORT & 0x0F);

 

   // Toggle the E line

   LCD_CTRL_PORT |= (1<<LCD_E);   // Going up..
   LCD_CTRL_PORT &= ~(1<<LCD_E);  // ..and down.

  }

 

/* LcdSendByte

 *

 * Sends a 8-bit byte to the display.

 *

 * Parameters:

 *    uint8_t theByte    The byte to send to the display

 *

 * Returns:

 *    nothing

 */

void LcdSendByte(uint8_t theByte)

  {

   // Send the high nibble

   LcdSendNibble(theByte);

 

   // Shift theByte to get lower nibble in upper part...

   theByte = theByte << 4;

   // ...and send it

   LcdSendNibble(theByte);

   }

 

/* LcdSendInstruction

 *

 * Sends an instruction to the display.

 *

 * Parameters:

 *    uint8_t command    This byte is sent to the display as

 *                    an instruction (RS low).

 * Returns:

 *    nothing

 */

void LcdSendInstruction( uint8_t theInstruction )

  {

   // RS low for instructions

   LCD_CTRL_PORT &= ~(1<<LCD_RS);

 

   // Send the instruction

   LcdSendByte(theInstruction);

  }

 

/* LcdSendCharacter

 *

 * Sends a character to the display.

 *

 * Parameters:

 *    uint8_t nibble    This byte is sent to the display as

 *                    a character (RS high).

 * Returns:

 *    nothing

 */

void LcdSendCharacter(uint8_t theChar)

  {

   // RS high for characters to display

   LCD_CTRL_PORT |= (1<<LCD_RS);

 

   // Send the command

   LcdSendByte(theChar);

  }

 

/* LcdInitialize

 *

 * Initialize the display.

 *

 * Parameters:

 *    none

 *

 * Returns:

 *    nothing

 */

void LcdInitialize(void)

  {

   // initialize LCD control lines

   LCD_CTRL_PORT &= ~(1<<LCD_RS);    // RS low

   LCD_CTRL_PORT &= ~(1<<LCD_RW);    // R/W low

   LCD_CTRL_PORT &= ~(1<<LCD_E);    // E low

 

   // initialize LCD control lines to output

   LCD_CTRL_DDR |= (1<<LCD_RS);

   LCD_CTRL_DDR |= (1<<LCD_RW);

   LCD_CTRL_DDR |= (1<<LCD_E);

 

   // initialize LCD data port to input

   LCD_DATA_DDR |= 0xF0;      // Data on high four bits of port for now...

 

   // First part of init sequence is 3 x Function Set with

   // stipulated waits. Note that the display is in 8-bit mode

   // initially, but although the four low data lines are not connected

   // this does not matter as the instructions low nibble is zero anyway.

   _delay_ms(15);

   LcdSendNibble( LCD_FUNCTION_SET );

   _delay_ms(5);

   LcdSendNibble( LCD_FUNCTION_SET );

   _delay_us(100);

   LcdSendNibble( LCD_FUNCTION_SET );

 

   // Now, still in 8-bit mode, set the display to 4-bit mode

   LcdSendNibble( LCD_FUNCTION_SET_4BIT );

 

   // We are now in 4-bit mode.

   // Do the rest of the init sequence.

   LcdSendInstruction( LCD_FUNCTION_SET_4BIT );

   LcdSendInstruction( LCD_DISPLAY_OFF );

   LcdSendInstruction( LCD_DISPLAY_CLEAR );

   LcdSendInstruction( LCD_ENTRY_MODE_SET );

   LcdSendInstruction( LCD_DISPLAY_ON );

  }

 

char message[] = "4-bit";

 

 

int main(void)

   {

     LcdInitialize();

     DDRD = 0xFF;
     PORTD = 0xFF;
 

     volatile int i = 0;

     while (message[i] != 0)

      {

         LcdSendCharacter(message[i]);

         i++;

      }

 

   while(1);

   return 0;

}

I have assigned everything to PortD. I have changed nothing in Johann's code except in main I have assigned port D (DDRD and PORTD )with 0xFF.

I am using an external crystal (8MHz) which I have confirmed the AVR is using.

Also everything else works fine with a simple test circuit (flashing an LED).

When I turn the power ON for my AVR, I see the blocks on my LCD on the first line. My LCD is a standard HD44780 driver type.

What am I missing?
Since I am using the four ports of Port D do I have to ground the unused pins on the LCD driver?
Is it maybe the delays that I have to tweak?

Any help appreciated. I have attached my schematic.
Thanks.

Attachment(s): 

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

Quote:
I am using an external crystal (8MHz) which I have confirmed the AVR is using.

Which probably means that your enable line goes high for only 250ns. It needs to go high for 500ns. Add in a couple of NOPs between.

Regards,
Steve A.

The Board helps those that help themselves.

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

Quote:
What am I missing?
Lot's of capacitors at a first glance. You need one 100nF on the reset line to give you a good reset (unless you are using the BOD). Do you have bypass caps springled across your supply lines? What about the 2 caps for the crystal?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

npat_avr:

All four of the

Quote:
LcdSendNibble( LCD_FUNCTION_SET...
instructions need delays after them (even though they are missing from the datasheet flowchart). Try 100 uS.

floresta

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

Thanks, guys.

Just want to confirm:Is this where I should add the NOP's?

// Toggle the E line

   LCD_CTRL_PORT |= (1<<LCD_E);   // Going up..
   NOP();
   NOP();
   NOP();
   LCD_CTRL_PORT &= ~(1<<LCD_E);  // ..and down. 
   NOP();
   NOP();

Also John,I don't have any caps on the reset line or the two caps for the crystal. I was doing a very simple app. so decided not to use the crystal caps. But I will add them and see if they make a difference.

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

npat_avr:

#define LCD_RS        2
#define LCD_RW        3
#define LCD_E         4 

Shouldn't these be defined in terms of the Port pins rather than the IC pins? I'm not sure of the exact syntax, but something like this.

#define LCD_RS        PD0
#define LCD_RW        PD1
#define LCD_E         PD2 

floresta

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

Quote:
I was doing a very simple app.
Some people decide to do a simple jump from a plane so they do not need the parachute. :?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Yes, floresta1212 has found one flaw. The pin numbers you state in the code should be the numbers within the port used, not the physical pin numbers on the chip pachage. From your circuit you have the control lines on PORTD pins 0, 1, and 2.

Yes instructions need delays after them, but apart from Clear display there should be no need for extra delays if running at max 8 MHz. (And would explicit delays be needed after instructions they should not go after LcdSendNibble but after LcdSendInstruction.) I don't have the figures under my eyes at the moment, but I can assure you that I checked the timing diagrams thoroughly. Still, different generations and makes of the 44780 has been reported to have varying timing characteristics. The best way to rule out a timing issue is not to mess with the code, but to slow down the controller. Eg 1MHz. If it starts working there then go look at timing. If it doesen't run at 1 MHz I would look for other things first.

Start by fixing those pin numbers.

Good luck!

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"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] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Johan:

I looked over your code again and I see that LcdSendNibble has a 5 mS delay built into it which should be a sufficient delay for all instructions but not for the first power-up delay. Why did you put additional delays after the first two 'Function Set' instructions in the reset procedure?

I would appreciate it if you (and anyone else who is interested) could look over the information on LCD Initialization that I have at http://web.alfredstate.edu/weimandn and let me know what I missed or misinterpreted.

Don

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

Quote:

Why did you put additional delays after the first two 'Function Set' instructions in the reset procedure?

Because they are stipulated in the data sheet. You should read it.

I once posted the applicable figure here: https://www.avrfreaks.net/index.p...

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"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] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Thanks, floresta and Johann. I will fix the pin numbers. I was using an external 8M crystal, but I will also try switching over to the 1M with internal RC, if the pin numbers don't work.

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

Johan-

Please do not misinterpret what I am saying here. I understand your frustration with students and others who come here without doing much research and expect you and the other regulars to do their work for them. Your terse, sometimes sarcastic, answers sound just like they came from me! I have never been accused of being diplomatic.

Now back to the business at hand:

Quote:
Because they are stipulated in the data sheet. You should read it.

From my previous post:
Quote:
I would appreciate it if you (and anyone else who is interested) could look over the information on LCD Initialization that I have at http://web.alfredstate.edu/weimandn and let me know what I missed or misinterpreted.

If you would look at the above link you will find the 'applicable figure' that you referenced, comments about that flowchart, a revised flowchart, and a complete step by step analysis of the initialization procedure. Do you really think I came up with all of that information without looking at the datasheet?

Don

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

OK, Don. Sorry.

But what puzzles me then is why you asked about the additional delay when you knew they had to be there according to the sheet.
The sheet says 15 ms, 4.1 ms and 100 us before the three first Function Sets respectively. Looking at the code now...

   _delay_ms(15);
   LcdSendNibble( LCD_FUNCTION_SET );
   _delay_ms(5);
   LcdSendNibble( LCD_FUNCTION_SET );
   _delay_us(100);
   LcdSendNibble( LCD_FUNCTION_SET ); 

If you knew about the stipulated delays in the sheet, what where you wondering about?

I was over at your site, and quickly browsing over it it looks impressive. I'm sorry I dont have the time to proof-read it, at least not for a month ahead. Yes, you have a lot of material there and it will take hours to proof-read.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"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] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

In addition to all above, your message[] has no zero at the end of the string. Change it to:
char message[] = "4 bit\0";

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

Quote:
In addition to all above, your message[] has no zero at the end of the string. Change it to:
char message[] = "4 bit\0";

:shock:

Nono, Simonetta! The compiler will add that terminating zero to any string literal surrounded by double quotes.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"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] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Quote:

In addition to all above, your message[] has no zero at the end of the string.

What are you talking about? You may want to consider taking a look at a good reference on C programming like K&R but the fact is that in C "4-bit" will define:

message[0]='4'
message[1]='-'
message[2]='b'
message[3]='i'
message[4]='t'

and, most importantly it throws in:

message[5]=0

for nothing.

If you really included a '\0' one the end you would get:

message[5]=0
message[6]=0

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

Yep. It's a char array so don't need the \0 terminator.

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

Johan:

Quote:
If you knew about the stipulated delays in the sheet, what where you wondering about?

When I looked more carefully at your code I saw that LcdSendNibble (which is used by LcdSendInstruction) incorporates a 5 ms delay. Therefore it already implements all of the time delays that are called out in the flowchart except for the initial 15 ms delay. That is why I characterized the two delays in question as 'additional'.

Don

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

Quote:

for nothing.

Well, actually for 1 byte of flash and one byte of RAM. :wink:

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"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] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Quote:

npat_avr:
Code:
#define LCD_RS 2
#define LCD_RW 3
#define LCD_E 4

Shouldn't these be defined in terms of the Port pins rather than the IC pins? I'm not sure of the exact syntax, but something like this.
Code:
#define LCD_RS PD0
#define LCD_RW PD1
#define LCD_E PD2

floresta

The problem with those names are that when used they contribute the same factg a second time. This is redundancy and will probably lead to confusion or errors. Eg if you have

#define LCD_CTRL_PORT PORTC
#define LCD_RS_PIN PC0
#define LCD_RW_PIN PC1
#define LCD_E_PIN PC2

and you then decide to move the LCD to PORTD, in how many places do you need to change things? If you had

#define LCD_CTRL_PORT PORTC
#define LCD_RS_PIN 0
#define LCD_RW_PIN 1
#define LCD_E_PIN 2

which will ultimately expand to the same thing as the first example, how many places needs change now?

Now some lazy programmer (you know what they look like, blue shirt on white T-shirt, shades and the tounge hanging out :D) moves the LCD from PORTC to PORTD but realises that PC0 and PD0 expands to the same thing. As he is so eager to move on he edits the defines thus:

#define LCD_CTRL_PORT PORTD
#define LCD_RS_PIN PC0
#define LCD_RW_PIN PC1
#define LCD_E_PIN PC2

and it works just fine. Half a year later something goes wrong, the display stops working and by this time that lazy bugger hs lost all memory of the trick, or it is someone else that now has the responsibility for maintaining the code. How much time will this programmer spend on de-confusing himself before he decides that the current problem is not caused by that inconsistent code?

No, in this (and many other) case(s) it should be

#define LCD_RS_PIN 0
#define LCD_RW_PIN 1
#define LCD_E_PIN 2

if you ask me.

Fighting redundancy in program code is done for a very practical purpose - to make the code as maintainable as possible. Us programmers spends an awful lot of time maintaining old code, and very little time writing new code. Anything you can do today to save maintenance time tomorrow is well worth considering.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"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] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Johan

Quote:
Half a year later something goes wrong ...

Wouldn't a comment be the best answer?

Don

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

Ok I made the changes and here is what I did:

/* Simple LCD character display module demonstrator using

 * the 4-bit interface. No handling of the busy flag is

 * done - all timing contraints are handled by delay loops.

 * This code should be good to run at up to 8 MHz.

 * Above that you might have to tweak the timing of things

 * including, but not restricted to, the existing delays.

 */

 



#include 

#include 

//#define F_CPU 1000000UL 

/* Here are some defines for the data connections,

 * DB4..7 on the LCD display module. These should be wired

 * up to the four high pins  of any port A..D. You need to alter

 * these to fit your wire up of your display.

 */

#define LCD_DATA_PORT PORTD

#define LCD_DATA_DDR  DDRD

 

/* Here are some defines for the control connections

 * (RS, R/W and E on the LCD display module). These can be wired

 * to any pins on any port A..D (all to the same port though).

 * You need to alter these to fit your wire up of your display.

 */

#define LCD_CTRL_PORT PORTD

#define LCD_CTRL_DDR  DDRD

#define LCD_RS        PD0 //2

#define LCD_RW        PD1//3

#define LCD_E         PD2//4

 

/*

 * YOU SHOULD NOT NEED TO ALTER ANYTHING BEYOND THIS POINT!

 *

 * This holds as long as you have the four data signals

 * connected to the upper 4-bit nibble of the AVR port,

 * and you run at a maximum frequency of 8 MHz.

 */

 

/* Here are some defines for the LCD instructions we'll use.

 */

#define LCD_FUNCTION_SET      0x38 // 0b00110000

#define LCD_FUNCTION_SET_4BIT 0x28 // 0b00101000

#define LCD_DISPLAY_OFF       0x08 // 0b00001000

#define LCD_DISPLAY_ON        0x0F // 0b00001111

#define LCD_DISPLAY_CLEAR     0x01 // 0b00000001

#define LCD_ENTRY_MODE_SET    0x06 // 0b00000110

#define LCD_CURSOR_HOME       0x02 // 0b00000010

 

 

/* LcdSendNibble

 *

 * Sends a 4-bit nibble to the display.

 *

 * Parameters:

 *    uint8_t nibble    The high nibble of of this byte

 *                    is sent to the display.

 * Returns:

 *    nothing

 */

void LcdSendNibble( uint8_t nibble )

{

   _delay_ms(20);

 

   // Output upper nibble on the data ports upper bits

   LCD_DATA_PORT = (nibble & 0xF0) | (LCD_DATA_PORT & 0x0F);

 

   // Toggle the E line

   LCD_CTRL_PORT |= (1<<LCD_E);   // Going up..

   LCD_CTRL_PORT &= ~(1<<LCD_E);  // ..and down.

}

 

/* LcdSendByte

 *

 * Sends a 8-bit byte to the display.

 *

 * Parameters:

 *    uint8_t theByte    The byte to send to the display

 *

 * Returns:

 *    nothing

 */

void LcdSendByte(uint8_t theByte)

{

   // Send the high nibble

   LcdSendNibble(theByte);

 

   // Shift theByte to get lower nibble in upper part...

   theByte = theByte << 4;

   // ...and send it

   LcdSendNibble(theByte);

}

 

/* LcdSendInstruction

 *

 * Sends an instruction to the display.

 *

 * Parameters:

 *    uint8_t command    This byte is sent to the display as

 *                    an instruction (RS low).

 * Returns:

 *    nothing

 */

void LcdSendInstruction( uint8_t theInstruction )

{

   // RS low for instructions

   LCD_CTRL_PORT &= ~(1<<LCD_RS);

 

   // Send the instruction

   LcdSendByte(theInstruction);

}

 

/* LcdSendCharacter

 *

 * Sends a character to the display.

 *

 * Parameters:

 *    uint8_t nibble    This byte is sent to the display as

 *                    a character (RS high).

 * Returns:

 *    nothing

 */

void LcdSendCharacter(uint8_t theChar)

{

   // RS high for characters to display

   LCD_CTRL_PORT |= (1<<LCD_RS);

 

   // Send the command

   LcdSendByte(theChar);

}

 

/* LcdInitialize

 *

 * Initialize the display.

 *

 * Parameters:

 *    none

 *

 * Returns:

 *    nothing

 */

void LcdInitialize(void)

{

   // initialize LCD control lines

   LCD_CTRL_PORT &= ~(1<<LCD_RS);    // RS low

   LCD_CTRL_PORT &= ~(1<<LCD_RW);    // R/W low

   LCD_CTRL_PORT &= ~(1<<LCD_E);    // E low

 

   // initialize LCD control lines to output

   LCD_CTRL_DDR |= (1<<LCD_RS);

   LCD_CTRL_DDR |= (1<<LCD_RW);

   LCD_CTRL_DDR |= (1<<LCD_E);

 

   // initialize LCD data port to input

   LCD_DATA_DDR |= 0xF0;      // Data on high four bits of port for now...

 

   // First part of init sequence is 3 x Function Set with

   // stipulated waits. Note that the display is in 8-bit mode

   // initially, but although the four low data lines are not connected

   // this does not matter as the instructions low nibble is zero anyway.

   _delay_ms(15);

   LcdSendNibble( LCD_FUNCTION_SET );

   _delay_ms(5);

   LcdSendNibble( LCD_FUNCTION_SET );

   _delay_us(100);

   LcdSendNibble( LCD_FUNCTION_SET );

 

   // Now, still in 8-bit mode, set the display to 4-bit mode

   LcdSendNibble( LCD_FUNCTION_SET_4BIT );

 

   // We are now in 4-bit mode.

   // Do the rest of the init sequence.

   LcdSendInstruction( LCD_FUNCTION_SET_4BIT );

   _delay_ms(500);

   LcdSendInstruction( LCD_DISPLAY_OFF );

   _delay_ms(500);

   LcdSendInstruction( LCD_DISPLAY_CLEAR );

   _delay_ms(500);

   LcdSendInstruction( LCD_ENTRY_MODE_SET );

   _delay_ms(500);

   LcdSendInstruction( LCD_DISPLAY_ON );

   _delay_ms(500);

}

 

char message[] = "Hello";

 

 

int main(void)

{

   LcdInitialize();

   DDRD = 0xFF;
   PORTD = 0xFF;
   DDRB = 0xFF;


   volatile int i = 0;

   while (message[i] != 0)

    {

       LcdSendCharacter(message[i]);

	  // _delay_ms(100);

        i++;




   }

 

   while(1)
   {

    		PORTB = 0x01;
		_delay_ms(500);
		PORTB = 0x00;
		_delay_ms(500);
    }

   return 0;

}

Now when I switch on the power supply switch, the LCD shows the first cell light up then I see a underscore in the cell scroll all the way to the fifth column in the first row and then I get a blinking cursor on the
fifth column. (I have a 7x2 display)

Looks like it is displaying the 5 characters but I may have to add some more delay?

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

npat_avr:
Johan should really be answering this but he is probably sleeping right now so I'll take a shot at it. Please be warned that although I have some knowledge of the LCD modules I have very little C programming background.

I found a copy of Johan's program and it looks like your circuit is wired just as his program expects.
You should be able to run his program with no changes except for the shorter message.

As far as your program behavior is concerned:
-You don't need to initialize PORTD, that is done along with the LCD initialization.
-You have driven all the pins on PORTD high including the RW pin which was set low in the LCD initialization. This is most likely the cause of your incorrect program behavior.
-Your diagram shows nothing connected to PORTB but your program has some code relating to that port.

Don

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

Quote:

Wouldn't a comment be the best answer?

In this particular case, what would be best:
a) Code that has no redundant information and that is un-ambigous, or
b) Code that has redundancy, is ambigous, but has a comment explaining it.

Sorry, I'm not convinced, and I will not mobe. The Pxn preprocessor symbols might be useful under some circumstances, but in this case it should be

#define LCD_RS_PIN 1
//etc

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"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] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

Quote:

Now when I switch on the power supply switch, the LCD shows the first cell light up then I see a underscore in the cell scroll all the way to the fifth column in the first row and then I get a blinking cursor on the
fifth column. (I have a 7x2 display)

I believe you are very close. Small moves now!

1) What did you do with the four high data pins on the LCD? Tied low, tied high, floating? For my displays it worked by leaving them floating.
2) Your results seems to indicate that the display displays characters, but not the correct ones. Double check the wiring of the data lines. Make sure that you have cleaned up all soldering so that you don't have any solder bridges etc..
3) Contrast control - what did you do with that?

Gotta work - more later..

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"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] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

People learning WinAVR C after mastering AVR assembler often find that it is easier and faster to get an answer to a simple C problem by posing the question as a fact here. If it's actually true the message will be ignored, but if it's false you will be quickly flamed with the correct answer and often a quote or reference in the WinAVR documentation (such as it is) or K&R book backing up the response.

If you just ask the question politely, you get ignored or, flamed and called a lazy retard who won't read the manual or the data sheet. But the problem is laziness or mental slowness,(lazy retards go into marketing, not programming) it's not knowing how to pose the question in such a way to actually be able to find the answer in all the documentation.

Nowhere is this more apparent than in the C error messages. They are all technically correct, but they give no information to the user as to what could be causing the error. Since simple errors are most likely to be made by beginners, they are the ones who need the simple explanations of what's causing the error. But there is none, because the C mindset that developed in the early 1970s when computer resources were extremely expensive greatly discourages it.
Recall the story of the helicopter pilot who got lost in a dense fog over Seattle. He had a passenger make a sign reading "Where am I?". Showing it to one tall building he got an response by sign saying "You're in a helicopter!". He then knew his geographical location was at the Microsoft campus, because he got a technically precise but completely useless answer to his question.

I disagree with the statement 100% that redundancy in code should be eliminated. Except for exact redundancy in tight time-based code, of course. But with the price of computer resources going down so fast and the speed of computer resources increasing so steadily, redundancy in code is inconsequential and redundancy in comments is desirable. We all read much faster than we write. Explaining something many times in a different manner each time is far more likely to convey the information that just having one dense concise explanation.

Using C language (which I am beginning to hate) recalls the ancient Greek myth of Sisyphus, who was condemned to push a huge rock up a mountain and watch it roll back to the bottom endlessly. Thousands of people are introduced to microcontrollers each month, and none of them are born with C knowledge in their brains. Every newcomer is going to asking the same questions over and over year after year.

I think that we should just dump C on the ash heap of history. Every new microprocessor should have its own language that is easy to learn, easy to use, and custom tailored to the individual processor. The bizarre technical details such as whether there is a NULL byte at the end of a string or why the instruction to set a register's bits to all logic one can only be used on half of the register set should be as invisible as microcode.

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

floresta1212 wrote:
npat_avr:

-You have driven all the pins on PORTD high including the RW pin which was set low in the LCD initialization. This is most likely the cause of your incorrect program behavior.
-Your diagram shows nothing connected to PORTB but your program has some code relating to that port.

Don

Thanks, Don.
I will check the R/W pin.
Apologies for not updating my schematic, but I do have a blinking LED connected to PORTB. This is just as an indicator that my AVR has good vitals.

Quote:

1) What did you do with the four high data pins on the LCD? Tied low, tied high, floating? For my displays it worked by leaving them floating.

The four high data pins are floating. I will try connecting them to high or low and see what happens.

Quote:

2) Your results seems to indicate that the display displays characters, but not the correct ones. Double check the wiring of the data lines. Make sure that you have cleaned up all soldering so that you don't have any solder bridges etc..


I have checked but will recheck..

Quote:

3) Contrast control - what did you do with that?

I have tied it to GND. I am getting good contrast.

I think you are right, the characters are being sent but not the right ones.

Are there any delays anywhere else that I should add/remove/modify?

Thanks for your patience for this. Something tells me I am very close and tweaking may be involved.

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

Quote:

I disagree with the statement 100% that redundancy in code should be eliminated. Except for exact redundancy in tight time-based code, of course. But with the price of computer resources going down so fast [...]

If this is a response to my post then you missed my point entirely. I am not figthing redundancy for efficiency in memory or execution time. I am fighting redundancy for reasons of source code quality and maintenance, and I thought that I was clear enough about that with my example. Obviously not.

As of January 15, 2018, Site fix-up work has begun! Now do your part and report any bugs or deficiencies here

No guarantees, but if we don't report problems they won't get much of  a chance to be fixed! Details/discussions at link given just above.

 

"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] "Words represent concepts. Use the wrong words, communicate the wrong concept." [J Morin] "Persistence only goes so far if you set yourself up for failure." [Kartman]

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

npat_avr

Quote:
I will check the R/W pin.
I wouldn't waste my time 'checking' the R/W pin. Just remove the line of code that is incorrectly driving it high, this one:

PORTD = 0xFF; 

and I think your program will work.

Even though your program is not working properly it is doing something. The cursor is visible, so the display is functioning. The cursor advances the same number of times as the number of letters in your message so your 'while' loop seems to be functioning.

Each time around that loop the SendCharacter function is invoked, which among other things pulses the Enable bit to transfer information. Unfortunately, your extra step has changed this data transfer direction to 'read' instead of 'write' so the data corresponding to your message is NOT being sent to the LCD and the default 'space' that is already there is being displayed in its place.

Don

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

Ok I did remove the PORTD statement and it works like magic!! Thanks, Don.

How do I get it to display on the second row? Do I send a "\n" or a "\r" to the LCDsendcharacter function?

Thanks for your help, guys. I was working on this for a long time and can now move on.

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

npat_avr:

Quote:
How do I get it to display on the second row? Do I send a "\n" or a "\r" to the LCDsendcharacter function?

It's not as simple as that, at least not with Johan's code which, is primarily designed to give you an example of code that works.

I recommend that you start by looking at the seven 'defines' at the beginning of his code and compare each of them to the information for corresponding command in the data sheet. Pay attention to the individual bits as expressed by the binary numbers in the comments, not the hex values used by the compiler.

Next go take a look at the information about LCD Addressing at http://web.alfredstate.edu/weimandn and figure out what address you need to start at to display information on the second line of your particular display.

Then look at the instruction 'Set DDRAM Address' in the datasheet and use LcdSendInstruction to implement it.

Don