Translate

Wednesday, 6 January 2016

Driving Character LCD using Atmega in 8-bit mode

                 So, ever wanted to make a simple message display. well here it is. this article will walk you through the simple steps of getting the LCD working. Before proceeding you must know how to use the ports on the MCU. A lot of tutorials are available online so I decided to jump to the fun stuff.

The image below is a simple message display


It consists of a

  • Charecter LCD
  • MCU (atmega 16)
  • 10k pullup resistor for reset
  • 10k variable resistor for contrast adjustment

here is the circuit diagram

NOTE: I have not used a reset button or an external crystal (x1) on the prototype board. you may use it if you wish as the next tutorials will require it


16X4


The 16 X 4 LCD has 16 columns and 4 rows. The LCD displays two screens with a delay of 2000 milli seconds or two seconds


16X2


The 16 X 2 LCD has 16 columns and 2 rows. The LCD displays two screens with a delay of 2000 milli seconds or two seconds. Note that the same code is used for both LCDs the 16 X 2 ignores line 3 and 4. well technically it is in the memory and can be forced to display but that's beyond the scope of this article.

The LCD has 16 pins the table below tabulates them


Pin number
Pin name
Discription
1
Gnd
Common ground
2
Vcc
5.5V max (check datasheet)
3
VE
Voltage for contrast adjustment use 10k pot
4
RS
Register select; Low for control; High for data
5
RW
Read or write; High for read; Low for write
6
EN
Enable pulse triggers on falling edge (high to low)
7 - 14
D0 - D7
8 bit data bus; 
15
+ LED
LED positive 5V max
16
- LED
Connect to common ground

 So to get the LCD started follow these steps
  • Ensure that  the vcc is powered to +5v and all ground pins are connected together for both the controller and the LCD. 

  •  before programming the chip. power on the circuite and adjust the contrast till you see black squares on the first line of the LCD

  • Now program the chip

  • The LCD will display as shown in the figures above

Possible problems you may encounter

If the LCD is not displaying anything even the black squares before flashing the chip.

  • Check the contrast.
  • Check the voltage and ground connections  

If the LCD is not initialising (i.e black squares not disappering)

  • Check data lines and control lines for shorts.
  • Ensure that the DDR (data direction register) for the data lines and control lines are set as output
  • Ensure that the F_CPU matches the clock speed of the chip. new chips have a frequency of 1 MHZ so F_CPU must be '1000000UL'. this is the value in hertz. for different frequencies change accordingly.
  • Atmega 16 and 32 have the JTAG unit enabled hence portc cannot function as a normal IO port ensure that the line MCUCSR|=(1<<JTD); is typed twice.

If the LCD displays random/junk characters

  • One or more data lines may not be soldered properly
  • Ensure that the F_CPU matches the clock speed of the chip. new chips have a frequency of 1 MHZ so F_CPU must be '1000000UL'. this is the value in hertz. for different frequencies change accordingly.

        So here it is the code to drive the LCD. this code was written in atmel studio.

  • just create a new executable project (c/c++). 
  • Select you device
  • past the code (starting from /*).
  • build the code by pressing F7
  • wait for the build to complete then use a flashing tool (burner as it is regularly called). to flash the program to the chip. 

        That's it, your done. Alter the lines to match your display needs. experiment with the code and find out how to make it work your way. I really recommend learning the theory behind the LCD's operation as it will help you a lot..... especially writing a code from scratch and debugging.

--------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------

/*
* LCD DEMO.cpp
* Created: 29-12-2015 13:16:17
* Author: Hemanth
*/
//////////////////////////////////////////Define CPU Frequency///////////////////////////////////////////////////

#ifndef F_CPU
#define F_CPU 1000000UL // CPU frequency
#endif

////////////////////////////////////////////Value definitions/////////////////////////////////////////////////

#define LCD_DATA PORTC // data port for LCD
#define control PORTB // port for command
#define rs PB2 // Register select pin
#define rw PB1 // Read or write pin
#define en PB0 // Enable pin

////////////////////////////////////////Header files/////////////////////////////////////////////////////

#include <avr/io.h> //header file for DDR and PORT function
#include <util/delay.h> //header file for _dela_ms() function

/////////////////////////////////////////Function prototypes////////////////////////////////////////////////////

void LCD_cmd(unsigned char cmd);
void init_LCD(void);
void LCD_write(unsigned char data);
void stringwrite(const char *q);
void moveto(int line,int pos);
void clearLCD();

/////////////////////////////////////Functions////////////////////////////////////////////////////////

void clearLCD()
{
LCD_cmd(0x01);
}

void init_LCD(void)
{
LCD_cmd(0x38);// initialization of 16X2 LCD in 8bit mode
_delay_ms(10);
LCD_cmd(0x01); // clear LCD
_delay_ms(10);
LCD_cmd(0x0C); // cursor ON
_delay_ms(10);
LCD_cmd(0x80);//8 go to first line and 0 is for 0th position
}

void LCD_cmd(unsigned char cmd)
{
LCD_DATA=cmd;
control |=(1<<en); // RS and RW as LOW and EN as HIGH
control &=~(1<<rs);
control &=~(1<<rw);
_delay_ms(10);
control &=~(1<<rs);
control &=~(1<<rw);
control &=~(1<<en); // RS, RW , LOW and EN as LOW

}

void LCD_write(unsigned char data)
{
LCD_DATA= data;
control |= (1<<rs)|(1<<en); // RW as LOW and RS, EN as HIGH
control &=~(1<<rw);
_delay_ms(10);
control |= (1<<rs); // EN and RW as LOW and RS HIGH
control &=~(1<<rw);
control &=~(1<<en);
// delay to get things executed
}

void stringwrite(const char *S)
{
while (*S) {
LCD_write(*S++);
}}

void moveto(int line,int pos)
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//The following block is for 16X4 LCD for 16X2 line 1 is 1st line and line 2 is second line
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if(line==1)
LCD_cmd(0x80+pos);//1st line 0th position
if(line==2)
LCD_cmd(0xC0+pos);//2nd line 0th position
if(line==3)
LCD_cmd(0x90+pos);//3rd line 0th position
if(line==4)
LCD_cmd(0xD0+pos);//4th line 0th position
}

/////////////////////////////////////////Main function//////////////////////////////////////////////////

int main(void)
{
MCUCSR|=(1<<JTD);//Disable JTAG
MCUCSR|=(1<<JTD);//Have to send it twice
DDRB=0xFF;// Set all pin of portB to act as output pins
DDRC=0xFF;// Set all pin of portC to act as output pins
DDRD=0xFF;// Set all pin of portD to act as output pins
PORTD|=(1<<PD7);//// Set pin PD7 to logic high.... this is used to turn on the LCD light

init_LCD(); // initializing LCD...... must be called else it will not accept any commands

while(1)
{
moveto(1,0);// 1st line 0th position
stringwrite("Simple 16X4 LCD");
moveto(2,0);
stringwrite("Interfacing in 8");
moveto(3,0);
stringwrite("bitmode~Atmega16");
moveto(4,0);
stringwrite("Hemanth Praveen");
_delay_ms(2000);// wait 2 seconds
clearLCD();// clears the LCD memory
moveto(1,0);
stringwrite("8bit DATA ~PORTC");
moveto(2,0);
stringwrite("Command ~PORTB");
moveto(3,0);
stringwrite("RS~PB2 R/W~PB1");
moveto(4,0);
stringwrite("En~PB0 CLK~1MHz");
_delay_ms(2000);
clearLCD();
}}

--------------------------------------------------------------------------------------------------

ok guys that's it for now do comment if you experience any problems with the code.

No comments:

Post a Comment