[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