[Icc-avr] 4-line LCD display
John Baraclough
j_baraclough at zetnet.co.uk
Tue Jan 29 09:16:22 PST 2008
Hi Albert,
What processor clock frequency are you using? I have found that a small
delay is required between the rising and falling edges of the E clock on
the HD44780. Also you have only written the setup byte to the device
once and I have also found that it requires two writes to be sure of
setting the correct operating mode.
I have attached a couple of files that I have used for several years
without a problem. If you don't see the files let me know and I'll email
them direct to you.
All the best for now,
John
Albert vanVeen wrote:
> Thanks, especially for hw suggestions; we're looking at it.
> Meanwhile here is my init code for your perusal.
>
>
>
<CODE SNIPPED>
-------------- next part --------------
/* ************************************************************ *\
file: Lcd.h
Purpose: Contains the definitions for the LCD.
Revisions
1.0 JNB 2005-11-16 Original Code
\* ************************************************************ */
#define LCD_PORT PORTC
#define LCD_RS BIT(2)
#define LCD_E BIT(3)
#define SET_E gucLcdControl|=LCD_E;LCD_PORT=gucLcdControl;delay(1)
#define CLEAR_E gucLcdControl&=~LCD_E;LCD_PORT=gucLcdControl
#define SET_RS gucLcdControl|=LCD_RS;LCD_PORT=gucLcdControl
#define CLEAR_RS gucLcdControl&=~LCD_RS;LCD_PORT=gucLcdControl
#define TEST_NEW_CENTS_FLAG ucFlags&BIT(0)
#define SET_NEW_CENTS_FLAG ucFlags|=BIT(0)
#define CLEAR_NEW_CENTS_FLAG ucFlags&=~BIT(0)
#define TEST_NEW_SECOND_FLAG ucFlags&BIT(1)
#define SET_NEW_SECOND_FLAG ucFlags|=BIT(1)
#define CLEAR_NEW_SECOND_FLAG ucFlags&=~BIT(1)
#define TEST_NEW_MINUTE_FLAG ucFlags&BIT(2)
#define SET_NEW_MINUTE_FLAG ucFlags|=BIT(2)
#define CLEAR_NEW_MINUTE_FLAG ucFlags&=~BIT(2)
#define TEST_NEW_HOUR_FLAG ucFlags&BIT(3)
#define SET_NEW_HOUR_FLAG ucFlags|=BIT(3)
#define CLEAR_NEW_HOUR_FLAG ucFlags&=~BIT(3)
#define LCD_MODE 0x28
#define LCD_OFF 0x08
#define LCD_INC 0x06
#define LCD_ON 0x0c
#define LCD_CLEAR 0x01
#define LCD_HOME 0x02
#define LCD_SET_CGRAM_ADDR 0x40
#ifdef MAIN
const unsigned char CharacterMap[64] =
{
0x06, 0x09, 0x09, 0x06, 0x00, 0x00, 0x00, 0x00, // Degree
0x00, 0x02, 0x06, 0x0e, 0x06, 0x02, 0x00, 0x00, // Left solid arrow
0x00, 0x08, 0x0c, 0x0e, 0x0c, 0x08, 0x00, 0x00, // Right solid arrow
0x00, 0x00, 0x04, 0x0e, 0x1f, 0x00, 0x00, 0x00, // Up solid arrow
0x00, 0x00, 0x1f, 0x0e, 0x04, 0x00, 0x00, 0x00, // Down solid arrow
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
} ;
#else
extern const unsigned char CharacterMap[];
#endif
#define DEGREE 0x08
#define LEFT_ARROW 0x09
#define RIGHT_ARROW 0x0a
#define UP_ARROW 0x0b
#define DOWN_ARROW 0x0c
-------------- next part --------------
/* ************************************************************ *\
File: Lcd.c
Purpose: Contains the code for the LCD. The delay() function
is clock dependent and is characterised for a
14.7456MHz crystal.
Revisions
1.0 JNB 2005-11-16 Original Code
Notes:
\* ****************************************************************** */
#include <includes.h>
/* ************************************************************************ *\
FUNCTION: void delay(int ticks);
Software delay function. This function was compiled in a test project and
the delay in clocks measured in AVRStudio. The resulting data was
transferred to M$oft Excel and a 'best fit' curve obtained. The resulting
equation is:
nClocks = 6*(ticks^2) + 12*ticks + 53
The delays required for the HD44780 LCD controller are as follows:
During initialisation - 15ms, 4.1ms & 100us
After screen clear/cursor home - 1.52ms
Character data entry - 37us
E clock pulse width - 1us
At 14.7456MHz where clock period is 67.82ns
Delay Ticks Actual
1us 1 4.8us
37us 9 43.9us
100us 15 107.4us
1520us 60 1517.3us
4100us 100 4154.2us
15000us 191 15003.9us
INPUTS: ticks.
OUTPUT: NONE.
FUNCTIONS USED: NONE.
\* ************************************************************************ */
#define MICRO_SEC_1 1
#define MICRO_SEC_37 9
#define MICRO_SEC_100 15
#define MICRO_SEC_1520 65
#define MICRO_SEC_4100 100
#define MICRO_SEC_15000 191
void delay(int ticks)
{
unsigned int x, y;
for(x = ticks; x > 0; x--)
{
for(y = ticks; y > 0; y--)
{
// There's no need to do anything here.
}
}
}
/* ************************************************************************ *\
FUNCTION: void WriteLcdData(unsigned char data);
Writes 'data' to the data register of the HD44780.
INPUTS: data.
OUTPUT: NONE.
FUNCTIONS USED: delay().
\* ************************************************************************ */
void WriteLcdData(unsigned char ucData)
{
// Get high nibble of data and set RS bit.
gucLcdControl = ucData & 0xf0;
SET_RS;
delay(MICRO_SEC_1); // Delay of 1uSec.
SET_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
CLEAR_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
// Get high nibble of data and set RS bit.
gucLcdControl = (ucData << 4) & 0xf0;
SET_RS;
delay(MICRO_SEC_1); // Delay of 1uSec.
SET_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
CLEAR_E;
delay(MICRO_SEC_37); // Delay of 40uSecs.
}
void WriteLcdCommand(unsigned char ucCommand)
{
// Get high nibble of data and clear RS bit.
gucLcdControl = ucCommand & 0xf0;
CLEAR_RS;
delay(MICRO_SEC_1); // Delay of 1uSec.
SET_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
CLEAR_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
// Get high nibble of data and set RS bit.
gucLcdControl = (ucCommand << 4) & 0xf0;
CLEAR_RS;
delay(MICRO_SEC_1); // Delay of 1uSec.
SET_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
CLEAR_E;
delay(MICRO_SEC_37); // Delay of 40uSecs.
}
void ClearLine(unsigned char Line)
{
unsigned char uc;
WriteLcdCommand(Line);
for(uc = 20; uc > 0; uc--)
{
WriteLcdData(' ');
}
}
void ClearLcd(void)
{
WriteLcdCommand(LCD_CLEAR);
delay(MICRO_SEC_1520);
}
void HomeLcd(void)
{
WriteLcdCommand(LCD_HOME);
delay(MICRO_SEC_1520);
}
/* ************************************************************************ *\
FUNCTION: void init_lcd(void);
Sets the HD44780 to 8-bit mode. Note that although the data sheet says only
two writes of 0x3c are required, experience has shown that sometimes fails.
Three writes of 0x3c ensure correct operation every time.
INPUTS: NONE.
OUTPUT: NONE.
FUNCTIONS USED: delay() & lcd_command().
\* ************************************************************************ */
void init_lcd(void)
{
unsigned char ucX;
// DDRC = 0xFF; // Port C is all outputs.
delay(MICRO_SEC_15000); // Although the HD44780 data sheet says 15ms is enough in here it isn't, so ...
delay(MICRO_SEC_15000); // ... put in an extra one.
gucLcdControl = 0x30;
CLEAR_RS;
delay(MICRO_SEC_1); // Delay of 1uSec.
SET_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
CLEAR_E;
delay(MICRO_SEC_4100);
SET_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
CLEAR_E;
delay(MICRO_SEC_4100);
SET_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
CLEAR_E;
delay(MICRO_SEC_4100);
gucLcdControl = 0x20;
CLEAR_RS;
delay(MICRO_SEC_1); // Delay of 1uSec.
SET_E;
delay(MICRO_SEC_1); // Delay of 1uSec.
CLEAR_E;
delay(MICRO_SEC_100);
WriteLcdCommand(LCD_MODE);
WriteLcdCommand(LCD_OFF);
WriteLcdCommand(LCD_SET_CGRAM_ADDR);
for(ucX = 0; ucX < 64; ucX++)
{
WriteLcdData(CharacterMap[ucX]);
}
WriteLcdCommand(LCD_INC);
WriteLcdCommand(LCD_ON);
}
/* ************************************************************************ *\
FUNCTION: void PutText(unsigned char *ucBuffer);
Sends a string in RAM to the screen.
Note that this function does not check for line overflow.
INPUTS: *ucBuffer.
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdData().
\* ************************************************************************ */
void PutText(unsigned char *ucBuffer)
{
unsigned char i;
for(i = 0; ucBuffer[i]; i++)
{
WriteLcdData(ucBuffer[i]);
}
}
/* ************************************************************************ *\
FUNCTION: void cPutText(const unsigned char *cucText);
Sends the string 'cucText' to the screen.
Note that this function does not check for line overflow.
INPUTS: *cucText.
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdData().
\* ************************************************************************ */
void cPutText(const unsigned char *cucText)
{
unsigned char i;
for(i = 0; cucText[i]; i++)
{
WriteLcdData((unsigned char)(cucText[i])); // Need a cast here as 'cucText[i] is 'const'.
}
}
/* ************************************************************************ *\
FUNCTION: void ShowSubtitle(Subtitle *pST);
Displays the subtitle pointed to by 'pST' on the screen.
INPUTS: *pST.
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdCommand(), WriteLcdData().
\* ************************************************************************ */
void ShowSubtitle(Subtitle *pST)
{
WriteLcdCommand(pST->MemAddr);
cPutText(pST->Value);
}
/* ************************************************************************ *\
FUNCTION: void ClearSubtitle(Subtitle *pST);
Clears the subtitle pointed to by 'pST' on the screen.
INPUTS: *pST.
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdCommand(), WriteLcdData().
\* ************************************************************************ */
void ClearSubtitle(Subtitle *pST)
{
unsigned char uc;
WriteLcdCommand(pST->MemAddr);
for(uc = cstrlen(pST->Value); uc > 0; uc--)
{
WriteLcdData(' ');
}
}
/* ************************************************************************ *\
FUNCTION: void HighlightOn(Subtitle *pST);
Highlights the subtitle pointed to by 'pST'.
INPUTS: *pST.
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdCommand(), WriteLcdData().
\* ************************************************************************ */
void HighlightOn(Subtitle *pST)
{
WriteLcdCommand(pST->MemAddr - 1);
WriteLcdData(RIGHT_ARROW);
WriteLcdCommand(pST->MemAddr + cstrlen(pST->Value));
WriteLcdData(LEFT_ARROW);
}
/* ************************************************************************ *\
FUNCTION: void HighlightOff(Subtitle *pST);
Removes the highlight from the subtitle pointed to by 'pST'.
INPUTS: *pST.
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdCommand(), WriteLcdData().
\* ************************************************************************ */
void HighlightOff(Subtitle *pST)
{
WriteLcdCommand(pST->MemAddr - 1);
WriteLcdData(' ');
WriteLcdCommand(pST->MemAddr + cstrlen(pST->Value));
WriteLcdData(' ');
}
/* ************************************************************************ *\
FUNCTION: void ShowButton(Button *pBT);
Displays the button pointed to by 'pBT'.
INPUTS: *pBT.
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdCommand(), WriteLcdData().
\* ************************************************************************ */
void ShowButton(Button *pBT)
{
WriteLcdCommand(pBT->MemAddr);
WriteLcdData('[');
cPutText(pBT->Value);
WriteLcdData(']');
}
/* ************************************************************************ *\
FUNCTION: void ShowTwoDigits(unsigned char Value);
Displays the value in 'Value' as a 2 digit integer with leading zeroes.
INPUTS: Value
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdCommand(), WriteLcdData().
\* ************************************************************************ */
void ShowTwoDigits(unsigned char Value)
{
unsigned char t, u;
if(Value > 99)
{
Value %= 100;
}
t = Value / 10;
u = Value % 10;
WriteLcdData('0' + t);
WriteLcdData('0' + u);
}
/* ************************************************************************ *\
FUNCTION: void FillInTempField(TempField *pTF);
Displays the temperature in the 'Value' field of the 'TempField' structure
pointed to by 'pTF' as a 3 digit integer with leading zero suppression.
INPUTS: *pTF
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdCommand(), WriteLcdData().
\* ************************************************************************ */
void FillInTempField(TempField *pTF)
{
unsigned char h, t, u, v;
v = *(pTF->Value);
h = v / 100;
v -= h * 100;
t = v / 10;
u = v - (t * 10);
WriteLcdCommand(pTF->MemAddr);
if(h == 0)
{
WriteLcdData(' ');
if(t == 0)
{
WriteLcdData(' ');
}
else
{
WriteLcdData('0' + t);
}
}
else
{
WriteLcdData('0' + h);
WriteLcdData('0' + t);
}
WriteLcdData('0' + u);
}
/* ************************************************************************ *\
FUNCTION: void ShowFloat(unsigned char Value);
Displays the value in 'Value' as a 2 digit pseudo floating point number.
INPUTS: Value
OUTPUT: NONE.
FUNCTIONS USED: WriteLcdCommand(), WriteLcdData().
\* ************************************************************************ */
void ShowFloat(unsigned char Value)
{
unsigned char u, d;
u = Value / 10;
d = Value % 10;
WriteLcdData('0' + u);
WriteLcdData('.');
WriteLcdData('0' + d);
}
More information about the Icc-avr
mailing list