HD4780 control with Mega16

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

I have written the following code following a video tutorial to gain a deeper understanding of lcd control rather than using a common library. For some reason i cant get the lcd to function as anticipated.

#include 
#include 

#define MrLCDsCrib 				PORTB
#define DataDir_MrLCDsCrib 		DDRB
#define MrLCDsControl 			PORTC
#define DataDir_MrLCDsControl   DDRC
#define LightSwitch 			5		//E
#define ReadWrite 				7		//RW
#define BiPolarMood 			2		//RS

void Check_If_MrLCD_isBusy(void);
void Peek_A_Boo(void);
void Send_A_Command(unsigned char command);
void Send_A_Character(unsigned char Character);


int main (void)
{
	DataDir_MrLCDsControl |= 1<<LightSwitch | 1<<ReadWrite | 1<<BiPolarMood;
	_delay_ms(15);
	
	Send_A_Command(0x01);		//Clears screen 0x01 = 0000 0001
	_delay_ms(2);	
	Send_A_Command(0x38);
	_delay_us(50);
	Send_A_Command(0b00001110);
	_delay_us(50);
	
	
	Send_A_Character(0x44); 	//D
	Send_A_Character(0x61); 	//a
	Send_A_Character(0x6e); 	//n
	Send_A_Character(0x69); 	//i
	Send_A_Character(0x65); 	//e
	Send_A_Character(0x6c); 	//l
	Send_A_Character(0x20); 	//space
	Send_A_Character(0x47); 	//G
	Send_A_Character(0x61); 	//a
	Send_A_Character(0x72); 	//r
	Send_A_Character(0x64); 	//d
	Send_A_Character(0x6e); 	//n
	Send_A_Character(0x65); 	//e
	Send_A_Character(0x72); 	//r
	while(1)
	{
	}
}	



void Peek_A_Boo(void)
{
	MrLCDsControl |= 1<<LightSwitch;
	asm volatile ("nop");
	asm volatile ("nop");
	MrLCDsControl &= ~1<<LightSwitch;
}

void Send_A_Command(unsigned char command)
{
	Check_If_MrLCD_isBusy();
	MrLCDsCrib = command;
	MrLCDsControl &= ~ (1<<ReadWrite|1<<BiPolarMood);
	Peek_A_Boo();
	MrLCDsCrib = 0;
}

void Send_A_Character(unsigned char Character)
{
	Check_If_MrLCD_isBusy();
	MrLCDsCrib = Character;
	MrLCDsControl &= ~ (1<<ReadWrite);
	MrLCDsControl |= 1<<BiPolarMood;
	Peek_A_Boo();
	MrLCDsCrib = 0;
}

void Check_If_MrLCD_isBusy()
{
	DataDir_MrLCDsCrib = 0;
	MrLCDsControl |= 1<<ReadWrite;
	MrLCDsControl &= ~1<<BiPolarMood;
	
	while(MrLCDsCrib >= 0x80)		//0b1000 0000 = 0x80 any hex number higher than 0x80 will have a 1 in the 8th digit 0b'1'0000000
	{
		Peek_A_Boo();
	}
	
	DataDir_MrLCDsCrib = 0xFF;		//0xFF means 0b11111111
	
}

The mega is in stk500 and connected to the lcd in the following fashion.

(RS B2) (RW B7) (E B5)
(Data bit 0 connected to C0 - Data bit 7 to C7)

Can anyone tell me if it is the code or possibly the wiring?

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

I’m just suggesting, but did you disable JTAG? Because some pins on port c can’t be used as i/o pins if its enabled. (see atmega16 datasheet)

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

Ah so this is going to be one of these threads then?:

https://www.avrfreaks.net/index.p...

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

clawson wrote:
Ah so this is going to be one of these threads then?:

https://www.avrfreaks.net/index.p...

I hope not :roll:

MainBrain wrote:
I’m just suggesting, but did you disable JTAG? Because some pins on port c can’t be used as i/o pins if its enabled. (see atmega16 datasheet)

I tried it on port D also, did not work.

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

I confess. I never really get the hang of operator precedence. i.e. I understand the concept. I just don't keep the C rules in my head.

58:          MrLCDsControl &= ~1<<LightSwitch;
+0000004D:   B188        IN        R24,0x08       In from I/O location
+0000004E:   7C80        ANDI      R24,0xC0       Logical AND with immediate
+0000004F:   B988        OUT       0x08,R24       Out to I/O location

I always get upset when I see bit-masks without parentheses. And sure enough, I bet the OP did not intend this consequence.

I echo Cliff's comment about "here we go again".

A second confession. I have written my own I2C, LCD, EEPROM routines.

However, when they don't work first time, I compare my effort with proven code.
Even then, I can't always spot my mistakes.

Quote:

I have written the following code following a video tutorial to gain a deeper understanding of lcd control rather than using a common library.

Before you try writing low level code, how about learning how to write a Send_A_String() function?

David.

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

Quote:
For some reason i cant get the lcd to function as anticipated.
Sometimes if you describe exactly what it does do that description can provide some hints.

Oh look - my crystal ball just started working. It says that you are seeing a single row of boxes on your display.

Have you considered following the initialization routines (Initializing by Instruction) recommended in the data sheet?

Did you see the note that says the 'Function set' instruction must be executed first?

Do you know which of the magic numbers in your program is actually the 'Function set' instruction? No cheating, you have to answer this without looking at the data sheet.

Don

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

Actually, I don't think he is far wrong in his 8-bit LCD code.

I don't understand the reasoning behind the silly names for his variables and functions. Perhaps the thread is just a wind-up.

David.

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

The controller wakes up thinking he is hooked to an 8 bit lcd, and you need to bonk it in the head several times with the 'you are in 4 bit mode, mule!' command to get its attention.

Imagecraft compiler user

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

Bob, it wakes up in 8-bit mode.
The OP is using it in 8-bit mode.

With a minor adjustment, it will work perfectly.

It does seem an awful waste of 11 GPIO lines though.

David.

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

Quote:
The controller wakes up thinking he is hooked to an 8 bit lcd, and you need to bonk it in the head several times with the 'you are in 4 bit mode, mule!' command to get its attention.
Actually, this is untrue, switching from 8 bit to 4 bit you simply send the command once. It is when you don't know what mode the controller is in (or if it is in an unstable state) that you need to send the command multiple times.

Regards,
Steve A.

The Board helps those that help themselves.

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

Yo Dave... have you spotted the necessary minor adjustment? Lets have a contest to see if the other old guys can spot it too?

Imagecraft compiler user

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

Quote:
... see if the other old guys can spot it too?

LCD beginners really shouldn't attempt to read the busy flag although this particular problem is not limited to LCDs.

Don

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

Quote:

LCD beginners really shouldn't attempt to read the busy flag

??? Thus, by extension anytime I interface my AVR to a new peripheral chip I must limit myself to one-way communications, even if:
-- the chip is useless without two-way communications; and/or
-- the chip defaults are not what is needed/desired ?

Gee, however did I start with AVRs 10years ago, when I went about it all wrong. :(

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

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

IMHO, reading peripheral status bit-flags is one of the really important things that new programmers need to learn.

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

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

Quote:
??? Thus, by extension anytime I interface my AVR to a new peripheral chip I must limit myself to one-way communications...
I didn't say that and I didn't imply that. My comment was a specific reply to the post that I quoted. It was worded that way so that Bob could tell that I indeed had spotted the problem which he had already identified - without spilling the beans.

Quote:
IMHO, reading peripheral status bit-flags is one of the really important things that new programmers need to learn.
True, but it would be easier to break the current problem into two parts. First get the LCD working without dealing with status flags and then get the reading of the status flags working. This thread is a perfect example.

Don

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

david.prentice wrote:

I don't understand the reasoning behind the silly names for his variables and functions. Perhaps the thread is just a wind-up.
David.

Well the way that it was explained in the tutorial was very helpful so i decided to leave it how it was to get it working then change it once i started fiddling with it.

floresta1212 wrote:

Oh look - my crystal ball just started working. It says that you are seeing a single row of boxes on your display.

You should buy a lotto ticket because that crystal ball is good!

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

Quote:

Well the way that it was explained in the tutorial was very helpful so i decided to leave it how it was to get it working then change it once i started fiddling with it.

So the tutorial used the "silly names".

Was the tutorial responsible for:

MrLCDsControl &= ~1<<LightSwitch; 

instead of using:

MrLCDsControl &= ~(1<<LightSwitch);

I have a sneaking suspicion that it will actually work if you relent with your parenthesis aversion.

I have no intention of wiring up an 8-bit LCD to run your code. (I can easily use 4-bit LCD)

I still reckon that you should use proven code.
Once you have confirmed that round wheels work, you can put serious effort into developing the square variety.

In the learning process, you will begin to understand the technicalities of wheel design. (and the pros of cons of silly names)

David.

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

I'm going to take everyone's advice and just use the 4bit program I was using and break it down. None the less thank you for all of the comments in this thread. I really didn't intend to be another one of those hopeless cases that reposts things that have already been discussed a trillion times. :wink:

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

Quote:
I'm going to take everyone's advice and just use the 4bit program I was using and break it down.
My advice is to fix the program that you are currently working on.

The first thing I would do is rework the comments in your existing code. You should be able to figure out what is being done in a routine without referring to the defines. Who could ever guess that this code is pulsing the Enable bit in order to initiate a transfer of data?

void Peek_A_Boo(void)
{
   MrLCDsControl |= 1<<LightSwitch;
   asm volatile ("nop");
   asm volatile ("nop");
   MrLCDsControl &= ~1<<LightSwitch;
} 

I recommend that you initially stick with the 8-bit interface but use time delays instead of using the busy flag. This is the most straightforward implementation and it makes it easier to concentrate on getting the initialization sequence working.

Concentrate on following the flow chart for 'Initialization by Instruction' (figure 23). There are other techniques that sometimes work but this one seems to always work. You can find an explanation by following the LCD Addressing link at http://web.alfredstate.edu/weimandn. There are some simplified timing diagrams elsewhere in this forum that should be helpful as well.

After you get the 8-bit interface working you can then work on using the 4-bit interface and/or the busy flag. I think starting with the 4-bit interface would be the best choice.

Don

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

Can you tell us the clock speed in the example and the clock speed in your project? If the example was using the internal 1MHz RC oscillator, and you project is using a 16MHz external xtal, the carefully crafted delay loops will be wrong by a factor of 16. This might have an effect on whether it is really strobing bytes into the controller.

Imagecraft compiler user

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

First of all, get your LCD going with proven library code.

I would agree with Don. Purely from an academic interest, fixing your code is worth doing.

MrLCDsControl &= ~1<<LightSwitch; 0
MrLCDsControl &= 0xFFFE << 5; 
MrLCDsControl &= 0xFFC0; 

In fact this particular statement will clear bit#5. So I chose a bad example. The LCD will not care too much that bits#0..4 get cleared as a side-effect.

Likewise this 'works' too.

   MrLCDsControl &= ~1<<BiPolarMood;
   MrLCDsControl &= 0xFFFE << 2;
   MrLCDsControl &= 0xFFF8;

My apologies. Your code will probably do what you intended, but by fluke rather than design.

LCDs start up in 8-bit mode. So you can almost get away with no initialisation. However, if you follow the data sheet exactly, you can ensure the correct operation.

I suspect you are going to have serious problems with any hardware connected to PORTC.#0,1,3,4.

David.

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

Quote:
the carefully crafted delay loops will be wrong by a factor of 16.
But the OP is using _delay_ms and _delay_us which automatically compensate for clock speed (assuming, of course, that the compiler is told the actual clock speed).

The one problem might be with the enable toggle which is hard coded to (likely) 4 cycles, which could be too short in the higher cpu frequencies.

Regards,
Steve A.

The Board helps those that help themselves.