Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

4 Bit LCD interfacing (AVR).

Status
Not open for further replies.

lord loh.

Member
I have been working for the past few days to interface a 16x2 LCD Module with an ATmega32 without success...

My connections are as

E -> D.7
RS ->C.4
RW ->C.5
DB4->C.0
DB5->C.1
DB6->C.2
DB7->C.3


Here are my files.

Where can I be going wrong?

Please help. Thanks in advance.

lcd.h
Code:
#define LCD_PORT PORTC
#define LCD_BUSY 3
#define LCD_CMD 4
#define LCD_RW 5
#define LCD_LED 6
#define LCD_SEL 7

#define LCDWord(data,cmd,rw) ((data)|(cmd<<LCD_CMD)|(rw<<LCD_RW)|(LCD_PORT&0x40))

#define selectLCD (PORTD &= ~(1 <<7))
#define unSelectLCD (PORTD |= (1<<7))
#define ledOn sbi(LCD_PORT,LCD_LED)
#define ledOff cbi(LCD_PORT,LCD_LED)

void lcd_init(void);
void lcd_writeCommand(unsigned char data);
void lcd_writeData(unsigned char data);
void lcdBusy(void);
void clk(void);

void clk(void)
{
	unSelectLCD;
	_delay_us(5);
	selectLCD;
}

void lcd_init(void)
{
	sbi(DDRD,7);
	DDRC=0xff;			//PORT C -> Output.
	selectLCD;			//clk ->Low
			
	LCD_PORT=LCDWord(0b0011,0,0);	//8bit interface
		
	clk();				//clk = high->low
	_delay_ms(20);
	
	clk();
	_delay_ms(20);

	clk();
	_delay_ms(20);

	LCD_PORT=LCDWord(0b0010,0,0);	//4bit interface
	
	clk();
	_delay_ms(20);

	lcd_writeCommand(0b00101000);	//4 Bit 2 Line
	lcd_writeCommand(0b00001110);	//Display ON Cursor On
	lcd_writeCommand(0b00000110);	//Entry mode
	lcd_writeCommand(0b00000001);	//ClearDisplay
	lcd_writeCommand(0b00000010);	//Return Home
	
	
}

void lcd_writeCommand(unsigned char data)
{
	LCD_PORT=LCDWord(((data&0xF0)>>4),0,0);	//MSB
	clk();
	lcdBusy();
	LCD_PORT=LCDWord((data&0x0F),0,0);	//LSB
	clk();
	lcdBusy();
}

void lcd_writeData(unsigned char data)
{
	LCD_PORT=LCDWord(((data&0xF0)>>4),1,0);	//MSB
	clk();
	lcdBusy();
	LCD_PORT=LCDWord((data&0x0F),1,0);	//LSB
	clk();
	lcdBusy();
}

void lcdBusy(void)
{
	/*cbi(DDRC,LCD_BUSY);		//Make Bit 7 as i/p
	unSelectLCD;			//EN->H
	cbi(LCD_PORT,LCD_CMD);	//Command
	sbi(LCD_PORT,LCD_RW);	//Read
	while(1)
	{
		selectLCD;
		unSelectLCD;
		if bit_is_set(LCD_PORT,LCD_BUSY) break;
	}
	sbi(DDRC,LCD_BUSY);		//Make Bit 7 as o/p
	*/
	_delay_ms(20);
}

stdmacro.h
Code:
#define rotl(var) (((var&0x80)>>7)|(var<<1))
#define sbi(port, bit) (port) |= (1 << (bit))
#define cbi(port, bit) (port) &= ~(1 << (bit))

lcdtest.c
Code:
#include <avr/io.h>
#include <avr/wdt.h>

#define F_CPU 1000000UL
#include <util/delay.h>

#include "stdmacro.h"
#include "lcd.h"


int main()
{
	wdt_disable();
	_delay_ms(5);
	lcd_init();
	ledOn;
	lcd_writeCommand(0x84);
	lcd_writeData(0x45);
	while(1)
	return 0;
}
 
You code is very confusing as you have unSelectLCD enabling the LCD and SelectLCD disabling it!! However, I think you problem is in your LCDBusy routine.

Your lcdBusy needs to do,
Set D7 as input, RW=1 and RS=0.
Make Enable = 1,
Wait for D7=0.
Make Enable=0.

Here is my code for a pic but the sequence is the same,
Code:
//wait for the LCD to finish last command.
void WaitLCDBusy(void){
    LCD_TRIS_BUSY = 1;              //set pin to input
    LCD_RS = 0;                     //Command
    LCD_RW = 1;                     //We want to read
    LCD_E=1;                        //enable LCD interface
    while(LCD_BUSY);                //wait for busy to clear
    LCD_E=0;                        //disable LCD interface
    LCD_TRIS_BUSY = 0;              //restore pin to output
}

HTH,

Mike.
 
my LCD Busy is just a delay of 20 ms. I have avoided it for the time being...
Don't avoid it! I did the exact same thing for a while. Then I finally implemented busy checking and it was easy, and makes your LCD code totally trouble free. Delays are only for when you really can't afford to lose that one MCU pin.

Delays are always a pain. Every time you change MCU or clock speed the LCD won't work without a bunch of fooling around with the delays.

There's some simple AVR LCD code on my site. See **broken link removed** and **broken link removed**.
 
my LCD Busy is just a delay of 20 ms. I have avoided it for the time being...

So you have, my apologies, I missed that.

With your AVR compiler, when you do,
Code:
int main()
{
	wdt_disable();
	_delay_ms(5);
	lcd_init();
	ledOn;
	lcd_writeCommand(0x84);
	lcd_writeData(0x45);
	while(1)
	return 0;
}
Where does the return 0; go to? Maybe you intended to have a semicolon on the while statement. It is probably unrelated to your problem but I thought I would mention it anyway.

Mike.
 
Here I have re written the code.

I still see only one dark line. No character appears. I am expecting one character at the 4th position of the first line 'E'.

I still have not figured out what is wrong.

Code:
#include <avr/io.h>
#include <avr/wdt.h>

#define F_CPU 1000000UL
#include <util/delay.h>

#define LCD_PORT PORTC
#define LCD_BUSY 3
#define LCD_CMD 4
#define LCD_RW 5
#define LCD_LED 6
#define LCD_SEL 7


void lcd_init(void);
void lcd_writeCommand(unsigned char);
void lcd_writeData(unsigned char);

int main()
{
	wdt_disable();
	_delay_ms(5);
	lcd_init();
	lcd_writeCommand(0x84);
	lcd_writeCommand(0x0E);
	lcd_writeData(0x45);
	return 0;
}

void lcd_init(void)
{
	DDRC=0xff;				//Port C is output
	DDRD|=(1<<LCD_SEL);		//Port D.7 is Output
	
	PORTD&=~(1<<LCD_SEL);	//E->Low.

	LCD_PORT&=~(1<<LCD_RW);	//Write
	LCD_PORT&=~(1<<LCD_CMD);//Command
	PORTD|=(1<<LCD_SEL);	//E->High.
	LCD_PORT=(LCD_PORT&0xF0)|0x03;//8 Bit interface.
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);

	PORTD|=(1<<LCD_SEL);	//E->High.
	_delay_ms(20);
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);

	PORTD|=(1<<LCD_SEL);	//E->High.
	_delay_ms(20);
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);

	PORTD|=(1<<LCD_SEL);	//E->High.
	LCD_PORT=(LCD_PORT&0xF0)|0x02;//4 Bit interface.
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);
	
	PORTD|=(1<<LCD_SEL);	//E->High.
	_delay_ms(20);			//4 Bit as 4 bit.
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);
	
	PORTD|=(1<<LCD_SEL);	//E->High.
	LCD_PORT=(LCD_PORT&0xF0)|0x08;//
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);

	lcd_writeCommand(0x08);
	lcd_writeCommand(0x01);
	lcd_writeCommand(0x06);
}

void lcd_writeCommand(unsigned char data)
{
	LCD_PORT&=~(1<<LCD_RW);	//Write
	LCD_PORT&=~(1<<LCD_CMD);//Command

	PORTD|=(1<<LCD_SEL);	//E->High.
	LCD_PORT=((LCD_PORT&0xF0)|((data&0xF0)>>4));
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);
	PORTD|=(1<<LCD_SEL);	//E->High.
	LCD_PORT=((LCD_PORT&0xF0)|(data&0x0F));
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);
}

void lcd_writeData(unsigned char data)
{
	LCD_PORT&=~(1<<LCD_RW);	//Write
	LCD_PORT|=(1<<LCD_CMD);	//ASCII

	PORTD|=(1<<LCD_SEL);	//E->High.
	LCD_PORT=((LCD_PORT&0xF0)|((data&0xF0)>>4));
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);
	PORTD|=(1<<LCD_SEL);	//E->High.
	LCD_PORT=((LCD_PORT&0xF0)|(data&0x0F));
	PORTD&=~(1<<LCD_SEL);	//E->Low.
	_delay_ms(20);
}
 
Here I have re written the code.

I still see only one dark line. No character appears. I am expecting one character at the 4th position of the first line 'E'.

I still have not figured out what is wrong.

... snip...
This may not be helpful, I haven't looked closely at your code, but have you checked the contrast setting? If you are getting one line of dark squares on a two line display, then this could be what is happening.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top