|
|
View previous topic :: View next topic |
Author |
Message |
Omer
Joined: 26 Jul 2013 Posts: 6 Location: United States
|
Analog Input reading problem |
Posted: Wed Nov 04, 2015 2:57 am |
|
|
I have a problem reading 2 Analog inputs on a PIC18F87K22 MCU. I need to read the Analog In 19/Pin G1 and 18/Pin G2. I have connected a 0-5VDC variable voltage source to these inputs and have a precision 5VDC source connected to VREF+/Pin27. Avdd is connected to VCC 5V, Avss is connected to Gnd/VSS. I'm reading input values on my PC via UART1. My PCH compiler version is 5.051.
The problem I'm having is with 0V at either or both of the inputs I read value 0 but when I connect say 2.5VDC the reading goes up to 95 and stays there. It should read 2048 since I set ADC=12. When I reduce the input to 0VDC the value goes down to 0. Anybody have any idea on what maybe wrong here? Here is my code:
Code: |
#include <18F87K22.h>
#device ADC=12
#FUSES NOWDT
#FUSES WDT128
#FUSES NOXINST
#FUSES NOBROWNOUT
#use delay(crystal=16000000)
#use rs232(baud=19200, UART1, ENABLE=PIN_C1, bits=8, stop=1, parity=N, stream=SERIAL1, errors)
int16 Temp_Read1; // Raw Temperature value
int16 Temp_Read2; // Raw Temperature value
#zero_ram
void main()
{
setup_adc_ports(sAN18|sAN19|VSS_VREF);
setup_adc(ADC_CLOCK_DIV_8|ADC_TAD_MUL_0);
while(TRUE){
printf("\r\nRead analog input channel:\r\n");
set_adc_channel(19);
delay_us(50);
Temp_Read1=read_adc();
delay_us(50);
set_adc_channel(18);
delay_us(50);
Temp_Read2=read_adc();
printf("\r\nTemp_Read1: %2Lu Temp_Read2: %2Lu\n\r",Temp_Read1,Temp_Read2);
delay_ms(500);
}
} |
+++++++++++++++++
Added code block.
- Forum Moderator
+++++++++++++++++ |
|
|
Omer
Joined: 26 Jul 2013 Posts: 6 Location: United States
|
Analog Input reading problem |
Posted: Wed Nov 04, 2015 3:20 am |
|
|
I just noticed I made an error in the printf format I changed the %2Lu to %5Lu but the problem still persists. Instead of the value 95 now I read 65520 continuously even though the input is at 0V. Weird! Any ideas?
Here is what I read on my PC using RealTerm:
Read analog input channel:
Temp_Read1: 65520 Temp_Read2: 65520
Read analog input channel:
Temp_Read1: 65520 Temp_Read2: 65520
Read analog input channel:
Temp_Read1: 65520 Temp_Read2: 65520
Read analog input channel:
Temp_Read1: 65520 Temp_Read2: 65520 |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19494
|
|
Posted: Wed Nov 04, 2015 5:14 am |
|
|
First, 9/10. You tell us everything we need to know, including compiler version, and a good description. Also including a short program. Hurrah. Except you forgot the code buttons in the original post. So nearly perfect.
Now there are several things about the pins, These are used by the ECCP3, EUSART2, and comparator 3. The ECCP PWM, and comparators in particular have the habit if interfering with other things, so explicitly disable these.
Then the number you are getting, looks to me as if the chip is possibly being configured to give the result 'left justified', so is giving the data as the top twelve bits, and seeing the value as -1 (remember this ADC supports differential operation, so can give -ve results). This is controlled by the ADFM bit, and this needs to be set to '1' for right justified operation. A quick look at the code generated, shows CCS leaving this bit unchanged, and the data sheet has it as defaulting to '0', which gives left justified operation. It looks as though this has been assumed to be set to '1' on boot (on many chips it is...). So you need to add (however see below!):
Code: |
#BIT ADFM=getenv("BIT:ADFM")
//then in your initialisation:
ADFM=TRUE; //right justify results
|
Then you are trying to set the ADC clock too fast. In table 23-1, the maximum frequency for Tosc/8, is given as 10Mhz. You need to be using /16, at 16MHz.
Interestingly as soon as I change the divider to /16, CCS starts setting the ADFM bit correctly!....
So with the clock rate set correctly, I can see the ANSEL bits being properly set-up, and all three AD registers correctly configured. The actual conversion and read all looks correct.
So
Code: |
void main()
{
setup_ccp3(CCP_OFF);
setup_comparator(NC_NC_NC_NC);
setup_adc_ports(sAN18|sAN19|VSS_VREF);
setup_adc(ADC_CLOCK_DIV_16|ADC_TAD_MUL_0);
while(TRUE)
{
fprintf(SERIAL1,"\r\nRead analog input channel:\r\n");
set_adc_channel(19,VSS); //shouldn't be needed, but be explicit in case
delay_us(50);
Temp_Read1=read_adc();
delay_us(50);
set_adc_channel(18,VSS);
delay_us(50);
Temp_Read2=read_adc();
fprintf(SERIAL1,"\r\nTemp_Read1: %Lu Temp_Read2: %Lu\n\r",Temp_Read1,Temp_Read2);
delay_ms(500);
}
}
|
Seems to set everything up correctly. |
|
|
Omer
Joined: 26 Jul 2013 Posts: 6 Location: United States
|
Analog Input Read problem solved |
Posted: Thu Nov 05, 2015 12:14 am |
|
|
Hi Ttelmah,
Thank you for your kind words and great support. I fixed the problem with your suggestions now I can read both analog input channels. However I had to set ADC_CLOCK_DIV_16 to ADC_CLOCK_DIV_2. With 16 setting the 2 channels interfered with each other in other words there was cross talk. I tried various settings and it worked best at setting 2. Don't know why but it worked so I'm happy
I did not know that I had to add the code buttons. I don't know what that is. I looked into the forum help but could not find any description.
Thanks again for your help!
Omer |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19494
|
|
Posted: Thu Nov 05, 2015 2:34 am |
|
|
The crosstalk will still be there. You are over-clocking the ADC, which has the effect of reducing it's accuracy (very significantly). You are probably only getting about an 7bit ADC, clocking it this fast. So this is hiding the noise.... |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Thu Nov 05, 2015 7:29 am |
|
|
You should try
setup_adc(ADC_CLOCK_DIV_16|ADC_TAD_MUL_4);
I have found this can improve the A/D performance even if you have the proper delay before reading the ADC. I haven't used this processor but I have used others in the k22 and k80 family where this helped. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19494
|
|
Posted: Thu Nov 05, 2015 8:20 am |
|
|
Yes. It is interesting. You will find that CCS won't actually give you a 0 Tad MUL. They will code as a _minimum_ of 1 on most of these processors. Actually pausing a little more at the start of the conversion using the Tad MUL ability often seems to reduce processor noise noticeably. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|