Recent Posts

Blogroll

                                          My PIC12F683 Development Board
Office Map Circuit diagram for each experiment may not be available separately because they are conducted with PIC12F683 development board that I made. So, the readers should first see the schematic of my development board.

Sunday, October 3, 2010

0-20V Digital Voltmeter (DVM) using PIC12F683

After finishing the serial LCD project, it is time to do some cool projects using PIC12F683. Now we can have a nice LCD display with PIC12F683. This project shows how to make a digital voltmeter of range 0-20V using PIC12F683. Enjoy!


Background
You cannot feed 20V  directly to a PIC I/O pin, you need a resistor divider network that converts 0-20V range into 0-5V. The figure below shows how it will be achieved.
At any instant, the voltage Va will be 1/4th of the input voltage, Vin. So, for maximum input voltage of 20V, the Va will be 5V. A 5.1V Zener diode in the figure is to prevent Va to rise above 5.1V if the input voltage goes much above 20V. This will protect the microcontroller port. The analog voltage Va is read through AN0 port and is converted to 10-bit digital number (0-1023) by PIC12F683.


ADC Math
     0-5V Analog I/P ---> 0-1023 Digital Count
=> Resolution = (5-0)/(1023-0) = 0.00489 V/Count
=> I/P voltage = 4*Va = 4* Digital Count * 0.00489 = 0.01956 * Digital Count

To avoid floating point, use I/P voltage = 196*Digital Count. This number is a long integer.
Example, suppose
Vin = 13.6V. Then,
Va = 0.25*Vin = 3.4V
=> Digital Count = 3.4/0.00489 = 695
=> Calculated I/P Voltage = 196*695 = 136220 = 13.6V  (First 3 digits of 6 digit product)

Sources of error
The above math looks pretty easy but when you implement it, you will not errors in output measurements  because the above calculations are based on following ideal conditions:

  • Vcc supply voltage to PIC12F683 is exactly 5V,
  • R1 and R2 are exact 1.3K and 3.9K respectively

So, let's revise the math above with real figures. I measured the supply voltage to PIC and it is 5.02V. R1 and R2 are measured to be 1267 and 3890 Ohms. So this gives,

     0 - 5.02 V Analog I/P ---> 0-1023 Digital Count
=> Resolution = (5.02-0)/(1023-0) = 0.004907 V/Count
Va = 1267*Vin/(1267+3890) = 0.2457*Vin
=> I/P voltage = 4.07*Va = 4.07* Digital Count * 0.004907 
                       = 0.01997 * Digital Count 
                       = 0.02*Digital Count (Approx.)

To avoid floating point, use I/P voltage = 2*Digital Count. No need for Long integer.
Example, suppose 
Vin = 4.6V. Then, 
Va = 0.2457*Vin = 1.13V
=> Digital Count = 1.13/0.004907 = 230
=> Calculated I/P Voltage = 2*230 = 0460 = 04.6V  (First 3 digits of 4 digit product)

Circuit Setup
Connect the Va terminal in the above resistor network to AN0 (GP0) input of PIC12F683. Also connect the serial LCD the same way as we did in our 3-wire serial LCD project. Just maintain the same setup for display as shown below.


Software

 /* Digital Voltmeter and
 3-wire Serial LCD using 74HC595
 Rajendra Bhatt, Oct 3, 2010
*/

sbit Data_Pin at GP5_bit;
sbit Clk_Pin at GP1_bit;
sbit Enable_Pin at GP2_bit;

// Always mention this definition statement
unsigned short Low_Nibble, High_Nibble, p, q,  Mask, N,t, RS, Flag, temp;

void Delay_50ms(){
 Delay_ms(50);
}

void Write_LCD_Nibble(unsigned short N){
 Enable_Pin = 0;
 // ****** Write RS *********
 Clk_Pin = 0;
 Data_Pin = RS;
 Clk_Pin = 1;
 Clk_Pin = 0;
 // ****** End RS Write

 // Shift in 4 bits
 Mask = 8;
  for (t=0; t<4; t++){
   Flag = N & Mask;
   if(Flag==0) Data_Pin = 0;
   else Data_Pin = 1;
   Clk_Pin = 1;
   Clk_Pin = 0;
   Mask = Mask >> 1;
  }
  // One more clock because SC and ST clks are tied
  Clk_Pin = 1;
  Clk_Pin = 0;
  Data_Pin = 0;
  Enable_Pin = 1;
  Enable_Pin = 0;
}
// ******* Write Nibble Ends

 void Write_LCD_Data(unsigned short D){
 RS = 1; // It is Data, not command
 Low_Nibble = D & 15;
 High_Nibble = D/16;
 Write_LCD_Nibble(High_Nibble);
 Write_LCD_Nibble(Low_Nibble);
 }

void Write_LCD_Cmd(unsigned short C){
 RS = 0; // It is command, not data
 Low_Nibble = C & 15;
 High_Nibble = C/16;
 Write_LCD_Nibble(High_Nibble);
 Write_LCD_Nibble(Low_Nibble);
}

void Initialize_LCD(){
 Delay_50ms();
 Write_LCD_Cmd(0x20); // Wake-Up Sequence
 Delay_50ms();
 Write_LCD_Cmd(0x20);
 Delay_50ms();
 Write_LCD_Cmd(0x20);
 Delay_50ms();
 Write_LCD_Cmd(0x28); // 4-bits, 2 lines, 5x7 font
 Delay_50ms();
 Write_LCD_Cmd(0x0C); // Display ON, No cursors
 Delay_50ms();
 Write_LCD_Cmd(0x06); // Entry mode- Auto-increment, No Display shifting
 Delay_50ms();
 Write_LCD_Cmd(0x01);
 Delay_50ms();
}

void Position_LCD(unsigned short x, unsigned short y){
 temp = 127 + y;
 if (x == 2) temp = temp + 64;
 Write_LCD_Cmd(temp);
}

void Write_LCD_Text(char *StrData){
 q = strlen(StrData);
 for (p = 0; p < q; p++){
  temp = StrData[p];
  Write_LCD_Data(temp);
 }

}

char Message1[] = "DVM Project";
unsigned int ADC_Value, DisplayVolt;
char *volt = "00.00";

void main() {
CMCON0 = 7;  // Disable Comparators
TRISIO = 0b00001001;  // All Outputs, except GP0 and GP3
ANSEL = 0x01; // GP0 analog i/p

Initialize_LCD();
Position_LCD(1,3);
Write_LCD_Text(Message1);
Position_LCD(2,10);
Write_LCD_Data('V');

do {

 ADC_Value = ADC_Read(0);
 DisplayVolt = ADC_Value * 2;

 volt[0] = DisplayVolt/1000 + 48;
 volt[1] = (DisplayVolt/100)%10 + 48;
 volt[3] = (DisplayVolt/10)%10 + 48;
 volt[4] = DisplayVolt%10 + 48;
 Position_LCD(2,4);
 Write_LCD_Text(volt);
 delay_ms(100);
} while(1);

}


Testing
I tested my DVM with my variable power supply and also verified with another digital multimeter.




I hope you liked this project.

I have another version of this project that uses PIC16F688 and no serial LCD driver. If you are interested, find here.


36 comments:

johnson said...

The circuit diagram and the coding is really helpful to make a such great device and i want to say thanks to this post owner and tell him to post more interesting thing continuously.
-industrial lighting fixtures

Fabio said...

Great work Mr. Raj.
I am very thankful with your blog.
It is an excellent source of knowledge.
Thank you.
From Brazil.

Michael said...

Wow this is awesome. Keep up the great work and keep posting more stuff if you get time

Getzata said...

why when I use the source code in CCS MPLAB compilator I have eror ?
Can you give me .HEX file from this project ?

Raj said...

Compile it with mikroC. Download it free @ http://www.mikroe.com/eng/downloads/get/29/mikroc_pro_pic_2010_v415_setup.zip

Mau said...

I have simulated in ISIS from Proteus but it don't work fine.Anyone try it too?

malvin said...

hi frend,
i am a final year student of e/e engineering.i am workin on a final year project title multiple measurement system like resistor,voltage,current,temperature and pressure using lcd at the output.i need u to give me ideal on how to go about it...i went thru ur multimeter project and it seens almost same....pls i am waitin 4 ur reply.cheerio

Raj said...

This is not a multimeter project, it is just a voltmeter. You can do some research and extend it to your desired project. I would suggest you to use a bigger PIC like PIC16F877A that has enough I/O pins.
Check other similar projects:
http://embedded-lab.com/blog/?p=11
http://embedded-lab.com/blog/?p=396

Diego said...

Great project, i was looking for something like this. I have a couple of questions for you: Have you considered connecting an external clock and a precision reference to your unused pins to improve the accuracy? I guess it would only be usefull for measuring really low currents. Also, have you considered using an op-amp before gp0 to lower the impedance?

Raj said...

Yes, you are right. I am going to use an opamp to lower the source impedance in my next ohmmeter project that would measure a wide range of resistance values. I liked the idea of using a precision reference voltage too. Thanks.

firdaus said...

where the 4.07 com from..can u explain more..??

Raj said...

Va = 0.2457*Vin
Therefore, Vin = Va/0.2457 = 4.07*Va

Praveen Kumar J said...

hi raj ...im from bangalore.... and unfortunately im not finding pic12f683 microcontroller ic in my place,,,,can i pls know any alternatives for this....

Raj said...

Try this,
http://embedded-lab.com/blog/?p=396

It uses PIC16F688 microcontroller and does not require the shift register IC, 74HC595.

MiMi said...

This is great. Amazing project.

discounted digital board

ric said...

even when compling with mikroC i get a bunch of errors, what am i doing wrong?

Raj said...

What errors are you getting? Can you mention them here?

faizal said...

HI frnd, i thnk u r using mikroc instead of mikroc pro, dats y u r getting errors, i thnk most of the errors are from sbit and lcd initialization, dis program is for mikroc pro.

Praveen Kumar J said...

Even i'm getting some of the errors ,wen still building the above program using microC PRO for PIC ....
I see the errors as below and all of these errors are associated with the for loop in the void write_lcd_text

; expected,but 'temp' found
invalid expression
')' expected,but ';' found
'}'expected ';' found
specifier needed
invalid declarator expected '('or identifier
undeclared identifier 'Message1'in expression
implicit conversionof int to ptr

Praveen Kumar J said...

@Raj
{
q = strlen(StrData);
for (p = 0; p
temp = StrData[p];
Write_LCD_Data(temp);
}

}

In the above loop after intialising p=0;...why is p coming again ? ,The for loop braces are not closed and why have you closed two curly braces...and wat does the last closed curly braces for?

Raj said...

Praveen,
It was format problem with blogger. Try the new code now. It should work.

egomez_mx said...

Hi Raj, I'm a newby trying to build the digital voltmeter, do I need to build first the development board to program the PIC?, how do I connect the board to the PC?

Raj said...

@ egomez_mx
You need an external PIC programmer to load the firmware inside the microcontroller even if you build the development board. I would suggest you to build this one instead, it is my another DVM project.
http://embedded-lab.com/blog/?p=396

K said...

Hi Raj! Nice tutorial!

In fact I am writing this post because I have a question about the polarity of the AN0.

If you switch by mistake the polarity of the analog input, i.e., connect the +5V into the GND and 0V into the AN0. My guess is that you'll get a +10V into AN0, right? OR to be more precise you will power the AN0 input with a -5Voltage to +5Voltage.

I tried switching the polarity, without the zener, and the PIC popped like popcorn :D

How do you suggest to protect the PIC against polarity changes?

K said...

Problem solved. The zener protects against polarity changes.

jiwe said...

i dont understand this completely
volt[0] = DisplayVolt/1000 + 48;
volt[1] = (DisplayVolt/100)%10 + 48;
volt[3] = (DisplayVolt/10)%10 + 48;
volt[4] = DisplayVolt%10 + 48;

Raj said...

It is extraction of individual digit from a 4-digit decimal number. 48 is added to individual number to convert it to its ASCII equivalent, that is required to display it as a character on LCD. ASCII value of character 0 is 48, 1 is 49, 2 is 50, 3 is 51 and so on.

Socially Responsible - Akbar said...

TO: Mr.Raj
I am new to this blog but would like to thank you for posting / sharing a very good project.

Regards
A. Durrani

hanif halim said...

to mr raj.. i had a problem on my project..im doing a rpm meter driven by voltage project..it use a lm2917(frequency to voltage)..it will produce a voltage instead of frequency and the problem is i dont know how to joint the circuit with the lcd..can you guide me what type of pic that i can use to joint from the lm2927 to lcd display..can i use the type of pic that you use in the project above?

bns2003 said...

Thank you raj for this well documented project can we use fixed voltage reference 16F chip for more accuracy

farlind said...

can u give me a detail file.hope u can help me.thanks..please email to farlin1987@gmail.com

yus said...

hello mr raj,
im quite impressive with this project
i want to ask a question
can we use EASY 68K for the software to run the coding?

Aries1470 said...

Hi,
Can someone please tell me, why the comment:
CMCON0 = 7; // Disable Comparators
is needed?
I compiled for the '683, no problem. I compiled for the '675, of which also has the same/ similar specs, but it gives an error due to that.
Also, using 4 MHZ, for INTOSC, is that ok? (8 MHz for '684, 4 MHz for the '675).

Another question I have, is if I wanted to count up to 30v, what would the differences be? Like resistors and programming values.
If an amp counter was added, would that still be below the 2K free compiler limit?

I am just more comforatable using mikroBasic, since I do not know C or mikroC at all.

Thank you.

Subhendu Manna said...

Hi.Friend,
Can you give me .HEX file from this DVM project ?please email to subho254@gmail.com

Abdul Fatah said...

volt[0] = DisplayVolt/1000 + 48;
volt[1] = (DisplayVolt/100)%10 + 48;
volt[3] = (DisplayVolt/10)%10 + 48;
volt[4] = DisplayVolt%10 + 48;


what this mean...?

Manoj Arakulam said...

Hello Raj..

Please tell me the coding for a 0 to 2000 mVolt (0-2000 mV)? Without change the resistors.. Thank you

Post a Comment

Online Embedded Systems Lab

This online laboratory teaches you the fundamentals of microcontroller-based embedded system development through a series of laboratory exercises. Most of the time, students and hobbyists could not afford expensive development kits and software to learn these things. These tutorials are prepared such that you will be building microcontroller projects at a minimum cost. Check this out