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.

Error on AN0 PIC18F

Status
Not open for further replies.

mikesmixes777

New Member
I am using a PIC18LF2620. I currently have 3 analog inputs, RA0,RA1 and RA3.

The two values on RA1 and RA3 *edit* are reading correct. THe value I am getting on RA0 is wrong. There is 217mV on the input however my ADC value is 128 which using Vss=3.3V results in 412.3mV.

Is there a specail setting for AN0 which the other analog inputs dont have?

The portion of my code:
Code:
void read_a2d(unsigned int adc_ch)		//Read the A2D Inputs
{ 
	unsigned int adcbits;
	unsigned int adcbit0, adcbit1, adcbit2, adcbit3;
	
			switch (adc_ch)					
			{	
				case 0:			// Setup AN0 
				ADCON1 = 0b00001011;	//-Vref=Vdd, +Vref=Vss, AN0:An3 inputs,
				ADCON0 = 0b00000000;					
				ADCON2 = 0b10011010;	// (Fosc/32), 6 TAD	
				ADCON0bits.ADON = 1;	//Turn On ADC
				break;

			
				case 1:			// Setup AN1
				ADCON1 = 0b00001011;				
				ADCON0 = 0b00000100;				
				ADCON2 = 0b10011010;				
				ADCON0bits.ADON = 1;				
				break;								
			
				case 3:			// Setup AN3
				ADCON1 = 0b00001011;				
				ADCON0 = 0b00001100;				
				ADCON2 = 0b10011010;					
				ADCON0bits.ADON = 1;				
			}


	ADCON0bits.GO=1;
	while(ADCON0bits.GO)
	adctemp = ADRESH;
	adctemp = adctemp<<8;
	adcbits = adctemp|ADRESL;
	adcvalue = adcbits;
	adcvalue = ((adcbits*3.3)/(1023));

Many thanks
Mike
 
Last edited:
Have you tried increasing your acquisition time. Try doubling it to 12. (ADCON2=0b10101010;) Your impedance on that source may be higher.

Mike.
 
Code:
while(ADCON0bits.GO)
	adctemp = ADRESH;

You're retrieving the ADRESH value while the conversion is not finished yet.
A semi-colon is missing there!
 
Good catch eng1, but why would that only effect AN0? It probably is the cause of the problem, I'm just curious as to why it only effects channel zero.

And, wouldn't the only error be in the LSB.

Mike.
 
Hi Eng1,
I put the semi-colon in and its still the same. it didnt seem to change anything...

However...Doubling the acquisition time seemed to do it. Thanks Pommie.

So now what do i do with the semi-colon? I seem to remember a while() loop having no semicolon...i could be wrong since i only been doing C for like 2months ;)
 
While we on the topic, I have now connected a LM35 sensor to AN0.
AN1 and AN3 are 0-3Vdc

What I have done in the code, as you can see, is extract each value of the "converted" voltage and then send each of those values to the usart.

It is a general function as I pass the necessary ADC channel. The problem is that now the Temperature value (AN0) is different as its decial format is different.

What/How would you suggest that i do to seperate these conversions in the most practical and simplest way?

Code:
void read_a2d(unsigned int adc_ch)			//Read the A2D Inputs
{ 
	unsigned int adcbits;
	unsigned int adcbit0, adcbit1, adcbit2, adcbit3;
	char buf[14];
	
			switch (adc_ch)					
			{	
				case 0:			// Setup AN0 
				ADCON1 = 0b00001011;	//-Vref=Vdd, +Vref=Vss, AN0:An3 inputs,
				ADCON0 = 0b00000000;					
				ADCON2 = 0b10101010;	// (Fosc/32), 12 TAD (LM35 needs longer time, higher impedance)
				ADCON0bits.ADON = 1;	//Turn On ADC
				break;

			
				case 1:			// Setup AN1
				ADCON1 = 0b00001011;				
				ADCON0 = 0b00000100;				
				ADCON2 = 0b10101010;				
				ADCON0bits.ADON = 1;				
				break;								
			
				case 3:			// Setup AN3
				ADCON1 = 0b00001011;				
				ADCON0 = 0b00001100;				
				ADCON2 = 0b10101010;					
				ADCON0bits.ADON = 1;				
			}


	ADCON0bits.GO=1;
	while(ADCON0bits.GO);
	adctemp = ADRESH;
	adctemp = adctemp<<8;
	adcbits = adctemp|ADRESL;
	adcvalue = adcbits;
	adcvalue = ((adcbits*3.3)/(1023));

	adcvalue = adcvalue*1000;												// Multiply by 1000 to include 3 d.p's
	adcbits = adcvalue;												// Force interger value xxxx.0000
	adcbits = adcvalue;
	
	adcbit0 = adcbits;
	adcbit0 = adcbit0/1000;				// Extract "thousands" value
	adcbit1 = adcbits-(adcbit0*1000);
	adcbit1 = adcbit1/100;				// Extract "hundreds" value
	adcbit2 = adcbits-((adcbit0*1000)+(adcbit1*100));
	adcbit2 = adcbit2/10;				// Extract "tens" value
	adcbit3 = adcbits-((adcbit0*1000)+(adcbit1*100) + (adcbit2*10));		
	adcbit3 = adcbit3/1;				// Extract "singles" value ***Good Practice***

	write_usart(adcbit0+48);		        // Output to UART in ASCII
	write_usart('.');
	write_usart(adcbit1+48);
	write_usart(adcbit2+48);
	write_usart(adcbit3+48);
	write_usart(32);				// Space
	
}
 
Last edited:
Pommie said:
And, wouldn't the only error be in the LSB.
I think that it depends on how the A/D converter stores the results in the ADRESH and ADRESL registers. Is the result available partially before the conversion is finished? IIRC there is an application note that reveals some details of the ADC of PICs...


mikesmixes777 said:
However...Doubling the acquisition time seemed to do it. Thanks Pommie.
Glad to hear that it's working now!


mikesmixes777 said:
o now what do i do with the semi-colon? I seem to remember a while() loop having no semicolon...i could be wrong since i only been doing C for like 2months ;)
It depends on what you want to do. In this case you want to just waste time until the GO/DONE bit is cleared.
You can write:
while(ADCON1bits.GO==1);
while(ADCON1bits.GO);
while(ADCON1bits.GO==1){} // no semi-colon

but using the following instructions

while(ADCON1bits.GO)
adctemp = ADRESH;

is wrong because you keep storing the ADRESH value into adctemp before the conversion is finished and that could yield unexpected results.
 
Last edited:
A while loop will execute the code block that follows. The code block can be either nothing, 1 executable statement followed by a semicollon or a number of statements enclosed in braces.

So,
Code:
	while(1);		//No code block

	while(1)
		Somert;		//1 executable statement

	while(1){
		Somert1;	//lots of statements
		Somert2;
		Somert1;
	}

I don't understand your question about the LM35 it just outputs a voltage. How is this different?

Mike.
 
I don't understand your question about the LM35 it just outputs a voltage. How is this different?

I realise that the LM35 also puts out a voltage....:D Had temperature on my mind...

I will try explain better...

I am displaying the values, after conversion, on the RS232 port.

At the moment I am using a routine to "format" all three results and send them to the usart.
Now with the LM35, the result needs to be formatted differently to the other two voltage inputs.

Currently the format is three decimal places, i.e. 2.173 Volts, however if i send the LM35 value to the usart it prints 0.217 when I want it to print 21.7 to represent the temperature (celcius).

What i need help on is the best way to go about creating functions for each analog input and then within the function have the correct formatting for the usart? Bare in mind that I can call this function anywhere in the code

i.e.
Code:
read_a2d(1);

I think my brain is slowing down....cant seem to put what i am thinking into words.:confused:
 
Currently the format is three decimal places, i.e. 2.173 Volts, however if i send the LM35 value to the usart it prints 0.217 when I want it to print 21.7 to represent the temperature (celcius).
Before you send it why don't you do Value+=100;

Mike.
 
I'll put an if(adc_ch==0) then adcvalue*=100;

I'm busy trying it but i seem to be getting weired values...

Ok its working...Thanks
 
Last edited:
Hi, i do realize that its been a long time when you started this thread. However i am stuck in the same place.

I have attached the image of what i am getting in simulation with this. Is there a way to fix the warning. I have used your same code.

Can you please tell me the value for TRISA and AN0, AN1 and AN3 aswell.
 

Attachments

  • Untitled.jpg
    Untitled.jpg
    263 KB · Views: 192
Last edited:
Tip for all... when dealing with more than 1 ANx pin.. Set the pins as input ... when ever you are going to get the value of another pin turn off the ADC then set the ADCON pin then turn it back on. This will save headaches...
 
I am only getting values either 0.000 or 1.000 but nothing in between for extreme temperatures (on Proteus).

Here is the code i have modified (from yours):

#include <p18cxxx.h>
#include <delays.h>
#include <usart.h>

#pragma config WDT = OFF

void read_a2d(unsigned int adc_ch) //Read the A2D Inputs
{
switch (adc_ch)
{
case 0: // Setup AN0
ADCON1 = 0b00001011; //-Vref=Vdd, +Vref=Vss, AN0:An3 inputs,
ADCON0 = 0b00000000;
ADCON2 = 0b10101010; // (Fosc/32), 12 TAD (LM35 needs longer time, higher impedance)
ADCON0bits.ADON = 1; //Turn On ADC
break;

case 1: // Setup AN1
ADCON1 = 0b00001011;
ADCON0 = 0b00000100;
ADCON2 = 0b10101010;
ADCON0bits.ADON = 1;
break;

case 3: // Setup AN3
ADCON1 = 0b00001011;
ADCON0 = 0b00001100;
ADCON2 = 0b10101010;
ADCON0bits.ADON = 1;
}
}

void SendData(unsigned char data)
{
while(BusyUSART());
WriteUSART(data);
while(BusyUSART());
}

void main(void)
{
unsigned int adcbits, adcbit0, adcbit1, adcbit2, adcbit3;
unsigned char adctemp,adcvalue;

TRISB = 0x00;
TRISA = 0x01;
TRISC = 0b11000000;
TRISD = 0x00;
TRISE = 0b000;
PORTA = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;

read_a2d(0);

OpenUSART (
USART_TX_INT_OFF &
USART_RX_INT_ON &
USART_ASYNCH_MODE &
USART_EIGHT_BIT &
USART_CONT_RX &
USART_BRGH_HIGH, 25
);

while(1)
{
ADCON0bits.GO=1;
while(ADCON0bits.GO);
adctemp = ADRESH;
adctemp = adctemp<<8;
adcbits = adctemp|ADRESL;
adcvalue = adcbits;
adcvalue = ((adcbits*3.3)/(1023));

adcvalue = adcvalue * 1000; // Multiply by 1000 to include 3 d.p's
adcbits = adcvalue; // Force interger value xxxx.0000
adcbit0 = adcbits;
adcbit0 = adcbit0/1000; // Extract "thousands" value
adcbit1 = adcbits-(adcbit0*1000);
adcbit1 = adcbit1/100; // Extract "hundreds" value
adcbit2 = adcbits-((adcbit0*1000)+(adcbit1*100));
adcbit2 = adcbit2/10; // Extract "tens" value
adcbit3 = adcbits-((adcbit0*1000)+(adcbit1*100) + (adcbit2*10));
adcbit3 = adcbit3/1; // Extract "singles" value ***Good Practice***

SendData(adcbit0+48); // Output to UART in ASCII
SendData('.');
SendData(adcbit1+48);
SendData(adcbit2+48);
SendData(adcbit3+48);
SendData(32); // Space
Delay10KTCYx(60);
}
}
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top