www.pudn.com > ucosii_block.rar > LCD.C
/*
*********************************************************************************************************
* Embedded Systems Building Blocks
* Complete and Ready-to-Use Modules in C
*
* LCD Display Module Driver
*
* (c) Copyright 1999, Jean J. Labrosse, Weston, FL
* All Rights Reserved
*
* Filename : LCD.C
* Programmer : Jean J. Labrosse
*********************************************************************************************************
* DESCRIPTION
*
*
* This module provides an interface to an alphanumeric display module.
*
* The current version of this driver supports any alphanumeric LCD module based on the:
* Hitachi HD44780 DOT MATRIX LCD controller.
*
* This driver supports LCD displays having the following configuration:
*
* 1 line x 16 characters 2 lines x 16 characters 4 lines x 16 characters
* 1 line x 20 characters 2 lines x 20 characters 4 lines x 20 characters
* 1 line x 24 characters 2 lines x 24 characters
* 1 line x 40 characters 2 lines x 40 characters
*********************************************************************************************************
*/
/*$PAGE*/
/*
*********************************************************************************************************
* INCLUDE FILES
*********************************************************************************************************
*/
#include "includes.h"
/*
*********************************************************************************************************
* LOCAL CONSTANTS
*********************************************************************************************************
*/
/* ---------------------- HD44780 COMMANDS -------------------- */
#define DISP_CMD_CLS 0x01 /* Clr display : clears display and returns cursor home */
#define DISP_CMD_FNCT 0x3B /* Function Set: Set 8 bit data length, 1/16 duty, 5x8 dots */
#define DISP_CMD_MODE 0x06 /* Entry mode : Inc. display data address when writing */
#define DISP_CMD_ON_OFF 0x0C /* Disp ON/OFF : Display ON, cursor OFF and no BLINK character */
/*
*********************************************************************************************************
* LOCAL VARIABLES
*********************************************************************************************************
*/
static INT8U DispMaxCols; /* Maximum number of columns (i.e. characters per line) */
static INT8U DispMaxRows; /* Maximum number of rows for the display */
static OS_EVENT *DispSem; /* Semaphore used to access display functions */
static INT8U DispBar1[] = {0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10};
static INT8U DispBar2[] = {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18};
static INT8U DispBar3[] = {0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C, 0x1C};
static INT8U DispBar4[] = {0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E, 0x1E};
static INT8U DispBar5[] = {0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F};
/*
*********************************************************************************************************
* LOCAL FUNCTION PROTOTYPES
*********************************************************************************************************
*/
static void DispCursorSet(INT8U row, INT8U col);
/*$PAGE*/
/*
*********************************************************************************************************
* DISPLAY A CHARACTER
*
* Description : This function is used to display a single character on the display device
* Arguments : 'row' is the row position of the cursor in the LCD Display
* 'row' can be a value from 0 to 'DispMaxRows - 1'
* 'col' is the column position of the cursor in the LCD Display
* 'col' can be a value from 0 to 'DispMaxCols - 1'
* 'c' is the character to write to the display at the current ROW/COLUMN position.
* Returns : none
*********************************************************************************************************
*/
void DispChar (INT8U row, INT8U col, char c)
{
INT8U err;
if (row < DispMaxRows && col < DispMaxCols) {
OSSemPend(DispSem, 0, &err); /* Obtain exclusive access to the display */
DispCursorSet(row, col); /* Position cursor at ROW/COL */
DispSel(DISP_SEL_DATA_REG);
DispDataWr(c); /* Send character to display */
OSSemPost(DispSem); /* Release access to display */
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* CLEAR LINE
*
* Description : This function clears one line on the LCD display and positions the cursor at the
* beginning of the line.
* Arguments : 'line' is the line number to clear and can take the value
* 0 to 'DispMaxRows - 1'
* Returns : none
*********************************************************************************************************
*/
void DispClrLine (INT8U line)
{
INT8U i;
INT8U err;
if (line < DispMaxRows) {
OSSemPend(DispSem, 0, &err); /* Obtain exclusive access to the display */
DispCursorSet(line, 0); /* Position cursor at begin of the line to clear */
DispSel(DISP_SEL_DATA_REG); /* Select the LCD Display DATA register */
for (i = 0; i < DispMaxCols; i++) { /* Write ' ' into all column positions of that line */
DispDataWr(' '); /* Write an ASCII space at current cursor position */
}
DispCursorSet(line, 0); /* Position cursor at begin of the line to clear */
OSSemPost(DispSem); /* Release access to display */
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* CLEAR THE SCREEN
*
* Description : This function clears the display
* Arguments : none
* Returns : none
*********************************************************************************************************
*/
void DispClrScr (void)
{
INT8U err;
OSSemPend(DispSem, 0, &err); /* Obtain exclusive access to the display */
DispSel(DISP_SEL_CMD_REG); /* Select the LCD display command register */
DispDataWr(DISP_CMD_CLS); /* Send command to LCD display to clear the display */
OSTimeDly(2); /* Delay at least 2 mS (2 ticks ensures at least this much) */
OSSemPost(DispSem); /* Release access to display */
}
/*$PAGE*/
/*
*********************************************************************************************************
* POSITION THE CURSOR (Internal)
*
* Description : This function positions the cursor into the LCD buffer
* Arguments : 'row' is the row position of the cursor in the LCD Display
* 'row' can be a value from 0 to 'DispMaxRows - 1'
* 'col' is the column position of the cursor in the LCD Display
* 'col' can be a value from 0 to 'DispMaxCols - 1'
* Returns : none
*********************************************************************************************************
*/
static void DispCursorSet (INT8U row, INT8U col)
{
DispSel(DISP_SEL_CMD_REG); /* Select LCD display command register */
switch (row) {
case 0:
if (DispMaxRows == 1) { /* Handle special case when only one line */
if (col < (DispMaxCols >> 1)) {
DispDataWr(0x80 + col); /* First half of the line starts at 0x80 */
} else { /* Second half of the line starts at 0xC0 */
DispDataWr(0xC0 + col - (DispMaxCols >> 1));
}
} else {
DispDataWr(0x80 + col); /* Select LCD's display line 1 */
}
break;
case 1:
DispDataWr(0xC0 + col); /* Select LCD's display line 2 */
break;
case 2:
DispDataWr(0x80 + DispMaxCols + col); /* Select LCD's display line 3 */
break;
case 3:
DispDataWr(0xC0 + DispMaxCols + col); /* Select LCD's display line 4 */
break;
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* DEFINE CHARACTER
*
* Description : This function defines the dot pattern for a character.
* Arguments : 'id' is the identifier for the desired dot pattern.
* 'pat' is a pointer to an 8 BYTE array containing the dot pattern.
* Returns : None.
*********************************************************************************************************
*/
void DispDefChar (INT8U id, INT8U *pat)
{
INT8U err;
INT8U i;
OSSemPend(DispSem, 0, &err); /* Obtain exclusive access to the display */
DispSel(DISP_SEL_CMD_REG); /* Select command register */
DispDataWr(0x40 + (id << 3)); /* Set address of CG RAM */
DispSel(DISP_SEL_DATA_REG); /* Select the data register */
for (i = 0; i < 8; i++) {
DispDataWr(*pat++); /* Write pattern into CG RAM */
}
OSSemPost(DispSem); /* Release access to display */
}
/*$PAGE*/
/*
*********************************************************************************************************
* DUMMY FUNCTION
*
* Description : This function doesn't do anything. It is used to act like a NOP (i.e. No Operation) to
* waste a few CPU cycles and thus, act as a short delay.
* Arguments : none
* Returns : none
*********************************************************************************************************
*/
void DispDummy (void)
{
}
/*$PAGE*/
/*
*********************************************************************************************************
* DISPLAY A HORIZONTAL BAR
*
* Description : This function allows you to display horizontal bars (bar graphs) on the LCD module.
* Arguments : 'row' is the row position of the cursor in the LCD Display
* 'row' can be a value from 0 to 'DispMaxRows - 1'
* 'val' is the value of the horizontal bar. This value cannot exceed:
* DispMaxCols * 5
* Returns : none
* Notes : To use this function, you must first call DispHorBarInit()
*********************************************************************************************************
*/
void DispHorBar (INT8U row, INT8U col, INT8U val)
{
INT8U i;
INT8U full;
INT8U fract;
INT8U err;
full = val / 5; /* Find out how many 'full' blocks to turn ON */
fract = val % 5; /* Compute portion of block */
if (row < DispMaxRows && (col + full - 1) < DispMaxCols) {
OSSemPend(DispSem, 0, &err); /* Obtain exclusive access to the display */
i = 0; /* Set counter to limit column to maximum allowable column */
DispCursorSet(row, col); /* Position cursor at beginning of the bar graph */
DispSel(DISP_SEL_DATA_REG);
while (full > 0) { /* Write all 'full' blocks */
DispDataWr(5); /* Send custom character #5 which is full block */
i++; /* Increment limit counter */
full--;
}
if (fract > 0) {
DispDataWr(fract); /* Send custom character # 'fract' (i.e. portion of block) */
}
OSSemPost(DispSem); /* Release access to display */
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* INITIALIZE HORIZONTAL BAR
*
* Description : This function is used to initialize the bar graph capability of this module. You must
* call this function prior to calling DispHorBar().
* Arguments : none
* Returns : none
*********************************************************************************************************
*/
void DispHorBarInit (void)
{
DispDefChar(1, &DispBar1[0]);
DispDefChar(2, &DispBar2[0]);
DispDefChar(3, &DispBar3[0]);
DispDefChar(4, &DispBar4[0]);
DispDefChar(5, &DispBar5[0]);
}
/*$PAGE*/
/*
*********************************************************************************************************
* DISPLAY DRIVER INITIALIZATION
*
* Description : This function initializes the display driver.
* Arguments : maxrows specifies the number of lines on the display (1 to 4)
* maxcols specified the number of characters per line
* Returns : None.
* Notes : - DispInit() MUST be called only when multitasking has started. This is because
* DispInit() requires time delay services from the operating system.
* - DispInit() MUST only be called once during initialization.
*********************************************************************************************************
*/
void DispInit (INT8U maxrows, INT8U maxcols)
{
DispInitPort(); /* Initialize I/O ports used in display driver */
DispMaxRows = maxrows;
DispMaxCols = maxcols;
DispSem = OSSemCreate(1); /* Create display access semaphore */
/* INITIALIZE THE DISPLAY MODULE */
DispSel(DISP_SEL_CMD_REG); /* Select command register. */
OSTimeDlyHMSM(0, 0, 0, 50); /* Delay more than 15 mS after power up (50 mS should be enough)*/
DispDataWr(DISP_CMD_FNCT); /* Function Set: Set 8 bit data length, 1/16 duty, 5x8 dots */
OSTimeDly(2); /* Busy flag cannot be checked yet! */
DispDataWr(DISP_CMD_FNCT); /* The above command is sent four times! */
OSTimeDly(2); /* This is recommended by Hitachi in the HD44780 data sheet */
DispDataWr(DISP_CMD_FNCT);
OSTimeDly(2);
DispDataWr(DISP_CMD_FNCT);
OSTimeDly(2);
DispDataWr(DISP_CMD_ON_OFF); /* Disp ON/OFF: Display ON, cursor OFF and no BLINK character */
DispDataWr(DISP_CMD_MODE); /* Entry mode: Inc. display data address when writing */
DispDataWr(DISP_CMD_CLS); /* Send command to LCD display to clear the display */
OSTimeDly(2); /* Delay at least 2 mS (2 ticks ensures at least this much) */
}
/*$PAGE*/
/*
*********************************************************************************************************
* DISPLAY AN ASCII STRING
*
* Description : This function is used to display an ASCII string on a line of the LCD display
* Arguments : 'row' is the row position of the cursor in the LCD Display
* 'row' can be a value from 0 to 'DispMaxRows - 1'
* 'col' is the column position of the cursor in the LCD Display
* 'col' can be a value from 0 to 'DispMaxCols - 1'
* 's' is a pointer to the string to write to the display at
* the desired row/col.
* Returns : none
*********************************************************************************************************
*/
void DispStr (INT8U row, INT8U col, char *s)
{
INT8U i;
INT8U err;
if (row < DispMaxRows && col < DispMaxCols) {
OSSemPend(DispSem, 0, &err); /* Obtain exclusive access to the display */
DispCursorSet(row, col); /* Position cursor at ROW/COL */
DispSel(DISP_SEL_DATA_REG);
i = col; /* Set counter to limit column to maximum allowable column */
while (i < DispMaxCols && *s) { /* Write all chars within str + limit to DispMaxCols */
DispDataWr(*s++); /* Send character to LCD display */
i++; /* Increment limit counter */
}
OSSemPost(DispSem); /* Release access to display */
}
}
/*$PAGE*/
/*
*********************************************************************************************************
* WRITE DATA TO DISPLAY DEVICE
*
* Description : This function sends a single BYTE to the display device.
* Arguments : 'data' is the BYTE to send to the display device
* Returns : none
* Notes : You will need to adjust the value of DISP_DLY_CNTS (LCD.H) to produce a delay between
* writes of at least 40 uS. The display I used for the test actually required a delay of
* 80 uS! If characters seem to appear randomly on the screen, you might want to increase
* the value of DISP_DLY_CNTS.
*********************************************************************************************************
*/
#ifndef CFG_C
void DispDataWr (INT8U data)
{
INT8U dly;
outp(DISP_PORT_DATA, data); /* Write data to display module */
outp(DISP_PORT_CMD, 0x01); /* Set E line HIGH */
DispDummy(); /* Delay about 1 uS */
outp(DISP_PORT_CMD, 0x00); /* Set E line LOW */
for (dly = DISP_DLY_CNTS; dly > 0; dly--) { /* Delay for at least 40 uS */
DispDummy();
}
}
#endif
/*
*********************************************************************************************************
* INITIALIZE DISPLAY DRIVER I/O PORTS
*
* Description : This initializes the I/O ports used by the display driver.
* Arguments : none
* Returns : none
*********************************************************************************************************
*/
#ifndef CFG_C
void DispInitPort (void)
{
outp(DISP_PORT_CMD, 0x82); /* Set to Mode 0: A are output, B are inputs, C are outputs */
}
#endif
/*
*********************************************************************************************************
* SELECT COMMAND OR DATA REGISTER
*
* Description : This function read a BYTE from the display device.
* Arguments : none
*********************************************************************************************************
*/
#ifndef CFG_C
void DispSel (INT8U sel)
{
if (sel == DISP_SEL_CMD_REG) {
outp(DISP_PORT_CMD, 0x02); /* Select the command register (RS low) */
} else {
outp(DISP_PORT_CMD, 0x03); /* Select the data register (RS high) */
}
}
#endif