Need help to convert code to show voltage as X,XX and not as XX,X

Status
Not open for further replies.

ggmssr

Member level 2
Joined
Oct 25, 2011
Messages
48
Helped
1
Reputation
2
Reaction score
1
Trophy points
1,288
Activity points
1,586
This is LED voltmeter with 3 digit and all works fine in format xx,xV. Today I need to measure up to 9,99V and how I can change source code to make this? Resolution its nice to sense 10mV. PIC is 16f676.

Code is here

Code:
#include <htc.h>
__CONFIG (FOSC_INTRCIO & MCLRE_OFF & BOREN_ON & CP_OFF & CPD_OFF & WDTE_OFF & PWRTE_ON ); 



#define SPORT PORTA
#define DPORT PORTC
const char SegCode[11] = {0x40,0x57,0x22,0x06,0x15,0x0C,0x08,0x56,0x00,0x04,0xFF};
	//                       0    1    2    3    4    5    6    7    8    9
const char Column[3]   = {0x02,0x01,0x04};
static char Segment[3] = {0x7f,0x7f,0x7f};	
static unsigned char ColCount=0x00;
void CPU_SETUP(void);
void Display(void);
void HTO7S(unsigned int Num);
void delayMs(int x);

unsigned int result;
unsigned int readAdc(void);
void interrupt  timer1_isr(void)
{
if(PIR1bits.TMR1IF==1)
{
PIR1bits.TMR1IF = 0;
	TMR1H=0xDF;
Display();
}
}
void main()
{		
	unsigned char i;
	
	CPU_SETUP();
	while(1)
	{			
		result=0;
		for (i=0;i<3;i++)
		{
			
			delayMs(1); 
			result=result+readAdc();
		}
				HTO7S(result/3);								
		
		delayMs(200);		    
	}
	
}

void CPU_SETUP()
{
	CMCON =0x07;		//Turn off comparator module
	ANSEL =0x8;			//AN3 as analog input
	ADCON1 =0x60; 		//clock/64
	ADCON0 = 0x8D;
   	TRISA=0b00011000;
   	PORTA=0x27;
   	TRISC=0b00000000;
   	PORTC=0x37;
   
   T1CON= 0x00;
  	TMR1H=0xDF;
   	INTCONbits.GIE =1;
	INTCONbits.PEIE=1;
	PIE1bits.TMR1IE =1;
 	T1CONbits.TMR1ON=1;
}
unsigned int readAdc()
{
unsigned int res;
ADCON0bits.GO_DONE =1;
while(ADCON0bits.GO_DONE ==1);
res=ADRESL+(ADRESH*0x100);
return(res);
}
//-------------------------------------
// Display routine
//-------------------------------------
void Display()
{
	PORTA = 0b00100111;	  // off all digits column and Segment G
	PORTC = 0b00111111;   // off segment a-f	

	

	if (ColCount>=3) 
	ColCount=0;
    	
	DPORT = Segment[ColCount];
	SPORT = ((Segment[ColCount] & 0b01000000)>>1) | (Column[ColCount]^0x07);
	ColCount++;				
}	

//--------------------------------------
// Convet HEX 2 byte to 7-Segment code
//--------------------------------------
void HTO7S(unsigned int Num)
{
	
	unsigned int res;

	res = ((30*Num)%1023)/100;
	if(res==10)
	{
	Num=Num+1;
	res=0;
	}
	Segment[2]=SegCode[res];

	res = (30*Num)/1023;
	Segment[1]=SegCode[res%10];

	Segment[0]=SegCode[res/10];
	if (Segment[0]==0x40) 
	Segment[0]=0xFF;	
	
}	

void delayMs(int x)
{
int i;
for (x ;x>0;x--)
{
for (i=0;i<=110;i++);
}
}
 

I hope that is ok if I post this short post, and that will pass without warnings.

I make first two digits, first number and first decimal, but for 2 decimal I cannot find solution.

Code:
//--------------------------------------
// Convet HEX 2 byte to 7-Segment code
//--------------------------------------
void HTO7S(unsigned int Num)
{
	
	unsigned int res;
	
	res = ((9*Num)%1023)/100;		
	 if(res==10)
	 {
	 Num=Num+1;
	 res=0;
	 }
	
	
	Segment[2]=SegCode[res];	  
	
	res = ((9*Num)%1023)/100;
	Segment[1]=SegCode[res];	

	res = (9*Num)/1023;	
	Segment[0]=SegCode[res];
	// if (Segment[0]==0x40) 
	// Segment[0]=0xFF;	
	
}
 

If I understand correctly you are trying to convert the ADC result (0-1023) to a voltage representation as ASCII.

You seem to be mixing the conversion steps which messes things up.
First calculate the ADC voltage , use
Code:
voltage = adc_result * Vref / 1023;   // for 10bit ADC

Then convert the voltage to ASCII
Code:
voltage=1234;
char lcd[6];

lcd[0]=voltage/1000;		// first digit
lcd[1]=(voltage/100) % 10;	// second digit
lcd[2]=(voltage/10) % 10;	// third digit
lcd[3]=(voltage) % 10;		// fourth digit

lcd[0] +='0'; convert integer to ASCII;
lcd[1] +='0'; convert integer to ASCII;
lcd[2] +='0'; convert integer to ASCII;
lcd[3] +='0'; convert integer to ASCII;

//the result will be "1234"

or
Code:
voltage=1234;
char lcd[6];

lcd[0]=voltage/1000;		// first digit
lcd[1]=(voltage/100) % 10;	// second digit
lcd[2]='.';					// dot
lcd[3]=(voltage/10) % 10;	// third digit
lcd[4]=(voltage) % 10;		// fourth digit

lcd[0] +='0'; convert integer to ASCII;
lcd[1] +='0'; convert integer to ASCII;
lcd[3] +='0'; convert integer to ASCII;
lcd[4] +='0'; convert integer to ASCII;

//the result will be "12.34"

For different ADC ranges change the code accordingly
 
Reactions: ggmssr

    ggmssr

    Points: 2
    Helpful Answer Positive Rating
if you dont mind plz explain the whole code , i am a beginner in embedded field, I am also searching for a code for measuring voltage.
 


This code from first post is for 7-seg LED display, and works with 3 7-seg digit, all works fine for voltage range from 0 to 30V in format 30,0 25,3 13,8 7,3 ... and I want now to modify this code to measure up to 9,99 with two decimals, and if possible to increase resolution, I think now is around 45mV for 3-digit. It will be fine that new code can sense second decimal for Li-Ion battery 4,21 3,95 3,74 ....

dp led on 7-seg is connected always in original circuit on second digit, now will be on first digit.
 

I thought it was for LCD :roll:

still I think you can use the code I have provided and just ignore the last lines that convert the digit to ASCII.

- - - Updated - - -

For example

Code:
voltage=123;

Segment[0]=(voltage/100) % 10;	// first digit
Segment[1]=(voltage/10) % 10;	// second digit
Segment[2]=(voltage) % 10;		// third digit
 
Reactions: ggmssr

    ggmssr

    Points: 2
    Helpful Answer Positive Rating
I dont have success.


This code works but only for first two digits, and I cant adjust third.

Code:
	res = (9*Num)/1023;	
	Segment[0]=SegCode[res];
	
	res = ((9*Num)%1023)/100;
	Segment[1]=SegCode[res];	

	res = ((9*Num)/1023);
	Segment[2]=SegCode[res];

For this code I get >

voltage is 7,93 and on display i get 797



For this code >

Code:
	res = (9*Num)/1023;	
	Segment[0]=SegCode[res];
	
	res = ((9*Num)%1023)/100;
	Segment[1]=SegCode[res];	

	res = ((9*Num)%1023)/1000;
	Segment[2]=SegCode[res];

Voltage is 7,93 and on display I get 790



for this code I get 008 on display and voltage is 7,93

Code:
	res = (9*Num)/1023;	
	Segment[0]=SegCode[res];
	
	res = ((9*Num)%1023)/100;
	Segment[1]=SegCode[res];	

	res = ((9*Num)%1023)/10;
	Segment[2]=SegCode[res];
 

I'm not sure what you are doing in your code , what I suggested is

Calculate the voltage from the ADC result using
Code:
voltage = adc_result * Vref / 1023;   // for 10bit ADC

What is your Vref , is it 5v?
What is the resolution of the ADC , is it 10bit (0-1023)?

If so then you can use
Code:
unsigned int voltage=0;

voltage = adc_result * (unsigned long)5000 / 1023;   // for 10bit ADC, using Vref=5000mV, result in mV

Segment[0]=(voltage/1000);	// first digit
Segment[1]=(voltage/100) % 10;	// second digit
Segment[2]=(voltage/10) % 10;		// third digit
 

Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…