Mega1284 to 4x20LCD

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

So I am trying to interface 4x20 LCD with KS0066 driver with ATmega1284p. I have read the datasheet and tried to code for initialization, blinking cursor and a simple character display on the first position of the LCD. I am not able to find any readymade code for such display, and as per the datasheet, HD44780 and KS0066 are having different init sequences. I am posting my hardware connection and code below. Please let me know if there is anything wrong with it. All I am able to get is a hint of LCD getting initialized (as the original poster said - the LCD is having 4 light lines from 2 dark and 2 light line setting). Nothing beyond that.

 

Also, please check out the attached datasheet of KS0066 driver for information. I've tried the init sequence of HD44780 too but result is the same.

 

H/W Connection:

RS pin connected to PA2

R/W pin connected to GND

EN pin connected to PA3

DB4 - PA4

DB5 - PA5

DB6 - PA6

DB7 - PA7

 

Crystal of 11.0592MHz

 

Code:


#include <avr/io.h>
#define F_CPU 11059200UL
#include <util/delay.h>

#define ms(ms_time)        _delay_ms(ms_time)
#define us(us_time)        _delay_us(us_time)

uint16_t ms_time,us_time;



// LCD Definitions



#define LCD_DDR        DDRA
#define LCD_PORT    PORTA
#define LCD_RS        PA2
#define LCD_EN        PA3
#define LCD_Data_Mask    0xF0
#define EN_SET        (LCD_PORT |= (1 << LCD_EN))
#define EN_CLEAR    (LCD_PORT &= ~(1 << LCD_EN))
#define RS_SET        (LCD_PORT |= (1 << LCD_RS))
#define RS_CLEAR    (LCD_PORT &= ~(1 << LCD_RS))



void LCD_Init(void);
void LCD_Init(void)
{
    LCD_DDR |= ((1 << LCD_RS) | (1 << LCD_EN));
    LCD_DDR |= LCD_Data_Mask;
    RS_CLEAR;
    EN_CLEAR;
    
/*    LCD_PORT |= (LCD_Data_Mask & 0x30);   // Sequence of HD44780
    LCD_PORT |= (1 << LCD_EN);
    us(2);
    LCD_PORT &= ~(1 << LCD_EN);
    ms(10);
    
    LCD_PORT |= (LCD_Data_Mask & 0x30);
    LCD_PORT |= (1 << LCD_EN);
    us(2);
    LCD_PORT &= ~(1 << LCD_EN);
    ms(1);
    
    LCD_PORT |= (LCD_Data_Mask & 0x30);
    LCD_PORT |= (1 << LCD_EN);
    us(2);
    LCD_PORT &= ~(1 << LCD_EN);
    us(100);*/
    

// Please go through the pg.29 of attached PDF for the init sequence

    LCD_PORT |= (LCD_Data_Mask & 0x20);
    EN_SET;
    us(2);
    EN_CLEAR;
    ms(1);
    
    LCD_PORT |= (LCD_Data_Mask & 0x20);
    EN_SET;
    us(2);
    EN_CLEAR;
    us(2);
    LCD_PORT |= (LCD_Data_Mask & 0x80);
    EN_SET;
    us(2);
    EN_CLEAR;
    ms(1);
    
    LCD_PORT |= (LCD_Data_Mask & 0x00);
    EN_SET;
    us(2);
    EN_CLEAR;
    us(2);
    LCD_PORT |= (LCD_Data_Mask & 0xF0);
    EN_SET;
    us(2);
    EN_CLEAR;
    ms(1);
    
    LCD_PORT |= (LCD_Data_Mask & 0x00);
    EN_SET;
    us(2);
    EN_CLEAR;
    us(2);
    LCD_PORT |= (LCD_Data_Mask & 0x10);
    EN_SET;
    us(2);
    EN_CLEAR;
    ms(10);
    
    LCD_PORT |= (LCD_Data_Mask & 0x00);
    EN_SET;
    us(2);
    EN_CLEAR;
    us(2);
    LCD_PORT |= (LCD_Data_Mask & 0x60);
    EN_SET;
    us(2);
    EN_CLEAR;
    ms(1);
    
    LCD_PORT |= (LCD_Data_Mask & 0x80);    // Setting DDRAM address
    EN_SET;
    us(2);
    EN_CLEAR;
    us(2);
    LCD_PORT |= (LCD_Data_Mask & 0x00);
    EN_SET;
    us(2);
    EN_CLEAR;
    ms(1);
    
    RS_SET;        // Trying to print 'H'
    LCD_PORT |= (LCD_Data_Mask & 0x40);
    EN_SET;
    us(2);
    EN_CLEAR;
    us(2);
    LCD_PORT |= (LCD_Data_Mask & 0x80);
    EN_SET;
    us(2);
    EN_CLEAR;
    ms(1);
}



int main(void)
{
    ms(2000);   // delay inserted to clearly observe the change from 2 dark 2 light lines on LCD to all light lines
    LCD_Init();
    while (1);
}

 

 

Any help is highly appreciated. Thank you.

Attachment(s): 

This topic has a solution.

Last Edited: Sat. Feb 3, 2018 - 01:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 2

This is what appears to be a standard Hitachi 4x20 LCD to which there are THOUSANDS of solutions on a Google Search and hundreds in a search of this site.

 

I'll save you, and the others here....PETER FLEURY's LCD library

 

http://homepage.hispeed.ch/peter...

 

It's called:

LCD library for HD44780 based LCD's

 

Everything you need is in there

 

JIm

If you want a career with a known path - become an undertaker. Dead people don't sue! - Kartman

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

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

Have you checked your wiring?

Is your contrast potmeter OK?

 

"Use Peter Fleury" has been the standard answer for 15 years around here.

There's probably a good reason for that. (But I prefer my own code :).

 

If you want to find some code (for another project), then try github first.

For example github finds 6 for the ks0066 and 4 of them seem to be source code libraries in C / C++.

https://github.com/search?utf8=%...

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

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

Your code only sets bits in portb by doing |=
So your code is not working as you expect.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you very much to Jim and Paul for useful links.

Libraries are great but I prefer not to use them, because I find it hard to read and understand every single line of most libraries and it vexes me a lot, when I am using something that I am unable to understand fully. I went through both links and tried to grasp as much as I can. But the problem was in my PORTA settings, as Kartman pointed out. Thanks a lot for that! I fixed it, along with some cleanup and minor changes and the code worked flawlessly. For reference of anyone interested, I am posting the code below. Also, it is generally said that HD44780 and KS0066 are identical, and that a code working for HD44780 will work for KS0066 - but is hugely flawed. At least that's what I came to know. I went through the datasheets of both controllers and they are having different init sequences. So althought there are number of libraries designed and working for HD44780, it is just not guaranteed to work for KS0066.

 

Code:

 

#include <avr/io.h>
#define F_CPU 11059200UL
#include <util/delay.h>
#define ms(ms_time)        _delay_ms(ms_time)
#define us(us_time)        _delay_us(us_time)

uint16_t ms_time,us_time;

// LCD Definitions

#define LCD_DDR        DDRA
#define LCD_PORT    PORTA
#define LCD_RS        PA2
#define LCD_EN        PA3
#define LCD_Data    0xF0
#define LCD_Mask    0x0F
#define EN_SET        (LCD_PORT |= (1 << LCD_EN))
#define EN_CLEAR    (LCD_PORT &= ~(1 << LCD_EN))
#define RS_SET        (LCD_PORT |= (1 << LCD_RS))
#define RS_CLEAR    (LCD_PORT &= ~(1 << LCD_RS))

void LCD_Send(uint8_t send, uint8_t flag)
{
    if(flag)
    {
        RS_SET;
    }
    else
    {
        RS_CLEAR;
    }
    LCD_PORT &= LCD_Mask;
    LCD_PORT |= (send & 0xF0);
    EN_SET;
    us(1);
    EN_CLEAR;
    LCD_PORT &= LCD_Mask;
    LCD_PORT |= ((send & 0x0F) << 4);
    EN_SET;
    us(1);
    EN_CLEAR;
    us(100);
}

void LCD_Clear(void)
{
    LCD_Send(0x01,0x00);
    ms(5);
}

void LCD_GotoXY(uint8_t x, uint8_t y)
{
    uint8_t LCD_Column_Start[4] = {0x80,0xC0,0x94,0xD4};
    LCD_Send(((LCD_Column_Start[x-1]) + (y-1)),0x00);
}

void LCD_Print(const char *str)
{
    uint8_t LCD_String_Cnt = 0;
    while(str[LCD_String_Cnt] != 0x00)
    {
        LCD_Send(str[LCD_String_Cnt++],0x01);
    }
}

void LCD_Init(void)
{
    LCD_DDR |= ((1 << LCD_RS) | (1 << LCD_EN));
    LCD_DDR |= LCD_Data;
    RS_CLEAR;
    EN_CLEAR;
    ms(100);
    LCD_PORT &= LCD_Mask;
    LCD_PORT |= 0x20;
    EN_SET;
    us(1);
    EN_CLEAR;

    LCD_Send(0x2C,0x00);    // Function Set
    LCD_Send(0x0C,0x00);    // Display ON, Cursor and Blink OFF
    LCD_Clear();
    LCD_Send(0x06,0x00);    // Entry Mode Set
}

int main(void)
{
    ms(1000);
    LCD_Init();
    LCD_GotoXY(1,1);
    LCD_Print("AB");
    LCD_GotoXY(2,1);
    LCD_Print("CD");
    LCD_GotoXY(3,1);
    LCD_Print("EF");
    LCD_GotoXY(4,1);
    LCD_Print("GH");
    while (1);
}

 

 

 

 

 

 

 

 

Last Edited: Sat. Feb 3, 2018 - 01:35 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Code i wrote 30 years ago works on a ks0066. A lot of people cut corners and their code ‘works’ sort of. Follow the datasheet especially with things like startup time, cmd execution time, setup and hold times and your code will be robust.

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

Poorn Mehta wrote:
For reference of anyone interested, I am posting the code

Could you fix the post so that the code is using code tags (as in your first post here)?

 

Also, there is no need to have a function prototype just before every function definition. Those prototypes serves no purpose and only confuses things. I suggest you remove them.

 

 

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: 2

About LCD...

"Timing" has been mentioned in this thread. If you read the datasheet you'll see that all delays specified in the datasheet assume a certain clock frequency of the HD.. / KS.. . With most displays you won't know if the display runs at that frequency. Some might run deliberately slower to save a bit of current. Others might run faster to be able to speed up data transfer. And it's a not so accurate RC oscillator.

 

Reading (library) code written by others can be very educational.

Some people write horrible code.

Some people write beautiful code.

Most are pretty sloppy, but "readable".

 

It is also ... to boldly say you don't want to use libraries.

You do use <util/delay.h> which has some pretty ... strange macro's to define a simple delay constant.

Quite well written, but it takes some time to appreciate the effort which it took to write such code.

 

The Bresenham Line algorithm is also a very good example of code you will not easily write your own.

It was invented somewhere in the '60s.

Linked lists, circular buffers. Quite finicky to get the pointers just right and it has been done already probably millions of times.

If you want to do something with stepper motors, the "David Austin" article (with code) is highly recommended.

 

And all the C standard libraries....

 

I can also understand you're easily vexed by library code.

A part is because of the different code styles people use.

After some time you get used to it that braces and such are not always where you expect them.

And you always have the option to push the code through a "code beautifier" such as indent or astyle before you look at it.

Paul van der Hoeven.
Bunch of old projects with AVR's:
http://www.hoevendesign.com

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

Thanks a lot for editing suggestions to Johan. I have edited that post. Let me know if there is anything more, needed to be done.

 

Thanks for the suggestion to Paul. You're right, I should not stick to 'no use of library'. It is pointless and I'm not implying it 100% anyway. I will keep on reading libraries with patience, because as you said - there's a lot to learn from them.

 

To everyone, thank you very much for giving your invaluable time for helping me out. Much appreciated!