Search code examples
atmegaavr-gcclcd

displaying Hexadecimal value in LCD


I wrote LCD interface program for Atmega328 (Though there are libraries available, I wanted to write from scratch). But have two problems. 1. Sometimes LCD does not display correctly. Only few strips are seen. I end up in resetting once or twice. 2. I am unable to display hexadecimal values usingdisplayOneByteHexValue(). However ASCII coversion was correct and I could see that in Atmel Simulator. Below is the code. I am using Atmel Studio 6.2

/*
* EmbeddedProgram1.c
*
* Created: 16-05-2015 08:19:38
*  Author: Mahesha
*/


#ifndef F_CPU
#define F_CPU 8000000UL
#endif

#include <avr/io.h>
#include <util/delay.h>

    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Only Change following when changing pin numbers.
// All Data bits have to be assigned sequentially in same the port . RS and EN must be allocated in the same port
#define LCDPORT PORTD
#define LCDDDR DDRD
// used pins on port appropriate ports
#define LCD_DB4 2    // PORTD.2
#define LCD_DB5 3    // PORTD.3
#define LCD_DB6 4    // PORTD.4
#define LCD_DB7 5    // PORTD.5
#define LCD_ENABLE_BIT  6     // PORTD.6 Enable
#define LCD_RS 7     // PORTD.7 Register Select
//#define LCD_RW     // R/W is connected to GND permanently


#define LCD_DATA_BITS_MASK 0x3C
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#define SET_EIGHT_BIT_MODE() LCDPORT|=((1<<LCD_DB5)|(1<<LCD_DB4))    // Set DB4 and DB5 as 1 for setting eight bit mode.
#define SET_FOUR_BIT_MODE() LCDPORT|=(1<<LCD_DB5)
#define SET_INSTRUCTION_MODE() LCDPORT&=~(1<<LCD_RS)      //Function to select command port on LCD RS pin bit 2
#define SET_DATA_MODE() LCDPORT|=(1<<LCD_RS)         //Function to select data port on LCD
#define DISABLE_LCD() LCDPORT&=~(1<<LCD_ENABLE_BIT)           //Function to disable LCD P0.18
#define ENABLE_LCD() LCDPORT|=(1<<LCD_ENABLE_BIT)            //Function to Enable LCD     P0.18

//#define EIGHT_BIT_MODE 0x30                                      // 0 0 1 1 x x x x DB7 to DB0 0f LCD
#define BUSY_FLAG_WAIT_TIME 20
#define FOUR_BIT_5_BY_10_2LINE 0x28
#define LCD_INIT_DELAY 100      // Give a delay of 200 msec after reset. // Datasheet says 10 msec delay.


//Commands Finalized
#define CLEAR_DISPLAY 0x01
#define CURSOR_HOME 0x02    // return home
#define ENTRY_MODE_LEFT_TO_RIGHT 0x06              // Cursor direction from Left to right   , Bit 1 of entry mode in LCD
#define DISPLAY_OFF  0x08        // Blink ON, Cursor ON etc are don't care
#define CURSOR_OFF_BLINK_OFF   0x0C
#define CURSOR_OFF_BLINK_ON 0x0D    // blink on Even 0x0D also works. So cursor need not be ON
#define CURSOR_ON_BLINK_OFF 0x0E    // blink off
#define CURSOR_ON_BLINK_ON 0x0F
#define SHIFT_ENTIRE_LEFT 0x18
#define SHIFT_CURSOR_LEFT 0x10
#define SHIFT_ENTIRE_RIGHT 0x1C
#define SHIFT_CURSOR_RIGHT 0x14

// Function prototypes
void unpackAndSend(char  data);
void waitForBusyFlagToClear(void);
void sendLCDPulse(void);
void displayInRow1(char* data);
void displayInRow2(char* data);
void displayInRow1WithPosition(char* data, uint8_t position);
void displayInRow2WithPosition(char* data, uint8_t position);
void sendTextToLCD(char *data);
void displayOneByteHexValue(unsigned char,unsigned char,char);
void initializeLCD(void);

void CL_delayMS(unsigned int delayMS)
{
    while(delayMS--)
    {
        _delay_ms(1);
    }
}

void CL_delayuS(unsigned int delayus)
{
    while(delayus--)
    {
        _delay_us(1);
    }
}


// writes a char to the LCD
void writeCharToLCD(unsigned char data)
{
    SET_DATA_MODE();                  // RS bit has to be 1 for data mode
    unpackAndSend(data);

}

// sendLCD pulse will just enable and disable the EN bit of LCD display.
void sendLCDPulse(void)
{
    DISABLE_LCD();
    CL_delayuS(50);
    ENABLE_LCD();
    CL_delayMS(1);
    DISABLE_LCD();
    CL_delayMS(1);
}

// writes an instruction to the LCD
void sendLCDCommand(unsigned char inst)
{
    SET_INSTRUCTION_MODE();
    unpackAndSend(inst);
    waitForBusyFlagToClear();

}

// Unpack and send data will separate two nibbles and send twice.
void unpackAndSend(char inst)
{
    char temp=inst;
    DISABLE_LCD();
    // SET_WRITE_MODE();               // If write is permanently disabled, do not use this.

    LCDPORT &= (~LCD_DATA_BITS_MASK);   // Clear the data bits
    //sendLCDPulse();
    inst&=0xF0;
    inst=inst>>4;                            // Get the upper nibble
    LCDPORT|=inst<<LCD_DB4;                 //Replace the bits starting from position of bit LCD_DB4 with this new data
    sendLCDPulse();
    LCDPORT &= (~LCD_DATA_BITS_MASK);  // Clear the data bits again
    //sendLCDPulse();
    temp &=0x0f; //send low nibble
    LCDPORT|=temp<<LCD_DB4;
    sendLCDPulse();

}

// waitForBusyFlagToClear functio can wait for the busy bit, But since we are permanently connected R/W pin to ground, we cannot read
// the flag from LCD. In case busy bit has to be read, implementation has to be changed.

void waitForBusyFlagToClear(void)
{
    CL_delayMS(BUSY_FLAG_WAIT_TIME);
}


// clear display
void clearDisplay(void)
{
    sendLCDCommand (CLEAR_DISPLAY);
}

// return home
void returnCursorHome(void)
{
    sendLCDCommand (CURSOR_HOME);
}

// LCD off
void displayOFF(void)
{
    sendLCDCommand (DISPLAY_OFF);
}

// LCD on
void displayONCursorOFF(void)
{
    sendLCDCommand (CURSOR_OFF_BLINK_OFF);
}

// cursor on
void displayONCursorON(void)
{
    sendLCDCommand (CURSOR_ON_BLINK_OFF);
}

// blink on
void cursorOffBlinkOn(void)
{
    sendLCDCommand (CURSOR_OFF_BLINK_ON);
}

// blink OFF, but display and cursors are ON
void cursorOnBlinkOff(void)
{
    sendLCDCommand (CURSOR_ON_BLINK_OFF);
}

// All are ON
void cursorOnBlinkOn(void)
{
    sendLCDCommand (CURSOR_ON_BLINK_ON);
}

//go to first line
void LCDline1 (void)

{
    sendLCDCommand (0b10000000);
}

//go to second line
void LCDline2 (void)

{
    sendLCDCommand (0b11000000);
}


// goto position x,y
// row1 or row2 are the parameters
// So parameters can be 1 or 2
void setRowAndColumnPositionOnDisplay (unsigned char rowNumber, unsigned char position)
{
    unsigned char pos;

    if (rowNumber == 1)
    {
        pos = 0x00 + position;
        pos|=0x80;                  // Command to set 1st Row.
    }

    else //if (rowNumber == 1)     // Either row 1 or two. We cannot have else option.
    {
        pos = 0x40 + position;
        pos|=0xC0;                // Command to set second row.
    }
    sendLCDCommand (pos);
}

void displayInRow1(char* data)
{
    sendLCDCommand(0x80);        // Set DDRAM Address as 0
    sendTextToLCD(data);
}

void displayInRow1WithPosition(char* data, unsigned char position)
{
    // The position cannot be more than 15. Display is 16 characters (0-15).
    if(position>15)
    {
        position = 15;
    }
    sendLCDCommand(0x80|position);    // Change the DDRAM address to first line by
    //  keeping D7 high and setting address to 0 onwards
    sendTextToLCD(data);
}

//////////////////////////////    diaplayInRow2   /////////////////////////////////////////////

void displayInRow2(char* data)
{
    sendLCDCommand(0xC0);     // Change the DDRAM address to next line 0x40 to 4F
    sendTextToLCD(data);
}

//////////////////////    diaplayInRow2WithPosition   //////////////////////

void displayInRow2WithPosition(char* data, unsigned char position)
{
    // The position cannot be more than 15. Display is 16 characters (0-15).
    if(position>15)
    {
        position = 15;
    }
    sendLCDCommand(0xC0|position);    // Change the DDRAM address to second line by
    //keeping Bit D7 high and setting address at 0x40 onwards
    sendTextToLCD(data);
}

void scrollLcd(char *row1Data,char *row2Data)
{

    while(1)
    {
        sendLCDCommand(SHIFT_CURSOR_LEFT);
        sendLCDCommand(SHIFT_ENTIRE_LEFT);
        CL_delayMS(200);
    }
}


//write text to the LCD
void sendTextToLCD(char *data)
{
    while (*data)
    {
        writeCharToLCD(*data);
        data++;
    }
}

// Function to convert lower nibble to ASCII Value
//Only lower nibble of the input is considered and higher nibble is lost

char convertLowerNibbleToASCIIValue(char data)
{
    data&=0x0F;
    if(data<=9)
    {
        return(data+0x30);
    }
    else            // There is no chance for getting more than 0x0F in the lowerNibble Parameter)
    {
        return(data+0x37);
    }
}

// Function to convert Higher nibble to ASCII Value
//Only higher nibble of the input is considered and lower nibble is lost
char convertHigherNibbleToASCIIValue(char data)
{
    data>>=4;
    if(data<=9)
    {
        return(data+0x30);
    }
    else            // There is no chance for getting more than 0x0F in the lowerNibble Parameter)
    {
        return(data+0x37);
    }
}

void displayOneByteHexValue(unsigned char rowNum, unsigned char pos, char data)
{
    char temp;
    setRowAndColumnPositionOnDisplay(rowNum,pos);
    temp = convertHigherNibbleToASCIIValue(data);
    sendTextToLCD(&temp);
    temp = convertLowerNibbleToASCIIValue(data);
    sendTextToLCD(&temp);

}

// init LCD

void initializeLCD(void)
{
    // Set the direction of port pins connected to LCD display as output ports.
    // We are permanently connecting R/W pin to ground. So there is no read instruction in this case..
    LCDDDR |= (1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7)|(1<<LCD_RS)|(1<<LCD_ENABLE_BIT);

    //After reset, data sheet suggests some delay.
    CL_delayMS(LCD_INIT_DELAY);

    // Note some sites says three times 8 bit mode setting commands need to be sent.
    // But it is observed that even without this, LCD works fine. So 1st Command, 2nd Command and 3rd Commands can be deleted below.
    //ENABLE_LCD();
    // 1st Command
    SET_EIGHT_BIT_MODE();
    //sendLCDPulse();    // Do not delete this. Need to further analyse. If pulse if sent it is not working
    //CL_delayMS(5);     // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
    _delay_ms(5);

    // Second Command
    SET_EIGHT_BIT_MODE();
    //sendLCDPulse();
    _delay_us(100);
    //CL_delayuS(100);   // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers

    // third Command
    SET_EIGHT_BIT_MODE();
    //sendLCDPulse();
    //CL_delayuS(100);   // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
    _delay_us(37);
    // Finally Set four bit mode
    SET_FOUR_BIT_MODE();
    //sendLCDPulse();
    CL_delayuS(100);

    // First time when 4 bit mode command is sent, only one higher nibble was sent since
    // only 4 bits are connected from MPU to LCD. Since D0 to D3 of LCD are not connected,
    // their values depend on how the pins are connected in LCD module (May be grounded, may kept open etc)
    //So again send function set command to set 2 line display mode mode and 5x7 character mode. But now two write operations to LCD is made
    // inside the function sendLCDCommand.
    sendLCDCommand (FOUR_BIT_5_BY_10_2LINE);

    //turn on display and cursor OFF, Blink OFF (sent two times using below command)
    sendLCDCommand (CURSOR_OFF_BLINK_OFF);

    //clr display
    sendLCDCommand (CLEAR_DISPLAY);

    // Set Entry mode left to right
    sendLCDCommand (ENTRY_MODE_LEFT_TO_RIGHT);
}



void LCDProgramCallFromMain(char *row1Data, char *row2Data)
{
    initializeLCD();
    setRowAndColumnPositionOnDisplay (1,0);
    sendTextToLCD (row1Data);   
    displayOneByteHexValue(2,0,0xF4);

    //setRowAndColumnPositionOnDisplay (2,5);
    //displayInRow1(row1Data);
}


int main(void)
{
    LCDProgramCallFromMain("Hello", "Welcome to cloude");
    while(1)
    {


    }
}

Below is the image of the display I am getting. Not able to makeout where the problem is. Result


Solution

  • Yes, it worked after I changed the function as below. Thanks for the help.

    void displayOneByteHexValue(unsigned char rowNum, unsigned char pos, char data)
    {
        char temp;
        setRowAndColumnPositionOnDisplay(rowNum,pos);
        temp = convertHigherNibbleToASCIIValue(data);
        writeCharToLCD(temp);
        temp = convertLowerNibbleToASCIIValue(data);
        writeCharToLCD(temp);
    
    }
    

    I further optimized the code and below is the complete working code with small demo function called from main.

    #ifndef F_CPU
    #define F_CPU 16000000UL
    #endif
    
    #include <avr/io.h>
    #include <util/delay.h>
    #include <stdlib.h>
    #include <avr/sfr_defs.h>
    
    
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //Only Change following when changing pin numbers.
    // All Data bits have to be assigned sequentially in same the port . RS and EN must be allocated in the same port
    #define LCDPORT PORTD
    #define LCDDDR DDRD
    // used pins on port appropriate ports
    #define LCD_DB4 2    // PORTD.2
    #define LCD_DB5 3    // PORTD.3
    #define LCD_DB6 4    // PORTD.4
    #define LCD_DB7 5    // PORTD.5
    #define LCD_ENABLE_BIT  6     // PORTD.6 Enable
    #define LCD_RS 7     // PORTD.7 Register Select
    //#define LCD_RW     // R/W is connected to GND permanently
    
    
    #define LCD_DATA_BITS_MASK ((1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7))
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    /*
    #define SET_EIGHT_BIT_MODE() LCDPORT|=((1<<LCD_DB5)|(1<<LCD_DB4))    // Set DB4 and DB5 as 1 for setting eight bit mode.
    #define SET_FOUR_BIT_MODE() LCDPORT|=(1<<LCD_DB5)
    */
    
    #define SET_INSTRUCTION_MODE() LCDPORT&=~(1<<LCD_RS)      //Function to select command port on LCD RS pin bit 2
    #define SET_DATA_MODE() LCDPORT|=(1<<LCD_RS)         //Function to select data port on LCD
    #define DISABLE_LCD() LCDPORT&=~(1<<LCD_ENABLE_BIT)           //Function to disable LCD P0.18
    #define ENABLE_LCD() LCDPORT|=(1<<LCD_ENABLE_BIT)            //Function to Enable LCD     P0.18
    #define BUSY_FLAG_WAIT_TIME 20
    #define FOUR_BIT_5_BY_10_2LINE 0x28
    #define LCD_INIT_DELAY 100      // Give a delay of 100 msec after reset. // Datasheet says 10 msec delay.
    
    
    // Function prototypes for external use (to be kept in Header file)
    void sendLCDCommand(unsigned char cmd);
    void displayInRow1(unsigned char* data);
    void displayInRow2(unsigned char* data);
    void displayInRow1WithPosition(unsigned char* data, uint8_t position);
    void displayInRow2WithPosition(unsigned char* data, uint8_t position);
    void sendTextToLCD(unsigned char *data);
    void initializeLCD(void);
    
    
    // Function prototypes for file use (only internal)
    void unpackAndSend(char  data);
    void waitForBusyFlagToClear(void);
    void sendLCDPulse(void);
    void displayOneByteHexValue(unsigned char,unsigned char,char);   // This function is no longer needed. Only for demo purpose.
    
    // #define commands are  replaced by enums to demonstrate the feature of enumerated data types
    
    enum DISPLAY_PROPERTY
    {
    CLEAR_DISPLAY=0x01,
    CURSOR_HOME =  0x02,    // return home
    ENTRY_MODE_LEFT_TO_RIGHT= 0x06,              // Cursor direction from Left to right , Bit 1 of entry mode in LCD
    DISPLAY_OFF=  0x08,        // Blink ON, Cursor ON etc are don't care
    CURSOR_OFF_BLINK_OFF= 0x0C,
    CURSOR_OFF_BLINK_ON= 0x0D,    // blink on Even 0x0D also works. So cursor need not be ON
    CURSOR_ON_BLINK_OFF=0x0E,    // blink off
    CURSOR_ON_BLINK_ON=0x0F,
    SHIFT_ENTIRE_LEFT= 0x18,
    SHIFT_CURSOR_LEFT= 0x10,
    SHIFT_ENTIRE_RIGHT= 0x1C,
    SHIFT_CURSOR_RIGHT= 0x14,
    };
    
    
    void SET_EIGHT_BIT_MODE(void)
    {
    LCDPORT=(LCDPORT&(~LCD_DATA_BITS_MASK))|((0<<LCD_DB7)|(0<<LCD_DB6)|(1<<LCD_DB5)|(1<<LCD_DB4));    // Set DB4 and DB5 as 1 for setting eight bit mode.
    }
    
    void SET_FOUR_BIT_MODE(void)
    {
    LCDPORT= (LCDPORT&(~LCD_DATA_BITS_MASK)) | ((0<<LCD_DB7)|(0<<LCD_DB6)|(1<<LCD_DB5)|(0<<LCD_DB4));
    }
    
    
    void CL_delayMS(unsigned int delayMS)
    {
        while(delayMS--)
        {
            _delay_ms(1);
        }
    }
    
    void CL_delayuS(unsigned int delayus)
    {
        while(delayus--)
        {
            _delay_us(1);
        }
    }
    
    
    // writes a char to the LCD
    void writeCharToLCD(unsigned char data)
    {
    SET_DATA_MODE();                  // RS bit has to be 1 for data mode
    unpackAndSend(data);
    }
    
    // sendLCD pulse will just enable and disable the EN bit of LCD display.
    void sendLCDPulse(void)
    {
    //DISABLE_LCD();
    //CL_delayuS(50);
    ENABLE_LCD();
    CL_delayMS(1);
    DISABLE_LCD();
    CL_delayMS(1);
    }
    
    // writes an instruction to the LCD
    void sendLCDCommand(unsigned char cmd)
    {
    SET_INSTRUCTION_MODE();
    unpackAndSend(cmd);
    waitForBusyFlagToClear();
    
    }
    
    // Unpack and send data will separate two nibbles and send twice.
    void unpackAndSend(char inst)
    {
    char temp=inst;
    DISABLE_LCD();
    // SET_WRITE_MODE();               // If write is permanently disabled, do not use this.
    
    LCDPORT &= (~LCD_DATA_BITS_MASK);   // Clear the data bits
    //sendLCDPulse();
    inst&=0xF0;
    inst=inst>>4;                            // Get the upper nibble
    LCDPORT|=inst<<LCD_DB4;                 //Replace the bits starting from position of bit LCD_DB4 with this new data
    sendLCDPulse();
    LCDPORT &= (~LCD_DATA_BITS_MASK);  // Clear the data bits again
    //sendLCDPulse();
    temp &=0x0f; //send low nibble
    LCDPORT|=temp<<LCD_DB4;
    sendLCDPulse();
    }
    
    // waitForBusyFlagToClear function can wait for the busy bit, But since we are permanently connected R/W pin to ground, we cannot read
    // the flag from LCD. In case busy bit has to be read, implementation has to be changed.
    
    void waitForBusyFlagToClear(void)
    {
    CL_delayMS(BUSY_FLAG_WAIT_TIME);
    }
    
    
    // goto position x,y
    // row1 or row2 are the parameters
    // So parameters can be 0 or 1
    void setRowAndColumnPositionOnDisplay (unsigned char rowNumber, unsigned char position)
    {
    unsigned char pos;
    
    if (rowNumber==0)            // If Row is 0, display in 1st row
    {
    pos = 0x00 + position;
    pos|=0x80;                  // Command to set 1st Row.
    }
    
    else //if (rowNumber == 1)     // Either row 1 or two etc
    {
    pos = 0x40 + position;
    pos|=0xC0;                // Command to set second row.
    }
    
    sendLCDCommand (pos);
    
    }
    
    void displayInRow1(unsigned char* data)
    {
    sendLCDCommand(0x80);        // Set DDRAM Address as 0
    sendTextToLCD(data);
    }
    
    void displayInRow1WithPosition(unsigned char* data, unsigned char position)
    {
    sendLCDCommand(0x80|position);    // Change the DDRAM address to first line by
    //  keeping D7 high and setting address to 0 onwards
    sendTextToLCD(data);
    }
    
    //////////////////////////////    diaplayInRow2   /////////////////////////////////////////////
    
    void displayInRow2(unsigned char* data)
    {
    sendLCDCommand(0xC0);     // Change the DDRAM address to next line 0x40 to 4F
    sendTextToLCD(data);
    }
    
    //////////////////////    diaplayInRow2WithPosition   //////////////////////
    
    void displayInRow2WithPosition(unsigned char* data, unsigned char position)
    {
    sendLCDCommand(0xC0|position);    // Change the DDRAM address to second line by
    //keeping Bit D7 high and setting address at 0x40 onwards
    sendTextToLCD(data);
    }
    
    
    //write text to the LCD
    void sendTextToLCD(unsigned char *data)
    {
    while (*data)
    {
    writeCharToLCD(*data);
    data++;
    }
    }
    
    // initialize LCD
    
    void initializeLCD(void)
    {
    // Set the direction of port pins connected to LCD display as output ports
    // We are permanently connecting R/W pin to ground. So there is no read instruction in this case
    LCDDDR |= (1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7)|(1<<LCD_RS)|(1<<LCD_ENABLE_BIT);
    
    //After reset, data sheet suggests some delay.
    CL_delayMS(LCD_INIT_DELAY);
    
    
    // Note some sites says three times 8 bit mode setting commands need to be sent.
    // But it is observed that even without this, LCD works fine. So 1st Command, 2nd Command and 3rd Commands can be deleted below.
    //ENABLE_LCD();
    // 1st Command
    SET_EIGHT_BIT_MODE();
    sendLCDPulse();    // Do not delete this. Need to further analyze. If pulse if sent it is not working
    //CL_delayMS(5);     // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
    _delay_ms(5);
    
    
    // Second Command
    SET_EIGHT_BIT_MODE();
    sendLCDPulse();
    _delay_us(100);
    //CL_delayuS(100);   // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
    
    // third Command
    SET_EIGHT_BIT_MODE();
    sendLCDPulse();
    //CL_delayuS(100);   // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
    _delay_us(37);
    // Finally Set four bit mode
    SET_FOUR_BIT_MODE();
    sendLCDPulse();
    CL_delayuS(100);
    
    // First time when 4 bit mode command is sent, only one higher nibble was sent since
    // only 4 bits are connected from MPU to LCD. Since D0 to D3 of LCD are not connected,
    // their values depend on how the pins are connected in LCD module (May be grounded, may kept open etc)
    //So again send function set command to set 2 line display mode mode and 5x7 character mode. But now two write operations to LCD is made
    // inside the function sendLCDCommand.
    sendLCDCommand (FOUR_BIT_5_BY_10_2LINE);
    
    
    //turn on display and cursor OFF, Blink OFF (sent two times using below command)
    sendLCDCommand (CURSOR_OFF_BLINK_OFF);
    
    //clr display
    sendLCDCommand (CLEAR_DISPLAY);
    
    // Set Entry mode left to right
    sendLCDCommand (ENTRY_MODE_LEFT_TO_RIGHT);
    
    }
    
    void displayNumberTest(int range)
    {
    float fNum = -0.332;
    unsigned char lcdBuffer[50];
    sendLCDCommand(CLEAR_DISPLAY);
    //setRowAndColumnPositionOnDisplay (0,0);
    //sendTextToLCD("Decimal = ");
    for (int count=0;count<range;count++)
    {
    
    itoa(count,lcdBuffer,2);
    setRowAndColumnPositionOnDisplay (1,0);
    sendTextToLCD(lcdBuffer);
    itoa(count,lcdBuffer,16);
    setRowAndColumnPositionOnDisplay (1,13);
    sendTextToLCD(lcdBuffer);
    itoa(count,lcdBuffer,10);
    setRowAndColumnPositionOnDisplay (0,0);  // 1st Row, 0th position
    sendTextToLCD(lcdBuffer);
    
    // Now display some floating value number.
    // use the function dtostrf(). It take 4 parameters
    // Parameter1: The value to be converted
    // 2: Width
    //3. Precision
    // 4. String to hold ASCII
    
    // It is also possible to  use sprintf function. But it takes more memory.
    
    fNum=(fNum*(-1)*(count+1)/101.12)+0.012;
    dtostrf(fNum,5,3,lcdBuffer);
    setRowAndColumnPositionOnDisplay (0,7);
    sendTextToLCD(lcdBuffer);
    CL_delayMS(300);
    }
    
    }
    
    // Scroll the display
    // This program need to be modified further to display only whatever characters are there in DDRAM.
    // Right now 4 columns will be shifted just to demonstrate.
    void scrollingDisplayTest(unsigned char *row1Text, unsigned char* row2Text, unsigned int scrollDelay)
    {
    unsigned char count=40;
    sendLCDCommand(CLEAR_DISPLAY);
    displayInRow1(row1Text);
    displayInRow2(row2Text);
    CL_delayMS(2000);
    while(count--)
    {
    sendLCDCommand(SHIFT_ENTIRE_LEFT);
    CL_delayMS(scrollDelay);
    
    }
    }
    
    
    void LCDDemoProgram(unsigned char *row1Data, unsigned char *row2Data)
    {
    
    initializeLCD();
    sendTextToLCD (row1Data);
    setRowAndColumnPositionOnDisplay (1,0);
    sendTextToLCD (row2Data);
    CL_delayMS(3000);
    sendLCDCommand(CLEAR_DISPLAY);
    // Just to demostrate how Hex values can be displayed without using itoa library function
    displayOneByteHexValue(0,0,CLKPR);
    setRowAndColumnPositionOnDisplay (1,0);
    displayOneByteHexValue(1,12,0xE2);
    CL_delayMS(3000);
    sendLCDCommand(CLEAR_DISPLAY);
    //Wait for 3 seconds
    scrollingDisplayTest("Display will be cleared for 3 sec after displaying DONE ", "Please Wait.... Please Wait.....",1000);
    CL_delayMS(2000);
    sendLCDCommand(CLEAR_DISPLAY);
    displayInRow1("DONE");
    CL_delayMS(3000);
    displayInRow1("Cur OFF Bl OFF");
    sendLCDCommand(CURSOR_OFF_BLINK_OFF);
    CL_delayMS(3000);
    sendLCDCommand(CLEAR_DISPLAY);
    displayInRow1("Cur OFF Bl ON");
    sendLCDCommand(CURSOR_OFF_BLINK_ON);
    CL_delayMS(3000);
    sendLCDCommand(CLEAR_DISPLAY);
    displayInRow1("Cur ON Bl OFF");
    sendLCDCommand(CURSOR_ON_BLINK_OFF);
    CL_delayMS(3000);
    sendLCDCommand(CLEAR_DISPLAY);
    displayInRow1("Cur ON Bl ON");
    sendLCDCommand(CURSOR_ON_BLINK_ON);
    CL_delayMS(3000);
    displayNumberTest(100);
    
    
    }
    
    
    ////////////////////////////////////////////////    Do No Use Below code. This is Only for demo purpose//////////////////////////////////////////
    
    // Function to convert lower nibble to ASCII Value
    //Only lower nibble of the input is considered and higher nibble is lost
    // This function is written for understanding purpose only.
    // itoa () library function can be used instead of this with base of 16.
    
    unsigned char convertLowerNibbleToASCIIValue(unsigned char data)
    {
    data&=0x0F;
    if(data<=9)
    {
    return(data+0x30);
    }
    else            // There is no chance for getting more than 0x0F in the lowerNibble Parameter)
    {
    return(data+0x37);
    }
    }
    
    // Function to convert Higher nibble to ASCII Value
    //Only higher nibble of the input is considered and lower nibble is lost
    unsigned char convertHigherNibbleToASCIIValue(unsigned char data)
    {
    data>>=4;
    if(data<=9)
    {
    return(data+0x30);
    }
    else            // There is no chance for getting more than 0x0F in the lowerNibble Parameter)
    {
    return(data+0x37);
    }
    }
    
    void displayOneByteHexValue(unsigned char rowNum, unsigned char pos, char data)
    {
    char temp;
    setRowAndColumnPositionOnDisplay(rowNum,pos);
    temp = convertHigherNibbleToASCIIValue(data);
    writeCharToLCD(temp);
    temp = convertLowerNibbleToASCIIValue(data);
    writeCharToLCD(temp);
    
    }
    
    // Displays 8 bit Register values in LCD display unit.
    // name is the name of the register to be displayed. You can give any name.
    // port is the register name.
    
    
    void displayRegisterValues(unsigned char *displayName, volatile uint8_t *registerName)
    {
    char temp2;
    displayInRow1(displayName);
    //temp2=registerName;
    temp2 = (convertLowerNibbleToASCIIValue(*registerName));
    displayInRow1(&temp2);
    // Get the higher Nibble
    temp2 = (convertLowerNibbleToASCIIValue((*registerName)>>4));
    displayInRow2(&temp2);
    
    }
    
    
    int main(void)
    {
        LCDDemoProgram("Hello", "World is Great");
        while(1)
        {
            //TODO:: Please write your application code 
        }
        return(0);
    }