Maker Pro
Maker Pro

Help Programming 16x2 LCD - PIC16F73

Hi Guys,

I'm having trouble programming an 16x2 LCD, I wondered if someone could check my code. It compiles ok.

Still don't fully understand how to program this LCD, the order of which to execute commands seems confusing.

What is the sequence of writing data to the LCD, for example selecting the line cursor position?



Code:
#include <htc.h>
#include <pic.h>
#define _XTAL_FREQ 4000000
__CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & CP_OFF & BOREN_OFF );

/****************** PIN Mapping *******************/
#define BF RC0
#define RS RA3
#define RW RA4
#define EN RA5
#define D0 RC7
#define D1 RC6
#define D2 RC5
#define D3 RC4
#define D4 RC3
#define D5 RC2
#define D6 RC1
#define D7 RC0
/************ LCD Command Mapping LSB-BITFLIP *****************/
#define CLRDISP     0b01000000
#define DISPLAY_ON     0b00110000
#define DISPLAY_OFF 0b00010000
#define CURSOR_ON     0b01010000
#define CURSOR_OFF  0b00010000
#define CURSOR_INC  0b01100000
#define MODE_8BIT     0b00011100
#define MODE_4BIT    0b00010100
/************** Line Addr Mapping LSB-BITFLIP******************/
#define LCD_LINE1     0b00000001
#define LCD_LINE2     0b00000011
#define LCD_LINE3     0b00101001
#define LCD_LINE4     0b00101011

   
void LCD_cmd(unsigned char cmd);
void LCD_busy(void);
void LCD_data(unsigned char data);
void LCD_init(void);
void LCD_string(const char *ptr);


void LCD_init(void){
    TRISB = 0x00;
    TRISC = 0x00;
    LCD_cmd(MODE_8BIT);                        //2 Line, 5x8 disp, 8 bit
    LCD_cmd(CLRDISP);                        //Clear Display
    LCD_cmd(CURSOR_INC);                    //Increment Cursor on each write
    LCD_cmd(DISPLAY_ON | CURSOR_OFF);        //Bitwise OR
return;
}

void LCD_cmd(unsigned char cmd){
    LCD_busy();                    //Check if LCD busy
    RS=0;                        //Register set to CMD
    RW=0;                        //Write data
    EN=1;                        //Ensure Enable is HIGH
    PORTC=cmd;                    //Send data to PORTC
    __delay_ms(50);
    EN=0;                        //Enable is LOW
}

void LCD_busy(){
    TRISCbits.TRISC0=1;         //Make D7 as input
    EN=0;                        //Ensure Enable is LOW
    RS=0;                        //Register set to CMD
    RW=1;                        //Read Data
    EN=1;                        //Enable LOW too HIGH transition
    __delay_ms(50);
    while(BF);
    TRISCbits.TRISC0=0;         //Make D7 as output
    EN=0;
}

void LCD_data(unsigned char data){
    RS=1;
    RW=0;
    EN=1;
    PORTC=data;
    __delay_ms(50);
    EN=0;
}

void LCD_string(const char *buffer){
    while(*buffer)              // Write data to LCD up to null
    {
        LCD_busy();           // Wait while LCD is busy
        LCD_data(*buffer);      // Write character to LCD
        buffer++;               // Increment buffer
    }
}

void main(){
    LCD_init();
    LCD_cmd(LCD_LINE1);
    __delay_ms(50);
    LCD_string("     Welcome to     ");
    __delay_ms(50);
    LCD_cmd(LCD_LINE2);
    __delay_ms(50);
    LCD_string("Handicare");
    __delay_ms(2000);
}
 
Thanks Minder, I think i read Nigels code before..
I've had a quick read through the first two links, but still having trouble understanding.

Too send commands or data.. have i got this bit write (No pun intended).

Sending a Command:
Code:
RS=0;
RW=0;
EN=1;
PORTC=cmd;
__delay_ms(50);
EN=0;

Sending Text data:
Code:
RS=1;
RW=0;
EN=1;
PORTC=data;
__delay_ms(50);
EN=0;
 
I was taught assembly initially, but its been a few years.. :rolleyes:

Since I'm struggling to understand this in C.. I'll try revisit assembly go through Nigel assembly code.. o_O
 
I can't find where I've gone wrong here, so I really need some help here.

Another Tutorial Site Used:
http://embedjournal.com/programming-lcd-in-8-bit-mode/

My LCD Command Sheet:
http://s000.tinyupload.com/index.php?file_id=00528284006574499388

My Circuit Diagram:

Screenshot_1.png


My current code:
Code:
#include <htc.h>
#include <pic.h>
#define _XTAL_FREQ 4000000
__CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & CP_OFF & BOREN_OFF );

/****************** PIN Mapping *******************/
#define BF PORTCbits.RC7
#define RS PORTAbits.RA3      
#define RW PORTAbits.RA4  
#define EN PORTAbits.RA5  
#define D0 PORTCbits.RC0
#define D1 PORTCbits.RC1
#define D2 PORTCbits.RC2
#define D3 PORTCbits.RC3
#define D4 PORTCbits.RC4
#define D5 PORTCbits.RC5
#define D6 PORTCbits.RC6
#define D7 PORTCbits.RC7
/************ LCD Command Mapping *****************/
#define CLRDISP     0b00000010
#define DISPLAY_ON     0b00001100
#define DISPLAY_OFF 0b00001000
#define CURSOR_ON     0b00001010    /////////////////////////////
#define CURSOR_OFF  0b00001000    //See CMD Instruction Sheet//
#define CURSOR_INC  0b00000110    /////////////////////////////
#define MODE_8BIT     0b00111000
#define MODE_4BIT    0b00101000

#define DATAPORT PORTC
/************** Line Addr Mapping******************/
#define LCD_LINE1     0b10000000
#define LCD_LINE2     0b11000000  
#define LCD_LINE3     0b10010100
#define LCD_LINE4     0b11010100

  
void LCD_cmd(unsigned char cmd);
void LCD_busy(void);
void LCD_data(unsigned char data);
void LCD_init(void);
void LCD_string(const char *ptr);



void LCD_init(void){
    LCD_cmd(MODE_8BIT);                        //2 Line, 5x8 disp, 8 bit
    LCD_cmd(CLRDISP);                        //Clear Display
    LCD_cmd(CURSOR_INC);                    //Increment Cursor on each write
    LCD_cmd(DISPLAY_ON | CURSOR_OFF);        //Bitwise OR
return;
}  

void LCD_cmd(unsigned char cmd){
    LCD_busy();                    //Check if LCD busy
    RS=0;                        //Register set to CMD
    RW=0;                        //Write data
    EN=1;                        //Ensure Enable is HIGH
    DATAPORT=cmd;                    //Send data to PORTC
    __delay_ms(200);
    EN=0;                        //Enable is LOW
}

void LCD_busy(){
    TRISC7=1;         //Make D7 as input
    RS=0;                        //Register set to CMD
    RW=1;                        //Read Data
    EN=1;                        //Enable LOW too HIGH transition
    __delay_ms(200);
    while(BF);
    TRISC7=0;         //Make D7 as output
    EN=0;
}

void LCD_data(unsigned char data){
    RS=1;
    RW=0;
    EN=1;
    DATAPORT=data;
    __delay_ms(200);
    EN=0;
}

void LCD_string(const char *buffer){
    while(*buffer)              // Write data to LCD up to null
    {
        LCD_busy();           // Wait while LCD is busy
        LCD_data(*buffer);      // Write character to LCD
        buffer++;               // Increment buffer
    }
}

void main(){
    TRISA = 0x00;
    TRISB = 0x00;
    TRISC = 0x00;
    LCD_init();
    while(1)
    {
    LCD_cmd(LCD_LINE1);
    __delay_ms(200);
    LCD_string("     Welcome to     ");
    __delay_ms(200);
    LCD_cmd(LCD_LINE2);
    __delay_ms(200);
    LCD_string("Handicare");
    __delay_ms(2000);
    }
}



Ok, I know I've set my frequency and config bits alright. I've also mapped out my commands, lines and pins.
This part of my program seems okay and I've checked it several times.
 
Last edited:
The write to a line is address (in Hex) 0x80 for 1st line, 0xc0 for second line, any subsequent write to a line will increment the position, if you want to write to a particular char in either line, then add the posn to either 0x80 or 0xc0.
I don't use C so I cannot help very much with the problem.
M.
 
Ok, I've done that. I have the 1st line as 0b11000000 (0x80) and the 2nd line as 0b11000000 (0xc0).

Minder, whats this part of the code for in asm.. I dont think I've used the hex table in my code
Code:
HEX_Table      ADDWF   PCL       , f
                RETLW   0x30
                RETLW   0x31
                RETLW   0x32
                RETLW   0x33
                RETLW   0x34
                RETLW   0x35
                RETLW   0x36
                RETLW   0x37
                RETLW   0x38
                RETLW   0x39
                RETLW   0x41
                RETLW   0x42
                RETLW   0x43
                RETLW   0x44
                RETLW   0x45
                RETLW   0x46


Text        addwf    PCL, f
        retlw    'H'
        retlw    'e'
        retlw    'l'
        retlw    'l'
        retlw    'o'
        retlw    0x00

Text2        ADDWF   PCL, f
                RETLW   'R'
                RETLW   'e'
                RETLW   'a'
                RETLW   'd'
                RETLW   'y'
                RETLW   '.'
                RETLW   '.'
                RETLW   '.'
                RETLW   0x00
 
That is a method of table read for the 16F series.
I found the 18F series much better to use as they have quite a few features and advantages over the 16F series, especially programming in Assembly.
If you are still getting problems with proven code, could it possibly be a hardware issue?
M.
 
I'm using a PIC16F73.

I do believe its my code, I have checked my hardware several times.

Do you have any more asm code I could look at, or a complete LCD program
 
Last edited:
Thanks! ;)

Could I have the code for the 18F series aswell? :rolleyes:

I always read the datasheet for a new PIC to become familiar with its registers, so should be alright.
 
Hi Minder.. I finally got it working.
6ce1fa7.jpg

The problem was hardware related and somehow I was not getting +5V when switching my RS, RW and EN pins.
This might of had something to do with the pins being on PORTA.

My code was pretty much OK! Here is my working code:
Code:
#include <htc.h>
#include <pic.h>
#define _XTAL_FREQ 4000000
__CONFIG(FOSC_XT & WDTE_OFF & PWRTE_OFF & CP_OFF & BOREN_OFF );

/****************** PIN Mapping *******************/
#define BF PORTCbits.RC7
#define RS PORTBbits.RB4       
#define RW PORTBbits.RB3   
#define EN PORTBbits.RB2   
#define D0 PORTCbits.RC0
#define D1 PORTCbits.RC1
#define D2 PORTCbits.RC2
#define D3 PORTCbits.RC3
#define D4 PORTCbits.RC4
#define D5 PORTCbits.RC5
#define D6 PORTCbits.RC6
#define D7 PORTCbits.RC7
#define DATAPORT PORTC
/************ LCD Command Mapping *****************/
#define CLRDISP     0b00000001
#define DISPLAY_ON     0b00001100
#define DISPLAY_OFF 0b00001000
#define CURSOR_ON     0b00001010    /////////////////////////////
#define CURSOR_OFF  0b00001000    //See CMD Instruction Sheet//
#define CURSOR_INC  0b00000110    /////////////////////////////
#define MODE_8BIT     0b00111000
#define MODE_4BIT    0b00101000
/************** Line Addr Mapping******************/
#define LCD_LINE1     0b10000000
#define LCD_LINE2     0b11000000   


void LCD_cmd(unsigned char cmd);
void LCD_busy(void);
void LCD_data(unsigned char data);
void LCD_init(void);


void LCD_init(void){
    LCD_cmd(MODE_8BIT);                        //2 Line, 5x8 disp, 8 bit
    LCD_cmd(CLRDISP);                        //Clear Display
    LCD_cmd(CURSOR_INC);                    //Increment Cursor on each write
    LCD_cmd(DISPLAY_ON | CURSOR_OFF);        //Bitwise OR
}   


void LCD_cmd(unsigned char cmd){
    LCD_busy();                    //Check if LCD busy
    RS=0;                        //Register set to CMD
    EN=1;                        //Ensure Enable is HIGH
    RW=0;                        //Write data
    DATAPORT=cmd;                    //Send data to PORTC
    __delay_ms(200);
    EN=0;                        //Enable is LOW
}


void LCD_busy(){
    TRISC7=1;         //Make D7 as input
    RS=0;                        //Register set to CMD
    EN=1;                        //Enable LOW too HIGH transition
    RW=1;                        //Read Data
    __delay_ms(200);
    while(BF);
    TRISC7=0;         //Make D7 as output
    EN=0;
}


void LCD_data(unsigned char data){
    RS=1;
    EN=1;
    RW=0;
    DATAPORT=data;
    __delay_ms(200);
    EN=0;
}


void LCD_string(const char *buffer){
    while(*buffer)              // Write data to LCD up to null
    {
        LCD_busy();           // Wait while LCD is busy
        LCD_data(*buffer);      // Write character to LCD
        buffer++;               // Increment buffer
    }
}


void main()
{
    ADCON1=0b00000111;
    TRISA = 0x00;
    TRISB = 0x00;
    TRISC = 0x00;
    LCD_init();
    while(1)
    {
    LCD_cmd(LCD_LINE1);
    __delay_ms(200);
    LCD_string("Finally");
    __delay_ms(200);
    LCD_cmd(LCD_LINE2);
    __delay_ms(200);
    LCD_string("Working!");
    __delay_ms(2000);
    }
}
 
Top