Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

How to get LCD to work with MPLAB XC8

Status
Not open for further replies.

DarrenUD

New Member
Hi All,

I am having serious issue with using MPLAB XC8 software. I have used MikroC before and programming is easy with all the built-in libraries. Just few weeks ago I thought I should learn MPLAB XB8 in order to write more flexible and optimised code as it is provided by Microchip it self. I couldn't get XLCD.H to work and I have also tried few other libraries and sample code available on the internet without any success.

I am just about to give up on MPLAB XC8 and move back to MikroC where everything is nice and easy for non PRO programmers like us. Here is my problem and I hope someone can guide me in the right direction.

I have my LCD connected to PORTB. uC - PIC16F887
RS - B7
E - B6
D4 - B3
D5 - B2
D6 - B1
D7 - B0

I have followed the directions given by Ian Rogers to a fellow forum member and code as follows.

Code:
#define _XTAL_FREQ 8000000

#define LCD_PORT    PORTB       // constants
#define LCD_TRIS    TRISB       //
#define LCD_RS      PORTBbits.RB7
#define LCD_E       PORTBbits.RB6
#define LCD_RW      PORTBbits.RB5

#include <stdio.h>
#include <stdlib.h>
#include <pic.h>
#include <xc.h>

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Reset Selection bits (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
#pragma config LVP = OFF        // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)

// CONFIG2
#pragma config BOR4V = BOR40V   // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)

      
void Delay5MS(){
    _delay(5100);
}
void Delay1MS(){
    _delay(1025);
}
void Delay15MS(){
    _delay(5100);
    _delay(5100);
    _delay(5100);
}
void Delay150MS()
{
    for(int i=0;i<10;i++)
    {
        Delay15MS();
    }
}
void Delay20MS(){
    _delay(5100);
    _delay(5100);
    _delay(5100);
    _delay(5100);
}
void Delay200US(){
    _delay(200);
}
void Delay50US(){
    _delay(45);
}
void Delay1US(){
_delay(1);
}
void LCD_init(void), LCD_cmd(unsigned char ch);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void), LCD_hex(int value);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);

int main() {
    ANSEL=0x04;
    ANSELH=0x00;   
   
   
    LCD_RW=0;          
    LCD_TRIS = 0x00;
    Delay150MS();              
    LCD_init();                    
           
    while(1)                       
        {
           LCD_goto(1,0);                   
           LCD_char('A'); 
           Delay20MS();
        }   
}

void LCD_init()
    {
    LCD_cmd(0x20);                  // 4 bit
    LCD_cmd(0x28);                  // display shift
    LCD_cmd(0x6);                   // character mode
    LCD_cmd(0xc);                   // display on / off and cursor
    LCD_clr();                      // clear display
    }


/*void LCD_hex(int value)
    {
    char data;                              // dispay hex values.
    data = value >> 4 & 0xf;                // send upper nibble
    data = HEX_Table[data];                 // hex lookup
    LCD_char(data);
    data = value & 0xf;                     // send lower nibble
    data = HEX_Table[data];                 // hex lookup
    LCD_char(data);
    }*/

void LCD_goto(char line, char column)       // combines line and lineW
    {
    unsigned char data = 0x80;              // default to 1
    if(line == 2)data = 0xc0;               // change to 2
    data += column;                         // add in  column
    LCD_cmd(data);
    }

void LCD_clr()
    {
    LCD_cmd(1);                             // Clr screen
    }

void LCD_cur(char on)
    {
    unsigned char cur = 0xc;                // cursor off
    if(on) cur = 0xd;                       // cursor on
    LCD_cmd(cur);
    }

void LCD_cmd(unsigned char ch)
    {
    LCD_PORT = ch  & 0xf0;          // write high nibble
    LCD_RS = 0;
    pulse_E();
    LCD_PORT = ch <<4 & 0xf0;               // write low nibble
    LCD_RS = 0;
    pulse_E();
    Delay5MS();
    }

void LCD_charD(unsigned char ch)
    {
    ch+=0x30;
    LCD_char(ch);                       // convert to ascii
    }

void LCD_char(unsigned char ch)
    {
    LCD_PORT = ch  & 0xf0;          // write high nibble
    LCD_RS = 0;
    pulse_E();
    LCD_PORT = ch <<4 & 0xf0; 
    LCD_RS = 1;
    pulse_E();
    Delay5MS();
    }

void pulse_E()
    {
    LCD_E = 1;
    Delay1US();
    LCD_E = 0;
    }


Thanks
 
The initialization of the LCD needs some delays inserted.

From the data sheet,
LCD init.png

HTH

Mike.
 
:(
Hi Mike,

Sorry I do not understand what it means. What is BF (is it busy flag). Please note I am not a professional programmer. Can you please give me a better explanation.
 
You need to go through the initialization sequence exactly as in the table.
Code:
void LCD_init()
    {
    Delay15MS();
    LCD_cmd(0x20);                  // 4 bit
    Delay5MS();
    LCD_cmd(0x20);                  // 4 bit
    Delay1MS();
    LCD_cmd(0x20);                  // 4 bit
    LCD_cmd(0x28);                  // display shift
    LCD_cmd(0x6);                   // character mode
    LCD_cmd(0xc);                   // display on / off and cursor
    LCD_clr();                      // clear display
    }

I just noticed that Ian has a delay in LCD_cmd so you may not need the delays but you do need to write 0x20 three times.

Mike.
 
I just noticed your connections. D7 to B0 isn't going to work without a big rewrite. D7 to B7 etc. is what the code needs. If you need to use D7 to B3 then the code will need a little tweeking.

Mike.
 
If at all possible... You need to swap those pins around.. MikroC allows single bit data bus, where as I didn't..

If you cant move your pins, I'll see if I can do a bit write to them.... Even the builtin "XLCD.H" doesn't allow for this kind of connection....
 
I have noticed a problem in the code as well..

RS should be set to 1 in both these commands...

C:
void LCD_char(unsigned char ch)
    {
    LCD_PORT = ch  & 0xf0;          // write high nibble
    LCD_RS = 0; //<-- should be set to 1..
    pulse_E();
    LCD_PORT = ch <<4 & 0xf0;
    LCD_RS = 1;
    pulse_E();
    Delay5MS();
    }
 
Hi all,

Mike, Ian, Nigel - Thank you very much for your valuable comments and updates, but I have tried all and still unsuccessful and think I am going to give up on MPLAB. I have wasted about week to figure it out how to use XC8 to interface with LCD. I think Microchip should built some easy to use code libraries for hobby users so we can design test and build simple uC circuits without scratching our heads and pulling hair for days. Any how I am updating my code again and please let me know if I made another mistake.

BTW: I have changed data pins to D4-D7 and RS,EN and RW to B0,B1,B2 (PORTB)

Code:
#define _XTAL_FREQ 8000000

#define LCD_PORT    PORTB       // constants
#define LCD_TRIS    TRISB       //
#define LCD_RS      PORTBbits.RB0
#define LCD_E       PORTBbits.RB1
#define LCD_RW      PORTBbits.RB2

#include <stdio.h>
#include <stdlib.h>
#include <pic.h>
#include <xc.h>

#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)
#pragma config CP = OFF         // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown Out Reset Selection bits (BOR enabled)
#pragma config IESO = ON        // Internal External Switchover bit (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
#pragma config LVP = OFF        // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)

// CONFIG2
#pragma config BOR4V = BOR40V   // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF        // Flash Program Memory Self Write Enable bits (Write protection off)

     
void Delay5MS(){
    _delay(5100);
}
void Delay1MS(){
    _delay(1025);
}
void Delay15MS(){
    _delay(5100);
    _delay(5100);
    _delay(5100);
}
void Delay150MS()
{
    for(int i=0;i<10;i++)
    {
        Delay15MS();
    }
}
void Delay20MS(){
    _delay(5100);
    _delay(5100);
    _delay(5100);
    _delay(5100);
}
void Delay200US(){
    _delay(200);
}
void Delay50US(){
    _delay(45);
}
void Delay1US(){
_delay(1);
}
void LCD_init(void), LCD_cmd(unsigned char ch);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void), LCD_hex(int value);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);

int main() {
    ANSEL=0x04;
    ANSELH=0x00;  
  
    TRISB6=0;  
    LCD_RW=0;         
    LCD_TRIS = 0x00;
    Delay150MS();             
    LCD_init();                   
          
    while(1)                      
        {
           LCD_goto(1,0);                  
           LCD_char('A');
           Delay20MS();
        }  
}

/*void LCD_init()
    {
    LCD_cmd(0x20);                  // 4 bit
    LCD_cmd(0x28);                  // display shift
    LCD_cmd(0x6);                   // character mode
    LCD_cmd(0xc);                   // display on / off and cursor
    LCD_clr();                      // clear display
    }*/

void LCD_init()
    {
    Delay15MS();
    LCD_cmd(0x20);                  // 4 bit
    Delay5MS();
    LCD_cmd(0x20);                  // 4 bit
    Delay1MS();
    LCD_cmd(0x20);                  // 4 bit
    LCD_cmd(0x28);                  // display shift
    LCD_cmd(0x6);                   // character mode
    LCD_cmd(0xc);                   // display on / off and cursor
    LCD_clr();                      // clear display
    }

/*void LCD_hex(int value)
    {
    char data;                              // dispay hex values.
    data = value >> 4 & 0xf;                // send upper nibble
    data = HEX_Table[data];                 // hex lookup
    LCD_char(data);
    data = value & 0xf;                     // send lower nibble
    data = HEX_Table[data];                 // hex lookup
    LCD_char(data);
    }*/

void LCD_goto(char line, char column)       // combines line and lineW
    {
    unsigned char data = 0x80;              // default to 1
    if(line == 2)data = 0xc0;               // change to 2
    data += column;                         // add in  column
    LCD_cmd(data);
    }

void LCD_clr()
    {
    LCD_cmd(1);                             // Clr screen
    }

void LCD_cur(char on)
    {
    unsigned char cur = 0xc;                // cursor off
    if(on) cur = 0xd;                       // cursor on
    LCD_cmd(cur);
    }

void LCD_cmd(unsigned char ch)
    {
    LCD_PORT = ch  & 0xf0;          // write high nibble
    LCD_RS = 0;
    pulse_E();
    LCD_PORT = ch <<4 & 0xf0;               // write low nibble
    LCD_RS = 1;
    pulse_E();
    Delay5MS();
    }

void LCD_charD(unsigned char ch)
    {
    ch+=0x30;
    LCD_char(ch);                       // convert to ascii
    }

void LCD_char(unsigned char ch)
    {
    LCD_PORT = ch  & 0xf0;          // write high nibble
    LCD_RS = 1;
    pulse_E();
    LCD_PORT = ch <<4 & 0xf0;
    LCD_RS = 1;
    pulse_E();
    Delay5MS();
    }

void pulse_E()
    {
    LCD_E = 1;
    Delay1US();
    LCD_E = 0;
    }
 
Mike, Ian, Nigel - Thank you very much for your valuable comments and updates, but I have tried all and still unsuccessful and think I am going to give up on MPLAB. I have wasted about week to figure it out how to use XC8 to interface with LCD. I think Microchip should built some easy to use code libraries for hobby users so we can design test and build simple uC circuits without scratching our heads and pulling hair for days.

You're doing something wrong somewhere :D

Both Ian's C version of my code, and the other site I linked to, worked perfectly first time for me.
 
Just give me your LCD pinouts... I'll do a function to swap all the data bits.... Its quite easy..

I think Microchip should built some easy to use code libraries for hobby users so we can design test and build simple uC circuits without scratching our heads and pulling hair for days. Any how I am updating my code again and please let me know if I made another mistake.

Just for your info!!! MikroC is too easy..... If you need to move from compiler to compiler then you really need to learn to make low level libraries.... XC8 is a brilliant compiler , sure one or two hangups , but none the less a fantastic compiler!!!

I use MikroC for Pic32.... Its okay for me because I understand how libraries are formed.... I know most of MikroC's pitfalls ( believe me there are plenty )... Here on this forum, you will get far more help with XC8 than any other compiler!! Just keep going just a little longer and I'll point you in the correct direction.... Just draft me a quick schematic, and I'll show you where you are going wrong!!
 
Just a mo!!!

Are you using ISIS??? Your delay routines are set for a 4Mhz crystal! When using an 8Mhz the delays were all half of what they should be....

Use this init() routine for ISIS ( Very low tolerance ISIS!!)

Here is the whole code working!!

C:
 #define _XTAL_FREQ 8000000

  #define LCD_PORT  PORTB  // constants
  #define LCD_TRIS  TRISB  //
  #define LCD_RS  PORTBbits.RB0
  #define LCD_E  PORTBbits.RB1
  #define LCD_RW  PORTBbits.RB2

  #include <stdio.h>
  #include <stdlib.h>
  #include <pic.h>
  #include <xc.h>

  #pragma config FOSC = HS  // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
  #pragma config WDTE = OFF  // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
  #pragma config PWRTE = OFF  // Power-up Timer Enable bit (PWRT disabled)
  #pragma config MCLRE = ON  // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)
  #pragma config CP = OFF  // Code Protection bit (Program memory code protection is disabled)
  #pragma config CPD = OFF  // Data Code Protection bit (Data memory code protection is disabled)
  #pragma config BOREN = ON  // Brown Out Reset Selection bits (BOR enabled)
  #pragma config IESO = ON  // Internal External Switchover bit (Internal/External Switchover mode is enabled)
  #pragma config FCMEN = ON  // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
  #pragma config LVP = OFF  // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)

  // CONFIG2
  #pragma config BOR4V = BOR40V  // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
  #pragma config WRT = OFF  // Flash Program Memory Self Write Enable bits (Write protection off)

   
  void Delay5MS(){
  _delay(5100);
  }
  void Delay1MS(){
  _delay(1025);
  }
  void Delay15MS(){
  _delay(5100);
  _delay(5100);
  _delay(5100);
  }
  void Delay150MS()
  {
  for(int i=0;i<10;i++)
  {
  Delay15MS();
  }
  }
  void Delay20MS(){
  _delay(5100);
  _delay(5100);
  _delay(5100);
  _delay(5100);
  }
  void Delay200US(){
  _delay(200);
  }
  void Delay50US(){
  _delay(45);
  }
  void Delay1US(){
  _delay(1);
  }
  void LCD_init(void), LCD_cmd(unsigned char ch);
  void LCD_goto(char line, char column), LCD_clr(void);
  void LCD_cur(unsigned char ch), pulse_E(void), LCD_hex(int value);
  void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);

  int main() {
  ANSEL=0x04;
  ANSELH=0x00;  
   
  TRISB6=0;  
  LCD_RW=0;   
  LCD_TRIS = 0x00;
  Delay150MS();   
  LCD_init();   
   
  while(1)   
  {
  LCD_goto(1,0);   
  LCD_char('A');
  Delay20MS();
  }  
  }
   
  void LCD_init()
  {
  Delay15MS();
  PORTB = 0x20;
     pulse_E();
    Delay5MS();
     pulse_E();
     Delay5MS();
     pulse_E();
     Delay5MS();
  LCD_cmd(0x28);  // display shift
  LCD_cmd(0x6);  // character mode
  LCD_cmd(0xc);  // display on / off and cursor
  LCD_clr();  // clear display
  }

   

  void LCD_goto(char line, char column)  // combines line and lineW
  {
  unsigned char data = 0x80;  // default to 1
  if(line == 2)data = 0xc0;  // change to 2
  data += column;  // add in  column
  LCD_cmd(data);
  }

  void LCD_clr()
  {
  LCD_cmd(1);  // Clr screen
  }

  void LCD_cur(char on)
  {
  unsigned char cur = 0xc;  // cursor off
  if(on) cur = 0xd;  // cursor on
  LCD_cmd(cur);
  }

  void LCD_cmd(unsigned char ch)
  {
  LCD_PORT = ch  & 0xf0;  // write high nibble
  LCD_RS = 0;
  pulse_E();
  LCD_PORT = ch <<4 & 0xf0;  // write low nibble
  LCD_RS = 0;
  pulse_E();
  Delay5MS();
  }

  void LCD_charD(unsigned char ch)
  {
  ch+=0x30;
  LCD_char(ch);  // convert to ascii
  }

  void LCD_char(unsigned char ch)
  {
  LCD_PORT = ch  & 0xf0;  // write high nibble
  LCD_RS = 1;
  pulse_E();
  LCD_PORT = ch <<4 & 0xf0;
  LCD_RS = 1;
  pulse_E();
  Delay5MS();
  }

  void pulse_E()
  {
  LCD_E = 1;
  Delay1US();
  LCD_E = 0;
  }
 
BTW: I have changed data pins to D4-D7 and RS,EN and RW to B0,B1,B2 (PORTB)
[/CODE]

I assume the above was a typo and you meant B4 to B7. However, you didn't say which way around you connected them. You need D7 to B7, D6 to B6 etc.

Mike.
 
Nigel:
You're doing something wrong somewhere :D

Thanks Nigel, I got it working and I am glad that I have asked the question in the right forum where lot of good programmers and designers willing to help beginners like me :).

Ian:
Just keep going just a little longer and I'll point you in the correct direction....


Thanks Ian. I really appreciate your words and finally I got it working. I believe it was the delay routines.

Ian:
Just a mo!!!

Are you using ISIS??? Your delay routines are set for a 4Mhz crystal! When using an 8Mhz the delays were all half of what they should be....

Yes you are right. And I didn't realize that proteus simulation can cause so much headache. I build the circuit on a proto board and the pin arrangement is different to what I have used here. I do normally run the simulation on Proteus before flashing the uC .

Mike:
I assume the above was a typo and you meant B4 to B7. However, you didn't say which way around you connected them. You need D7 to B7, D6 to B6 etc.

Yes Mike that was a mistake. in my proto board the connection are like follows.
B7 - RS
B6 - EN

B3 - D4
B3 - D5
B1 - D6
B0 - D7


currently the code runs with the pin arrangement sown in the attachment and I am trying to modify the code so that I use the PORT and pins in any order.
Disign_zps9gqj3njo.jpg

Disign_zps9gqj3njo.jpg

Disign_zps9gqj3njo.jpg

Thanks everyone for helping me. I believe I have lot to learn......
 
Last edited by a moderator:
Hi All,

I am updating my final code for the project so it will help other people who has similar issues programming LCD or ADC modules. Moreover, I have separated LCD routines to a separate .h file for the convenience of reading and understanding the code clearly. I still have questions, like my ADC value won't go more than 1020 (max should be 1023), hopefully someone with broad knowledge can answer this question. So here it is:

LCD.h
Code:
#define LCD_PORT  PORTB  // constants
#define LCD_TRIS  TRISB  //
#define LCD_RS  PORTBbits.RB0
#define LCD_E  PORTBbits.RB1
#define LCD_RW  PORTBbits.RB2

void Delay5MS()
{
  _delay(5100);
}

void Delay1MS()
{
  _delay(1025);
}

void Delay15MS()
{
  _delay(5100);
  _delay(5100);
  _delay(5100);
}

void Delay150MS()
{
  for(int i=0;i<10;i++)
  {
    Delay15MS();
  }
}

void Delay20MS()
{
  _delay(5100);
  _delay(5100);
  _delay(5100);
  _delay(5100);
}

void Delay200US()
{
  _delay(200);
}

void Delay50US()
{
  _delay(45);
}

void Delay1US()
{
  _delay(1);
}

void LCD_init(void), LCD_cmd(unsigned char ch);
void LCD_goto(char line, char column), LCD_clr(void);
void LCD_cur(unsigned char ch), pulse_E(void), LCD_hex(int value);
void LCD_char(unsigned char ch), LCD_charD(unsigned char ch);
void LCD_Write_String(char *a);
void LCD_Write_Float(unsigned long adc_val);
void LCD_Write_Int(int adc_val);

void LCD_init()
{
  Delay15MS();
  PORTB = 0x20;
  pulse_E();
  Delay5MS();
  pulse_E();
  Delay5MS();
  pulse_E();
  Delay5MS();
  LCD_cmd(0x28);  // display shift
  LCD_cmd(0x6);  // character mode
  LCD_cmd(0xc);  // display on / off and cursor
  LCD_clr();  // clear display
}
void LCD_goto(char line, char column)  // combines line and lineW
{
  unsigned char data = 0x80;  // default to 1
  if(line == 2)data = 0xc0;  // change to 2
  data += column;  // add in  column
  LCD_cmd(data);
}

void LCD_clr()
{
  LCD_cmd(1);  // Clr screen
}

void LCD_cur(char on)
{
  unsigned char cur = 0xc;  // cursor off

  if(on) cur = 0xd;  // cursor on
  LCD_cmd(cur);
}

void LCD_cmd(unsigned char ch)
{
  LCD_PORT = ch  & 0xf0;  // write high nibble
  LCD_RS = 0;
  pulse_E();
  LCD_PORT = ch <<4 & 0xf0;  // write low nibble
  LCD_RS = 0;
  pulse_E();
  Delay5MS();
}

void LCD_charD(unsigned char ch)
{
  ch+=0x30;
  LCD_char(ch);  // convert to ascii
}

void LCD_char(unsigned char ch)
{
  LCD_PORT = ch  & 0xf0;  // write high nibble
  LCD_RS = 1;
  pulse_E();
  LCD_PORT = ch <<4 & 0xf0;
  LCD_RS = 1;
  pulse_E();
  Delay5MS();
}

void LCD_Write_String(unsigned char *a)
{
  int i;
  for(i=0;a[i]!='\0';i++)
    LCD_char(a[i]);
}

void pulse_E()
{
  LCD_E = 1;
  Delay1US();
  LCD_E = 0;
}

void LCD_Write_Float(unsigned long adc_val)
{
  unsigned long tlong;
  unsigned long ch;
  unsigned char fstring[]="0.000";

  tlong = (adc_val*5000)/1024;
  ch = tlong/1000;     
  fstring[0]=48+ch;

  fstring[1]='.';

  ch=(tlong/100) % 10;
  fstring[2]=48+ch;

  ch=(tlong/10) % 10;
  fstring[3]=48+ch;

  ch=(tlong/1) % 10;
  fstring[4]=48+ch;

  fstring[5]='\0';  
  LCD_Write_String(fstring);
}

void LCD_Write_Int(int adc_val)
{
  int ch;
  unsigned char Istring[]="0000";
   
  ch = adc_val/1000;     
  Istring[0]=48+ch;
    
  ch=(adc_val/100) % 10;
  Istring[1]=48+ch;

  ch=(adc_val/10) % 10;
  Istring[2]=48+ch;

  ch=(adc_val/1) % 10;
  Istring[3]=48+ch;

  Istring[4]='\0';  
  LCD_Write_String(Istring);
}


PIC16F887_ADC_LCD.C Code
Code:
#define _XTAL_FREQ 8000000

#include <xc.h>
#include "LCD.h"

#pragma config FOSC = HS  // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF  // Watchdog Timer Enable bit (WDT disabled and can be enabled by SWDTEN bit of the WDTCON register)
#pragma config PWRTE = OFF  // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON  // RE3/MCLR pin function select bit (RE3/MCLR pin function is MCLR)
#pragma config CP = OFF  // Code Protection bit (Program memory code protection is disabled)
#pragma config CPD = OFF  // Data Code Protection bit (Data memory code protection is disabled)
#pragma config BOREN = ON  // Brown Out Reset Selection bits (BOR enabled)
#pragma config IESO = ON  // Internal External Switchover bit (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON  // Fail-Safe Clock Monitor Enabled bit (Fail-Safe Clock Monitor is enabled)
#pragma config LVP = OFF  // Low Voltage Programming Enable bit (RB3 pin has digital I/O, HV on MCLR must be used for programming)

// CONFIG2
#pragma config BOR4V = BOR40V  // Brown-out Reset Selection bit (Brown-out Reset set to 4.0V)
#pragma config WRT = OFF  // Flash Program Memory Self Write Enable bits (Write protection off)

unsigned char text1[] = "ADC Test";
char s[10];
int result;     //variable to store our ADC result

void ADC_Config()
{
  ANSEL=0x04;
  ANSELH=0x00;

  ADCON0bits.ADCS=0b10;     //Fosc/32 is the conversion clock
  ADCON0bits.CHS=0b0010;    //select analog input, AN2
  ADCON0bits.ADON=1;        //Turn on the ADC

  ADCON1bits.ADFM=1;        //ADC result is right justified
  ADCON1bits.VCFG1=0;       //Vdd is the +ve reference
}
int main()
{
  TRISA = 0xFF;   //set all digital I/O to inputs
  TRISB = 0x00;
  TRISC = 0x00;

  LCD_RW=0;
  LCD_TRIS = 0x00;
  
  ADC_Config();

  Delay150MS();
  LCD_init();

  LCD_clr();
  LCD_goto(1,0);    ;
  LCD_Write_String(text1);

  __delay_ms(500);

  while(1)
  { 
    __delay_us(5);
    ADCON0bits.GO = 1;          //start the conversion
        while(ADCON0bits.GO==1){};  //wait for the conversion to end
        result = (ADRESH<<8)+ADRESL;    //combine the 10 bits of the conversion
    
    LCD_goto(1,0);
    LCD_goto(2,0);
    LCD_Write_Int(result);
    LCD_goto(2,7);
    LCD_Write_Float(result);
    __delay_ms(150);
  }
}

Thanks goes to fellow forum members Ian, Nigel, Mike for helping me with this project.
 
Last edited:
Hi All,

I have found a way to assign LCD port to the way I want initially, which was:
B0 - D7
B1 - D6
B2 - D5
B3 - D4

and B7 - RS, B6 - EN , B5 - N/A or RW. Here is the code and please let me know if you know how to do it better and optimized way.

Define union:
Code:
typedef union {
    unsigned char byte;
    struct {
        unsigned b0:1, b1:1, b2:1, b3:1, b4:1, b5:1, b6:1, b7:1;
    };
} t_byte;
 
t_byte CPORT;

Define functions:
Code:
void LCD_CPORT_Setbits(t_byte ch);
void CPORT_Setbits(unsigned char ch);

Implement functions:
Code:
void CPORT_Setbits(unsigned char ch)
{ t_byte CUPORT;
 
  CUPORT.byte = ch;
  LCD_CPORT_Setbits(CUPORT);   
}

void LCD_CPORT_Setbits(t_byte ch)
{
  PORTBbits.RB0 = ch.b7;
  PORTBbits.RB1 = ch.b6;
  PORTBbits.RB2 = ch.b5;
  PORTBbits.RB3 = ch.b4;
  PORTBbits.RB4 = ch.b3;
  PORTBbits.RB5 = ch.b2;
  PORTBbits.RB6 = ch.b1;
  PORTBbits.RB7 = ch.b0;
 
}

Finally, modify previous code/functions:
Code:
void LCD_init()
{
  Delay15MS();
  //PORTB = 0x20;
  CPORT_Setbits(0x20);
  pulse_E();
  Delay5MS();
  pulse_E();
  Delay5MS();
  pulse_E();
  Delay5MS();
  LCD_cmd(0x28);  // display shift
  LCD_cmd(0x6);  // character mode
  LCD_cmd(0xc);  // display on / off and cursor
  LCD_clr();  // clear display
}

void LCD_cmd(unsigned char ch)
{
  //LCD_PORT = ch  & 0xf0;  // write high nibble
  CPORT.byte = ch  & 0xf0;
  LCD_CPORT_Setbits(CPORT); 
  LCD_RS = 0;
  pulse_E();
  //LCD_PORT = ch <<4 & 0xf0;  // write low nibble
  CPORT.byte = ch <<4 & 0xf0;
  LCD_CPORT_Setbits(CPORT);
  LCD_RS = 0;
  pulse_E();
  Delay5MS();
}

void LCD_char(unsigned char ch)
{
  //LCD_PORT = ch  & 0xf0;  // write high nibble
  CPORT.byte = ch  & 0xf0;
  LCD_CPORT_Setbits(CPORT); 
  LCD_RS = 1;
  pulse_E();
  //LCD_PORT = ch <<4 & 0xf0;
  CPORT.byte = ch <<4 & 0xf0;
  LCD_CPORT_Setbits(CPORT); 
  LCD_RS = 1;
  pulse_E();
  Delay5MS();
}

and the final result is something like this:
Disign2_zpss1lgzufo.jpg


Thanks.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top