Interfacing an LCD to pic16f876a for Digital Voltmeter

Status
Not open for further replies.

jean12

Advanced Member level 2
Joined
Aug 27, 2013
Messages
529
Helped
5
Reputation
12
Reaction score
6
Trophy points
18
www.ntigltd.com
Activity points
5,497
Hello there ,I have a problem;I want to interface an LCD to PIC16F876A for digital voltmeter 0-30VDC.

can you help me to see what's wrong with the below codes?

PHP:
#include "16f876a.h"     use portc for output
#device adc=10
#fuses HS,NOWDT,NOLVP,NOCPD
#use delay(clock=4M)
#include "lcd.c"
int value;
float value1,value2;
char *volt = "00.00";
void main()
{
	set_tris_a(0xff);
	set_tris_d(0x00);
	set_tris_c(0x00);
	
	setup_comparator(NC_NC_NC_NC);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(ALL_ANALOG);
   set_adc_channel(0);
   setup_vref(FALSE);


	lcd_init();
lcd_gotoxy(1,1);
	
	while(1)
	{
	delay_us(20);
	read_adc(adc_start_only);
	delay_us(100);
	value=read_adc(adc_read_only);
	value1=value*500*6/1023;
	value2=value1;
	
    volt[0] = value2/1000 + 48;
    volt[1] = value2/100)%10 + 48;
   volt[3] = (value2/10)%10 + 48;
     printf(lcd_putc,"\f%c",volt);
    delay_ms(100);
 printf(lcd_putc,2,5,volt);

/*
	delay_ms(150);
	printf(lcd_putc,"\f%.3f",value2);
	delay_ms(500);
		*/
		}
	
	
	}
Thanks
 

Hello,the codes are here below
PHP:
#include "16f876a.h"
#device adc=10
#fuses HS,NOWDT,NOLVP,NOCPD
#use delay(clock=4M)
#include "lcd.c"
int value;
float value1,value2;
char *volt = "00.00";
void main()
{
	set_tris_a(0xff);
	set_tris_b(0x00);
	set_tris_c(0x00);
	
	setup_comparator(NC_NC_NC_NC);
   setup_adc(ADC_CLOCK_INTERNAL);
   setup_adc_ports(ALL_ANALOG);
   set_adc_channel(0);
   setup_vref(FALSE);


	lcd_init();
lcd_gotoxy(1,1);
	
	while(1)
	{
	delay_us(20);
	read_adc(adc_start_only);
	delay_us(100);
	value=read_adc(adc_read_only);
	value1=value*500*6/1023;
	value2=value1;
	
    volt[0] = value2/1000 + 48;
    volt[1] = value2/100)%10 + 48;
   volt[3] = (value2/10)%10 + 48;
     printf(lcd_putc,"\f%c",volt);
    delay_ms(100);
 printf(lcd_putc,2,5,volt);

/*
	delay_ms(150);
	printf(lcd_putc,"\f%.3f",value2);
	delay_ms(500);
		*/
		}
	
	
	}
 

The problem is not interfacing just the conversion of analog input and display it on the LCD :0V-30V by this pic;I saw some codes on the net but they are in mikroC which is somehow hard for me ;please help me to make collections of the above codes and be able to read that range of voltage.

Thanks.
 

Hello,see my lcd.c file here:
PHP:
///////////////////////////////////////////////////////////////////////////////
////                             LCD.C                                     ////
////                 Driver for common LCD modules                         ////
////                                                                       ////
////  lcd_init()   Must be called before any other function.               ////
////                                                                       ////
////  lcd_putc(c)  Will display c on the next position of the LCD.         ////
////                     The following have special meaning:               ////
////                      \f  Clear display                                ////
////                      \n  Go to start of second line                   ////
////                      \b  Move back one position                       ////
////                                                                       ////
////  lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)        ////
////                                                                       ////
////  lcd_getc(x,y)   Returns character at position x,y on LCD             ////
////                                                                       ////
////  CONFIGURATION                                                        ////
////  The LCD can be configured in one of two ways: a.) port access or     ////
////  b.) pin access.  Port access requires the entire 7 bit interface     ////
////  connected to one GPIO port, and the data bits (D4:D7 of the LCD)     ////
////  connected to sequential pins on the GPIO.  Pin access                ////
////  has no requirements, all 7 bits of the control interface can         ////
////  can be connected to any GPIO using several ports.                    ////
////                                                                       ////
////  To use port access, #define LCD_DATA_PORT to the SFR location of     ////
////  of the GPIO port that holds the interface, -AND- edit LCD_PIN_MAP    ////
////  of this file to configure the pin order.  If you are using a         ////
////  baseline PIC (PCB), then LCD_OUTPUT_MAP and LCD_INPUT_MAP also must  ////
////  be defined.                                                          ////
////                                                                       ////
////  Example of port access:                                              ////
////     #define LCD_DATA_PORT getenv("SFR:PORTD")                         ////
////                                                                       ////
////  To use pin access, the following pins must be defined:               ////
////     LCD_ENABLE_PIN                                                    ////
////     LCD_RS_PIN                                                        ////
////     LCD_RW_PIN                                                        ////
////     LCD_DATA4                                                         ////
////     LCD_DATA5                                                         ////
////     LCD_DATA6                                                         ////
////     LCD_DATA7                                                         ////
////                                                                       ////
////  Example of pin access:                                               ////
////     #define LCD_ENABLE_PIN  PIN_E0                                    ////
////     #define LCD_RS_PIN      PIN_E1                                    ////
////     #define LCD_RW_PIN      PIN_E2                                    ////
////     #define LCD_DATA4       PIN_D4                                    ////
////     #define LCD_DATA5       PIN_D5                                    ////
////     #define LCD_DATA6       PIN_D6                                    ////
////     #define LCD_DATA7       PIN_D7                                    ////
////                                                                       ////
///////////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2010 Custom Computer Services           ////
//// This source code may only be used by licensed users of the CCS C  ////
//// compiler.  This source code may only be distributed to other      ////
//// licensed users of the CCS C compiler.  No other use, reproduction ////
//// or distribution is permitted without written permission.          ////
//// Derivative programs created using this software in object code    ////
//// form are not restricted in any way.                               ////
///////////////////////////////////////////////////////////////////////////

// define the pinout.
// only required if port access is being used.
typedef struct  
{                            // This structure is overlayed
   BOOLEAN enable;           // on to an I/O port to gain
   BOOLEAN rs;               // access to the LCD pins.
   BOOLEAN rw;               // The bits are allocated from
   BOOLEAN unused;           // low order up.  ENABLE will
   int     data : 4;         // be LSB pin of that port.
  #if defined(__PCD__)       // The port used will be LCD_DATA_PORT.
   int    reserved: 8;
  #endif
} LCD_PIN_MAP;

// this is to improve compatability with previous LCD drivers that accepted
// a define labeled 'use_portb_lcd' that configured the LCD onto port B.
#if ((defined(use_portb_lcd)) && (use_portb_lcd==TRUE))
 #define LCD_DATA_PORT getenv("SFR:PORTB")
#endif

#if defined(__PCB__)
   // these definitions only need to be modified for baseline PICs.
   // all other PICs use LCD_PIN_MAP or individual LCD_xxx pin definitions.
/*                                    EN, RS,   RW,   UNUSED,  DATA  */
 const LCD_PIN_MAP LCD_OUTPUT_MAP =  {0,  0,    0,    0,       0};
 const LCD_PIN_MAP LCD_INPUT_MAP =   {0,  0,    0,    0,       0xF};
#endif

////////////////////// END CONFIGURATION ///////////////////////////////////

#ifndef LCD_ENABLE_PIN
   #define lcd_output_enable(x) lcdlat.enable=x
   #define lcd_enable_tris()   lcdtris.enable=0
#else
   #define lcd_output_enable(x) output_bit(LCD_ENABLE_PIN, x)
   #define lcd_enable_tris()  output_drive(LCD_ENABLE_PIN)
#endif

#ifndef LCD_RS_PIN
   #define lcd_output_rs(x) lcdlat.rs=x
   #define lcd_rs_tris()   lcdtris.rs=0
#else
   #define lcd_output_rs(x) output_bit(LCD_RS_PIN, x)
   #define lcd_rs_tris()  output_drive(LCD_RS_PIN)
#endif

#ifndef LCD_RW_PIN
   #define lcd_output_rw(x) lcdlat.rw=x
   #define lcd_rw_tris()   lcdtris.rw=0
#else
   #define lcd_output_rw(x) output_bit(LCD_RW_PIN, x)
   #define lcd_rw_tris()  output_drive(LCD_RW_PIN)
#endif

// original version of this library incorrectly labeled LCD_DATA0 as LCD_DATA4,
// LCD_DATA1 as LCD_DATA5, and so on.  this block of code makes the driver
// compatible with any code written for the original library
#if (defined(LCD_DATA0) && defined(LCD_DATA1) && defined(LCD_DATA2) && defined(LCD_DATA3) && !defined(LCD_DATA4) && !defined(LCD_DATA5) && !defined(LCD_DATA6) && !defined(LCD_DATA7))
   #define  LCD_DATA4    LCD_DATA0
   #define  LCD_DATA5    LCD_DATA1
   #define  LCD_DATA6    LCD_DATA2
   #define  LCD_DATA7    LCD_DATA3
#endif

#ifndef LCD_DATA4
#ifndef LCD_DATA_PORT
   #if defined(__PCB__)
      #define LCD_DATA_PORT      0x06     //portb
      #define set_tris_lcd(x)   set_tris_b(x)
   #else
     #if defined(PIN_D0)
      #define LCD_DATA_PORT      getenv("SFR:PORTD")     //portd
     #else
      #define LCD_DATA_PORT      getenv("SFR:PORTB")     //portb
     #endif
   #endif   
#endif

#if defined(__PCB__)
   LCD_PIN_MAP lcd, lcdlat;
   #byte lcd = LCD_DATA_PORT
   #byte lcdlat = LCD_DATA_PORT
#elif defined(__PCM__)
   LCD_PIN_MAP lcd, lcdlat, lcdtris;
   #byte lcd = LCD_DATA_PORT
   #byte lcdlat = LCD_DATA_PORT
   #byte lcdtris = LCD_DATA_PORT+0x80
#elif defined(__PCH__)
   LCD_PIN_MAP lcd, lcdlat, lcdtris;
   #byte lcd = LCD_DATA_PORT
   #byte lcdlat = LCD_DATA_PORT+9
   #byte lcdtris = LCD_DATA_PORT+0x12
#elif defined(__PCD__)
   LCD_PIN_MAP lcd, lcdlat, lcdtris;
   #word lcd = LCD_DATA_PORT
   #word lcdlat = LCD_DATA_PORT+2
   #word lcdtris = LCD_DATA_PORT-0x02
#endif
#endif   //LCD_DATA4 not defined

#ifndef LCD_TYPE
   #define LCD_TYPE 2           // 0=5x7, 1=5x10, 2=2 lines
#endif

#ifndef LCD_LINE_TWO
   #define LCD_LINE_TWO 0x40    // LCD RAM address for the second line
#endif

BYTE const LCD_INIT_STRING[4] = {0x20 | (LCD_TYPE << 2), 0xc, 1, 6};
                             // These bytes need to be sent to the LCD
                             // to start it up.

BYTE lcd_read_nibble(void);

BYTE lcd_read_byte(void)
{
   BYTE low,high;

 #if defined(__PCB__)
   set_tris_lcd(LCD_INPUT_MAP);
 #else
  #if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
   output_float(LCD_DATA4);
   output_float(LCD_DATA5);
   output_float(LCD_DATA6);
   output_float(LCD_DATA7);
  #else
   lcdtris.data = 0xF;
  #endif
 #endif
        
   lcd_output_rw(1);
   delay_cycles(1);
   lcd_output_enable(1);
   delay_cycles(1);
   high = lcd_read_nibble();
      
   lcd_output_enable(0);
   delay_cycles(1);
   lcd_output_enable(1);
   delay_us(1);
   low = lcd_read_nibble();
      
   lcd_output_enable(0);

 #if defined(__PCB__)
   set_tris_lcd(LCD_INPUT_MAP);
 #else
  #if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
   output_drive(LCD_DATA4);
   output_drive(LCD_DATA5);
   output_drive(LCD_DATA6);
   output_drive(LCD_DATA7);
  #else
   lcdtris.data = 0x0;
  #endif
 #endif

   return( (high<<4) | low);
}

BYTE lcd_read_nibble(void)
{
  #if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
   BYTE n = 0x00;

   /* Read the data port */
   n |= input(LCD_DATA4);
   n |= input(LCD_DATA5) << 1;
   n |= input(LCD_DATA6) << 2;
   n |= input(LCD_DATA7) << 3;
   
   return(n);
  #else
   return(lcd.data);
  #endif
}

void lcd_send_nibble(BYTE n)
{
  #if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
   /* Write to the data port */
   output_bit(LCD_DATA4, bit_test(n, 0));
   output_bit(LCD_DATA5, bit_test(n, 1));
   output_bit(LCD_DATA6, bit_test(n, 2));
   output_bit(LCD_DATA7, bit_test(n, 3));
  #else      
   lcdlat.data = n;
  #endif
      
   delay_cycles(1);
   lcd_output_enable(1);
   delay_us(2);
   lcd_output_enable(0);
}

void lcd_send_byte(BYTE address, BYTE n)
{
   lcd_enable_tris();
   lcd_rs_tris();
   lcd_rw_tris();

   lcd_output_rs(0);
   while ( bit_test(lcd_read_byte(),7) ) ;
   lcd_output_rs(address);
   delay_cycles(1);
   lcd_output_rw(0);
   delay_cycles(1);
   lcd_output_enable(0);
   lcd_send_nibble(n >> 4);
   lcd_send_nibble(n & 0xf);
}

void lcd_init(void) 
{
   BYTE i;

 #if defined(__PCB__)
   set_tris_lcd(LCD_OUTPUT_MAP);
 #else
  #if (defined(LCD_DATA4) && defined(LCD_DATA5) && defined(LCD_DATA6) && defined(LCD_DATA7))
   output_drive(LCD_DATA4);
   output_drive(LCD_DATA5);
   output_drive(LCD_DATA6);
   output_drive(LCD_DATA7);
  #else
   lcdtris.data = 0x0;
  #endif
   lcd_enable_tris();
   lcd_rs_tris();
   lcd_rw_tris();
 #endif

   lcd_output_rs(0);
   lcd_output_rw(0);
   lcd_output_enable(0);
    
   delay_ms(15);
   for(i=1;i<=3;++i)
   {
       lcd_send_nibble(3);
       delay_ms(5);
   }
    
   lcd_send_nibble(2);
   for(i=0;i<=3;++i)
      lcd_send_byte(0,LCD_INIT_STRING[i]);
}

void lcd_gotoxy(BYTE x, BYTE y)
{
   BYTE address;
   
   if(y!=1)
      address=LCD_LINE_TWO;
   else
      address=0;
     
   address+=x-1;
   lcd_send_byte(0,0x80|address);
}

void lcd_putc(char c)
{
   switch (c)
   {
      case '\f'   :  lcd_send_byte(0,1);
                     delay_ms(2);
                     break;
                     
      case '\n'   : lcd_gotoxy(1,2);        break;
     
      case '\b'   : lcd_send_byte(0,0x10);  break;
     
      default     : lcd_send_byte(1,c);     break;
   }
}
 
char lcd_getc(BYTE x, BYTE y)
{
   char value;

   lcd_gotoxy(x,y);
   while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low
   lcd_output_rs(1);
   value = lcd_read_byte();
   lcd_output_rs(0);
   
   return(value);
}

Here are my codes for reading the voltage and displaying the result on the LCD:
PHP:
#include "16f876a.h"
#device adc=10
#fuses HS,NOWDT,NOLVP,NOCPD
#use delay(clock=4M)
#include "lcd.c"
int value;
float value1,value2;

#define LCD_ENABLE_PIN   PIN_C2                                   
#define LCD_RS_PIN       PIN_C0                                  
 #define LCD_RW_PIN      PIN_C1                                   
 #define LCD_DATA4       PIN_C3                                   
#define LCD_DATA5        PIN_C4                                   
 #define LCD_DATA6       PIN_C6                                   
 #define LCD_DATA7       PIN_C7


void main()
{
	set_tris_A(0xff);
	set_tris_B(0x00);
	set_tris_C(0x00);
	
setup_comparator(NC_NC_NC_NC);
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(ALL_ANALOG);
set_adc_channel(0);
setup_vref(FALSE);
delay_us(100);
printf(lcd_putc,"\fKKK");

delay_ms(1500);

	lcd_init();
   lcd_gotoxy(1,1);
	
	while(1)
	{
	delay_us(20);
	read_adc(adc_start_only);
	delay_us(100);
	value=read_adc(adc_read_only);
	value1=value*500*6/1023;
	value2=value1;	
  

	delay_ms(50);
	printf(lcd_putc,"\f%.3f",value2);
	delay_ms(1500);
	
		}
	
	
	}

The circuit which I am simulating with in Proteus is here attached.


Thanks.
 

Attachments

  • DVMLCD876.zip
    21.1 KB · Views: 121

Try this code.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "16f876a.h"
 
#device adc=10
 
#fuses XT,NOWDT,NOLVP,NOCPD
 
#use delay(clock=4M)
 
 
#define LCD_ENABLE_PIN  PIN_C2
#define LCD_RS_PIN      PIN_C0
#define LCD_RW_PIN      PIN_C1
#define LCD_DATA4       PIN_C4
#define LCD_DATA5       PIN_C5
#define LCD_DATA6       PIN_C6
#define LCD_DATA7       PIN_C7
 
#include "lcd.c"
 
int value;
float value1,value2;
 
void main()
{
    set_tris_a(0xff);
    set_tris_b(0x00);
    set_tris_c(0x00);
    
    setup_comparator(NC_NC_NC_NC);
    setup_adc(ADC_CLOCK_INTERNAL);
    setup_adc_ports(AN0);
    set_adc_channel(0);
    setup_vref(FALSE);
 
 
    lcd_init();
    lcd_gotoxy(0,1);
    
    while(1)
    {
        delay_us(20);
        read_adc(adc_start_only);
        delay_us(100);
        value = read_adc(adc_read_only);
        value = value * 30.0 / 1023.0;
                
        printf(lcd_putc,"\f%7.3f",value);
        delay_ms(100);
    }    
}

 

Those codes are printing nothing, igot another LCD.C file which makes my circuit to display something but the calculations remain wrong,so can you please help me to convert the voltage read from the ADC to be well converter and be displayed on the screen.
the file is from **broken link removed**;so now help me to read good values for the voltage 0V-30V.


Thanks
 

Post your Proteus file and CCS C project files zipped. I can't create a new project just for testing.


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include "16f876a.h"
 
#device adc=10
 
#fuses XT,NOWDT,NOLVP,NOCPD
 
#use delay(clock=4M)
 
#define LCD_ENABLE_PIN  PIN_C2
#define LCD_RS_PIN      PIN_C0
#define LCD_RW_PIN      PIN_C1
#define LCD_DATA4       PIN_C4
#define LCD_DATA5       PIN_C5
#define LCD_DATA6       PIN_C6
#define LCD_DATA7       PIN_C7
 
#include "lcd.c"
 
float volt, oldval = 0.0;
 
void main()
{
    set_tris_a(0xff);
    set_tris_b(0x00);
    set_tris_c(0x00);
    
    setup_comparator(NC_NC_NC_NC);
    setup_adc(ADC_CLOCK_INTERNAL);
    setup_adc_ports(AN0);
    set_adc_channel(0);
    setup_vref(FALSE);
  
    lcd_init();
    lcd_gotoxy(0,1);
    
    while(1)
    {
        delay_us(20);
        read_adc(adc_start_only);
        delay_us(100);
        volt = read_adc(adc_read_only);
        volt = volt * 30.0 / 1023.0;
                
        if(oldval != volt){
               printf(lcd_putc,"%7.3f", volt);
               oldval = volt;
        }
        delay_ms(100);
    }    
}

 
Last edited:

Hello,here is the zipped folder for ccs c project and proteus simulation.

Thanks.
 

Attachments

  • DVMLCD876A.zip
    48.5 KB · Views: 110

Hello, I am using the codes you posted above they are working but when I adjust a little bit the voltage on the dc power supply the LCD is not displaying the value automatically I have first to shut down the voltmeter (I shut it down I restart for reading the new values);how can I proceed for reading the value automatically without shutting down the system.

the codes are here
PHP:
#include "16f876a.h"
 
#device adc=10
 
#fuses XT,NOWDT,NOLVP,NOCPD
 
#use delay(clock=4M)
 
#define LCD_ENABLE_PIN  PIN_C2
#define LCD_RS_PIN      PIN_C0
#define LCD_RW_PIN      PIN_C1
#define LCD_DATA4       PIN_C4
#define LCD_DATA5       PIN_C5
#define LCD_DATA6       PIN_C6
#define LCD_DATA7       PIN_C7
 
#include "lcd.c"

 
//float volt, oldval,volt1 = 0.0;
float volt, oldval,volt1 ;
 
void main()
{
    set_tris_a(0xff);
    set_tris_b(0x00);
    set_tris_c(0x00);
    
    setup_comparator(NC_NC_NC_NC);
    setup_adc(ADC_CLOCK_INTERNAL);
    setup_adc_ports(AN0);
    set_adc_channel(0);
    setup_vref(FALSE);
  
    lcd_init();
    lcd_gotoxy(0,1);
    
    while(1)
    {
        delay_us(20);
        read_adc(adc_start_only);
        delay_us(100);
        volt = read_adc(adc_read_only);
        volt = volt * 30.0/ 1023.0;
                
       if(oldval != volt)

                 {
          delay_ms(1);
 				printf(lcd_putc,"\fDVM Shows:");
				delay_ms(1);
               printf(lcd_putc,"%3.1fV", volt);
               oldval = volt;
             delay_ms(1);
       }
       delay_ms(100);
    }    
}
I am using a Quartz of 4MHz;and some time the LCD is displaying differents symbols.

Please help on this

Thanks.
 
Last edited:

Hello,how may I proceed for getting 30V on the LCD;in simulation I am getting the rigth values but with physical implementation when I measure 30V I get 25.....V;what can I do?

I am using a voltage divider of 3.9Kohm and 750ohm.

Thanks.
 

I used 780Ohm and 3.9Kohm but the problem which is making the system to give me the wrong result is that with resistors only I get the good values,but when adding a zener diode the voltage drops to 4.2V so when multiplying 4.2V*6=25.2V (as the maximum).

I think if I try to change the resistors and use the one you told me I think the problem will be the same.

So how do you thionk may I correct thsi one by having 5V exactly with the zener diode connected?

Thanks,please help.
 

that is the one I am using.

- - - Updated - - -

I used 780Ohm and 3.9Kohm but the problem which is making the system to give me the wrong result is that with resistors only I get the good values,but when adding a zener diode the voltage drops to 4.2V so when multiplying 4.2V*6=25.2V (as the maximum).

I think if I try to change the resistors and use the one you told me I think the problem will be the same.

So how do you thionk may I correct thsi one by having 5V exactly with the zener diode connected?

Thanks,please help.
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…