NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » ADC problem

September 02, 2012
by jmuthe
jmuthe's Avatar

I have been experimenting with the ADC part of the Microcontroller and something strange happens that I don't like. I created a program that first reads from ADC0 and ADC5 and displays both ADC values (from 0 to 1024)on the LCD. ADC0 is connected to the temperature sensor and ADC5 is connected to a 1 Kohm potentiometer. One end of the potentiometer is connected to the 5V source and the other end is connected to ground. By doing this, I could vary the voltage at ADC5 from 0 to 5 volts. The more clockwise I turn the pot, the more voltage goes to ADC5. I notice that when I turn the potentiometer counterclockwise (0V), everything on the LCD is displayed normally. However, as I turn the potentiometer more clockwise, it affects the LCD display reading for ADC0. I measured the voltage going to ADC0 and it is not changing but the LCD displayed values for ADC0 jumps all over the place. However, the LCD reading for ADC5 is always accurate and steady. Once I set the pot, the ADC5 reading does not change. Why does the voltage going to one ADC input affect the others reading and how do I stop that from happening?

September 03, 2012
by pcbolt
pcbolt's Avatar

jmuthe -

You might be pulling too much current when the pot is turned all the way up. In this state you are basically wiring the ADC5 pin directly to the 5v rail and puling a good deal of current. This draw may affect the current to the other pin. One thing to check is if you have the pot turned up, see if the voltage regulator gets hot. If so, you'll need to find a way to limit the current going to ADC5.

September 09, 2012
by jmuthe
jmuthe's Avatar

If that is the problem then how exactly do I limit the current but still keep the full 5 volts going to ADC5. One thing that I tried to do was use a bigger potentiometer (250 ohms) and also put it in series with a 10 Kohm resistor. By doing this, even if I put the pontentiometer at the maximum value, the current would still have to go through a 10 Kohm resistor. However, first of all it didn't work. The LCD display value for ADC0 still gets more and more jumpy, the higher I set the potentiometer to. The second problem with this method is that by connecting it this way, ADC5 will never get the full 5 volts because there will always be a voltage drop across the 10 Kohm resistor that would reduce the voltage going to ADC5. Anyway, how could I apply a full 5 volts to ADC5 but keep the current low?

September 09, 2012
by pcbolt
pcbolt's Avatar

jmuthe -

One thing that may work is a shunt resistor. You can put a low value resistor from your ADC5 pin to ground. This would make two paths for the current to flow into ground and since they are in parallel, the voltage should not be affected. The one thing that worries me with this approach is if the internal MCU circuitry produces any voltage on ADC5 it will be sunk to ground through the shunt resistor (I don't think this is the case).

The second thing you could try (and I wish I read this sooner) is to disable the ADC5 pin when making a measurement on ADC0. Something like this...

DIDR0 |= (1<<ADC5D)   // disable ADC5
// get measurement for tempsensor
DIDR0 &= ~(1<<ADC5D)  // enable ADC5
September 10, 2012
by Ralphxyz
Ralphxyz's Avatar

The second problem with this method is that by connecting it this way, ADC5 will never get the full 5 volts because there will always be a voltage drop across the 10 Kohm resistor that would reduce the voltage going to ADC5.

Once you know your readings it is very easy to scale the output in your code.

So if with your pot and resistor you get .5 volt at the minimum and 3.5 volt at the max essentially just display 3.5 as 5.

Actually it should not matter as long as you know what your potential outputs/actions will be just take what ever actions you would for any given situation.

Ralph

September 10, 2012
by jmuthe
jmuthe's Avatar

I think that the idea of disabling ADC5 seems to be the best idea but I can't seem to get that line of code to work. I iniitially wrote a program that simply reads the contents of ADC0 (from 0 to 1024) and outputs them on the LCD. The program worked just fine so I modified it to add the line "DIDR0 |= (1<<ADC0D);" to disable ADC0. According to the data sheet that line of code should disable ADC0 and cause it to display a 0 on the LCD. I added it just to test the disable code. However, when I ran the program, the LCD still displayed a value for ADC0. Basically, its like the disable code did nothing, so the program runs the same way it did before I entered that line of code. Here is a copy of the program I did. Could you tell me why the line "DIDR0 |= (1<<ADC0D);" isn't doing anything?

#include <stdio.h>

#include <math.h>

#include <avr/io.h>

#include <avr/interrupt.h>

#include <avr/pgmspace.h>

#include <inttypes.h>

#include "../libnerdkits/delay.h"

#include "../libnerdkits/lcd.h"

#include "../libnerdkits/uart.h"

int main() { uint16_t result;

lcd_init();

lcd_home();

ADMUX = 0; // set analog to digital converter for external //reference (5v), single ended input ADC0

ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // set analog to digital converter // to be enabled, with a clock prescale of 1/128 // so that the ADC clock runs at 115.2kHz.

while(1)

{

DIDR0 |= (1<<ADC0D); // disable ADC0

uint16_t low = ADCL;

uint16_t high = ADCH;

result = low + (high<<8);

ADCSRA |= (1<<ADSC);

lcd_line_one();

lcd_write_int16(result);

}

return 0;

}

September 11, 2012
by bretm
bretm's Avatar

Because DIDR0 |= (1<<ADC0D) doesn't disable the ADC, it disables the digital function of the pin so that it only functions as analog and not as a digital pin also.

September 11, 2012
by pcbolt
pcbolt's Avatar

Rats. I was hoping that would work (I guess I should have read the fine print like Bret did). You may have to go back to the shunt resistor idea using a low value resistor in parallel with your ADC pin. Bret...do you know the internal resistance of the I/O pins? I don't have the ATmega 168 datasheet at my disposal right now.

September 20, 2012
by jmuthe
jmuthe's Avatar

Okay, I am still working on the problem and my first question is for bretm. Could you clarify what you mean when you say "it disables the digital function of the pin so that it only functions as analog and not as a digital pin also"? If the ADC stands for an Analog to Digital Converter, then the input would always be analog. Why would it be digital at all.

In regards to the shunt reistor idea, it doesn't seem to work no matter how I connect the pot and resistor. First I tried connecting a 10 Kohm resistor directly to ADC5 so that ADC5 recieves 5 volts but would have its current limited by a resistor. That didn't work. It still caused the LCD values displayed from ADC0 to jump wildly. I've also hooked one end of the 10k resistor to 5V and the other end to terminal 1 of a 250 kohm potentiometer. The arm of the pot (or pin2) was connected to ADC5 and the other end terminal of the pot (pin 3) was connected to ground. Again, when I set the pot low, the value for ADC0 was steady and became jumpy when I set the pot higher. I also tried to connect pot pin 1 to 5 V, pot pin2 to ADC5, pin 3 to ground and then connect a 10 K reistor from ADC5 to ground. I got the same result. I noticed that when I set the pot all the way up it doesn't cause the regulator to get hot so maybe this isn't a current problem. Could you explain to me how exactly to connect the resistor and pot to ADC5 or maybe I have to connect the temperature sensor differently.

September 20, 2012
by jmuthe
jmuthe's Avatar

I've been thinking that maybe the problem could be my program. Here it is if you want to check it. Could you also tell me how to copy and paste lines of program without the line spacing looking so distorted. Unless, I fix it after I paste it, the whole code would be written in one long line.

define F_CPU 14745600

include <stdio.h>

include <math.h>

include <avr/io.h>

include <avr/interrupt.h>

include <avr/pgmspace.h>

include <inttypes.h>

include "../libnerdkits/delay.h"

include "../libnerdkits/lcd.h"

include "../libnerdkits/uart.h"

int main()

{

uint16_t result;

uint16_t result2;

lcd_home();

ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);

// set analog to digital converter // to be enabled, with a clock prescale of 1/128 // so that the ADC clock runs at 115.2kHz.

while(1)

{

ADMUX = 0; //set ADC0 as input

ADCSRA |= (1<<ADSC);

delay_ms(1000);

uint16_t low = ADCL;

uint16_t high = ADCH;

result = low + (high<<8);//value for ADC0

ADMUX = 5;//set ADC5 as input

ADCSRA |= (1<<ADSC);

delay_ms(1000);

low = ADCL;

high = ADCH;

result2 = low + (high<<8);//value for ADC5

lcd_init();

lcd_line_one();

lcd_write_int16(result);//ADC0 value

lcd_line_two();

lcd_write_int16(result2);//ADC5 value

}

return 0;

}

September 20, 2012
by Ralphxyz
Ralphxyz's Avatar

Could you clarify what you mean when you say "it disables the digital function of the pin so that it only functions as analog and not as a digital pin also"?

PORT C can have either digital or analog input, in analog mode it functions as a ADC so you disable the digital capabilities so that the dear little mcu does not get confused.

Could you also tell me how to copy and paste lines of program without the line spacing looking so distorted.

Use the "Indent Selection as Code Block" button! Or if you wanted to do it the way it originally was done precede each line of code with four spaces as the instructions on the bottom of this page instruct.

Just highlight your code and click the button, is definitely the easiest way.

Ralph

Post a Reply

Please log in to post a reply.

Did you know that a thermometer can be made "faster" by using a bit of math? Learn more...