PIC ADC issue

I am working on ADC with PIC16F1829 and have an issue understanding where the error appears. I wrote a function that samples analogue signal allowing sufficient acquisition time.

1
2
3
4
5
6
  unsigned int ADC(void){
	__delay_ms(1); // wait the required acquisition time
	GO_nDONE = 1;
	while(GO_nDONE);
	return ((ADRESH << 8) + ADRESL);	
}


The result is 10 bit long which I then pass into the function that lights up corresponding LEDs. However, it never seems to reach 1023 (3FFh) value. Data sheet for this particular uC specifies that maximum impedance for an analogue source shouldn't be greater than 10k Ohm which is fine since that is exactly what I am using. I used a debugger to check ADRESH and ADRESL SFR's and what i found out was : 0x03 and 0xDE which implies that it doesn't sweep through the entire voltage range. I used multimeter to check the input voltage from the uC which happens to be - 4.78V. When i turn the dial one way - the voltage seen across the POT is 0V. However, when I turn it the other way the voltage seen is ~4.3V which is not exactly the reference voltage from the uC. Why is this the case... Any help, please.
Line 4 will be an endless loop because of the trailing ;
Line 4 will be an endless loop because of the trailing ;
Sine the OP is getting results, GO_nDONE is probably a memory mapped register that triggers the ADC.

This is hardware, things vary. Whatever conditions will generate exactly 3FFh, it appears that you aren't hitting them. Maybe the ambient temperature needs to be higher, maybe the impedance needs to be a little lower. Or maybe you're right and the microcontroller is faulty. Can you try another one?

You say you're using exactly 10k Ohms impedance. Really? Did you measure it? Resistors have a tolerance that's usually 5% or 1% as I recall. Are you sure that exactly 10k is the amount that the uC can handle? You might try going slightly lower.

Basically, you have to realize that you're dealing with the analog world. Voltage, impedance, timing, etc. are never exactly what they are supposed to be and your code must accommodate accordingly.

Why to highlight the 4th line as being endless one? It checks if the conversion has finished and then returns 10bit result. I don't want this process to terminate..

Unfortunately, I don't have another uC at the moment, but will try to obtain another one. dhayden, well yes there is a tolerance, but i just ignored it. The max resistance measured was 9.42k Ohms.

Also, I tried supplying 5 V to the POT from the external power supply and the problem seems to go away. It happens to work when the voltage is just over 4.7 V which is close enough to the reference voltage of the uC!
It seems that the problem indeed lies within hardware...
Last edited on
The max resistance measured was 9.42k Ohms.

So since the resistance is not 10k why would you expect the ATOD to give you the complete range?

Also, I tried supplying 5 V to the POT from the external power supply and the problem seems to go away.

I'm glad you said seems, because using a voltage higher than the reference will skew the results at best, and it may even harm the micro-controller.

Did you try to calculate the "voltage" that that something with 9.42k Ohms will produce using the 4.7v reference voltage? Do you know how to calculate the voltage for each possible bit value of your ATOD?

Well it does not need to be 10k exactly as far as I know. Vo = Vi(R2/(R2+R1)). If the POT wiper is turned on fully, Vo = 4.7(9.42k/(9.42k+ ~0)) which leads to ~4.7V regardless of what the tolerance of the POT is. Correct me if I am wrong.

I should have been more careful when said 5V. Once i figured that the conversion works i turned it down to just below Vref of the uC (~4.6 V).

Since the measured Vref from the uC is not 4.78V, but 4.3V for each bit there is (4.3 / 1023) = 4.2 mV. When i turn the POT fully the result tends to fluctuate (but never reaches 3FFh). From the ADRESH:ADRESL SFRs I can see that the value written is 001111011110 which happens to be 990 in binary. (1023 - 996) x 4.2mV = 0.113V. (The binary number varies)

So i probed the POT across (Vdd - Wiper) -- > 0.1V and (Wiper - GND) --> 4.25V. Which raises the question: why is there 0.1V still between Vdd and the POT wiper.
Last edited on
In addition, when external power supply is used for the potentiometer (4.71V), I observed the similar behaviour across (Vdd - Wiper) --> 0.99V and (Wiper - GND) --> 4.61. Although this time 4.61 is much closer, but still not the actual +Vref of the uC.
Since the measured Vref from the uC is not 4.78V, but 4.3V for each bit there is (4.3 / 1023) = 4.2 mV.

Shouldn't that be 1024 not 1023 since you have a 10 bit ATOD ( 0 to 1023) or 2024 discrete steps.

How do you have your pot connected? Have you tried a different pot, perhaps of differing values (1k, 5k?)?

Have you tried putting some caps into the circuit to aid holding the voltage constant.

You may be interested in the following links:

https://www.eetimes.com/document.asp?doc_id=1276974
http://www.ti.com/lit/an/spna061/spna061.pdf

By the way your ATOD is probably a successive approximation converter and these converters can be fairly noisy unless you take the proper precautions.



Oh and by the way be careful about how fast you're trying to read the voltage. Start by only reading the voltage a few times a second and see what happens.

jlb, you are right. It is 1024 I should have used. The connection is [Vdd] - [AnalogueIn] - [GND].

I have not tried smaller range pots, but should consider doing so. Unfortunately, don't have them handy with me.

Yeah, I used different caps already. Thanks for your help everyone I shall debug it further until it becomes clear!
Luckily, I found another POT with smaller impedance of 2kΩ. So i connected it, but this time the value written to ADRESH:ADRESL SFR's is : [0000 0011]:[1111 0011]. I think it has to do with the input voltage to the uC and the +Vref that ADC works with.
What is the value at the other end of the pot?
3mV
Eventually, it works. I decided to change the analogue channel that ADC was working on and the problem no longer persists. This time the value on the other side of the pot is 0V. Thanks everyone for your help!
Topic archived. No new replies allowed.