ATmega328P ADC Unreadable When Resistive Divider Switched by Solid State Relay

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

AVCC is connected to VCC and both are decoupled from ground. AREF is decoupled from ground.

 

With REFS=01, the reference is AVCC and an external capacitor is expected at AREF. This configuration does not allow the ADC to read a resistive divider coming from a battery supply (only values close to zero are returned), but a potentiometer is read properly.

 

With REFS=00, the reference is AREF and the internal VREF is turned off. This configuration allows the ADC to read a resistive divider.

 

 

What is the difference? Why does REFS=01 not work?

Last Edited: Sat. Oct 28, 2017 - 05:24 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

R0b0t1 wrote:
What is the difference?

Don't you need to tell us which AVR model this deals with?

R0b0t1 wrote:
This configuration does not allow the ADC to read a resistive divider coming from a battery supply,

???  What does "does not allow" mean?  Did you receive a municipal citation, or other notice of illegality?

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Don't you need to tell us which AVR model this deals with?
My apologies, my device is an ATmega328P.

theusch wrote:
???  What does "does not allow" mean?  Did you receive a municipal citation, or other notice of illegality?
Per the topic, the ADC reads all zeroes, or values very close to zero.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You will need to post a schematic or circuit diagram.  Particularly all the analog stuff.

From

http://www.avrfreaks.net/comment...

please post a complete test program that demonstrates your symptoms.  Tell what you expect to happen; tell what >>is<< happening.  Tell how you are testing.  Tell toolchain, version, and optimization settings.

 

1)  What are the voltage levels, >>right on the AVR pins<< ?

...

Tell how you are testing.  Tell what you expect to happen; tell what is happening.

 

[my guess is the battery doesn't have common ground connection]

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:

You will need to post a schematic or circuit diagram.  Particularly all the analog stuff.

From

http://www.avrfreaks.net/comment...

 

Tell how you are testing.  Tell what you expect to happen; tell what is happening.

 

[my guess is the battery doesn't have common ground connection]

 

Hello,

 

My apologies. I tried to cover those things but I am not very intelligent. I will try to address those things now.

 

I test by reading the ADC. If I set REFS=01 it always returns a value close to zero (max I read was 3, which seems like noise). If I set REFS=00 I read a voltage that is not zero, but is 1023. I was too early in saying that REFS=00 works.

 

I am not sure how to provide a schematic.

 

I am able to use a potentiometer with REFS=00 set with the wiper on the ADC pin to read the potentiometer. The circuit used with the battery (actually an external supply, but the voltage from full power should be 4.7V, not ~5V, as the supply is 14.1-14.4V) is similar. The ADC pin is connected between a high side resistor of 10K and a low side resistor of 5K. The resistive divider is turned on and off by a solid state relay which has an optocoupler.

 

The optocoupler, on closer inspection, seems to be the issue, but I do not know how it is the issue. Is more information needed? I can read the resistive divider properly with a multimeter. The grounds are commoned, and everything is "one circuit."

 

My initial confusion seems to stem from a hidden 36K pullup that exists within the ADC. That seems to be why a disconnected pin can read 5V.

 

Here is the code used to control the ADC:

void
adc_up(void)
{
	PRR &= ~(1 << PRADC);

	// Ref. voltage is AVcc with decoupling on Aref.
	// Multiplexer reading ADC0, or pin 23.
	ADMUX = (0 << REFS1) |
			(0 << REFS0) |
			(0 << ADLAR) |
			(0 << MUX3)	 |
			(0 << MUX2)	 |
			(0 << MUX1)  |
			(0 << MUX0);

	// Prescaler of 64 for 125kHz clock from 8MHz.
	// Enable the completion interrupt so that the noise reduction sleep mode
	// may be used in a timely manner.
	ADCSRA = (1 << ADEN)  |
			 (0 << ADSC)  |
			 (0 << ADATE) |
			 (0 << ADIF)  |
			 (1 << ADIE)  |
			 (1 << ADPS2) |
			 (1 << ADPS1) |
			 (0 << ADPS0);

	// Comparator multiplexing off, freerunning conversion mode.
	ADCSRB = (0 << ACME)  |
			 (0 << ADTS2) |
			 (0 << ADTS1) |
			 (0 << ADTS0);

	// Disable digital IO logic for all ADC pins.
	DIDR0 = (1 << ADC5D) |
			(1 << ADC4D) |
			(1 << ADC3D) |
			(1 << ADC2D) |
			(1 << ADC1D) |
			(1 << ADC0D);
}

void
adc_down(void)
{
	// ADC must be disabled before setting PRR.
	ADCSRA &= ~(1 << ADEN);
	PRR    |=  (1 << PRADC);
}

void
adc_convert(void)
{
	SMCR = (0 << SM2) |
		   (0 << SM1) |
		   (1 << SM0) |
		   (1 << SE);
	sleep_cpu();
	SMCR = 0;

	//ADCSRA |= (1 << ADSC);
	//while(ADCSRA & (1 << ADSC));
}

uint16_t
adc_getv(void)
{
	uint16_t r = 0;
	r = ADC;

	ADCSRA |= (1 << ADIF);
	return r;
}

EMPTY_INTERRUPT(ADC_vect);

Here is the code that uses the reading:

#define sense_off() \
	do { PORTD |=  (1 << PD5); } while (0)
#define sense_on() \
	do { PORTD &= ~(1 << PD5); } while (0)

int
main(void)
{
    // .. I/O initialization ..

    uint8_t dip = 0;
	dip |= (!((PINB & (1 << PB1)) >> PB1)) << 1;
	dip |= (!((PINB & (1 << PB2)) >> PB2)) << 0;

    switch (dip) {
    case 0: runtime = RUNTIME_SET_0 - 1; vfall =   0; break;
    case 1: runtime = RUNTIME_SET_1 - 1; vfall =  50; break;
    case 2: runtime = RUNTIME_SET_2 - 1; vfall = 100; break;
    case 3: runtime = RUNTIME_SET_3 - 1; vfall = 150; break;
    }

    // Check battery voltage before starting run.
    uint16_t v = 0, r = 0;

    sense_on();
    adc_convert();
    sense_off();
    v = adc_getv();
    if (v > BATTERY_CUTOFF)
        r = (v - BATTERY_CUTOFF) / vfall;
    else
        r = 0;

    // Check that r > 0.
}

 

Last Edited: Sat. Oct 28, 2017 - 05:25 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
You will need to post a schematic or circuit diagram.  Particularly all the analog stuff.

Instructions here: http://www.avrfreaks.net/comment...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

you miss the easiest check ---

 

Hook your multimeter to the pin, under the different scenarios.....it the pin at least getting some readable voltage to work with....if so, it so match/scale to your readings. 

 

The resistive divider is turned on and off by a solid state relay

why & how?    Probably a bad idea.  If to save power, just use a fet between the divider resistors  (put one leg of lower resistor to gnd  & on the other leg the fet source. resistor junction to adc.  The high resistor goes between  the batt, and the fet Drain)) ....If you use a 5V micro, then you have 5V of potential gate drive to assign...find a fet with a 2V thresh & allocate 2.5V to turn on fet. Scale your lower resistor to provide ADC with 5-gate (2.5), leaving 2.5V max for the adc.  Or allocate 3V to the gate & 2V to the ADC.  Or use a higher separate controlled voltage (say 6v, 12v, etc) to drive the gate & now all 5v is avail for ADC signal range.

When in the dark remember-the future looks brighter than ever.

Last Edited: Sun. Oct 29, 2017 - 04:31 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:
why & how?   

The schematic would show the how ...

 

Agree that a SSR really doesn't sound like an appropriate tool for this job!