The ADC module's resolution is up to 10-bit, yield an acceptable measuring accuracy with the voltage within 50 V DC.
In this example, I use this ADC module to measure a DC voltage within -25 V to +25 V. So the total voltage magnitude is 50 V.
Since the maximum reference voltage is 5 V in magnitude. I use a voltage divider circuit to scale the input voltage to the lower 5 V.
From the voltage divider:
The V(ADC) is at 5 V maximum. V(MEASURE) could be 50 V in magnitude. So we divide the V(MEASURE) by 11.
But in the program simulation I don't use 11. I use 9 because it cause a lot of error.
In the real hardware test, you can try 11.
The voltmeter display the measuring voltage on a five-digit multiplexed SSD. The ADC reading is scheduled every one second due the timer 0 scheduling. The analog DC input voltage is fed from a -25 V and +25 V voltage terminals, giving a 50 V DC magnitude.
Schematic diagram a digital two poles voltmeter. A POT used for adjusting the analog input voltage, varies from -25 V to +25 V. |
Source code:
#include<xc.h>
// PIC16F887 Configuration Bit Settings
// CONFIG1
#pragma config FOSC = XT
#pragma config WDTE = OFF
#pragma config PWRTE = OFF
#pragma config MCLRE = ON
#pragma config CP = OFF
#pragma config CPD = OFF
#pragma config BOREN = ON
#pragma config IESO = ON
#pragma config FCMEN = ON
#pragma config LVP = ON
// CONFIG2
#pragma config BOR4V = BOR40V
#pragma config WRT = OFF
/*_XTAL_FREQ use for __delay*/
#define _XTAL_FREQ 4000000
void driveDisplays( int analogRead){
unsigned char ssd[16]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,
0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
float voltage;
int _voltage;
/*Voltage Calculation total reference is
+5V with centered ground*/
voltage=((5.0*((float)(analogRead)/1024))-2.5)/9.1;
//voltage/=11;
_voltage=(int)(voltage*10000);
/*Check negative voltage*/
if(_voltage&0x8000){
_voltage=-_voltage;
PORTD=0x00;
PORTC=0x40;
PORTD=0x01;
__delay_ms(10);
}
/*Decimal Place*/
PORTD=0x00;
PORTC=ssd[_voltage/1000];
if(_voltage>=1000)
PORTD=0x02;
__delay_ms(10);
/*Floating point*/
PORTD=0x00;
PORTC=ssd[(_voltage%1000)/100]|0x80;
PORTD=0x04;
__delay_ms(10);
PORTD=0x00;
PORTC=ssd[(_voltage%100)/10];
PORTD=0x08;
__delay_ms(10);
PORTD=0x00;
PORTC=ssd[_voltage%10];
PORTD=0x10;
__delay_ms(10);
}
int readADC(void){
GO=1;
while(GO);
return (ADRESH<<8)+ADRESL;
}
void portInit(void){
/*Analog and digital Port
Configuration*/
PORTB=0x00;
PORTC=0x00;
PORTD=0x00;
/*RB4 for analog input*/
TRISB4=1;
TRISC=0x00;
TRISD=0x00;
}
void adcInit(void){
/*Select external Voltage reference
+2.5V to -2.5V*/
VCFG1=1;
VCFG0=1;
/*Result is right justify*/
ADFM=1;
/*By default is analog,
but again set it to analog*/
ANS11=1;
/*Select FRC Clock of ADC module*/
ADCON0bits.ADCS=0x03;
/*Turn on ADC Module*/
ADON=1;
/*Select AN11 RB4*/
ADCON0bits.CHS=0x0B;
/*initiate a conversion*/
GO=1;
/*Wait until GO=0 "done"*/
while(GO);
}
void timerInit(void){
/*Select FOSC*/
T0CS=0;
/*Select timer 0 Prescaler*/
PSA=0;
/*Enable Timer 0 Overflow
interrupt*/
T0IE=1;
/*Turn on Global interrupt
Control*/
GIE=1;
/*Clear interrupt flage*/
T0IF=0;
/*Clear timer 0 register*/
TMR0=0;
}
int adcResult;
int counter=0;
void main(void){
portInit();
adcInit();
timerInit();
while(1){
driveDisplays(adcResult);
}
}
void interrupt _ISR(void){
if(T0IF){
counter++;
T0IF=0;
}
/* If it's one second*/
if(counter>=15){
adcResult=readADC();
counter=0;
}
}
A screen shot shows a positive voltage reading 24.84 V nearest to the positive terminal. |
A screen shot shows a negative voltage reading -24.89 V nearest to the negative terminal. |
No comments:
Post a Comment