## Powering R + LDR voltage divider from µC's output pin?

9 posts / 0 new
Author
Message

I conected the output of voltage divider formed from 10k resistor and LDR:

```               ADC
o
|
|
+5V o----10k----o----LDR----o GND```

to ATmega328's ADC input and got measures of about 850. Then I tried to power the voltage divider from an output pin of a microcontroller and under the same light conditions the ADC readings dropped to about 650.

When I am using an output pin to power the voltage divider, the voltage at the pin supplying power to voltage divider measured with digital multimeter is only 2.8 V instead of Vcc.

The outcome is - I have to use one calibration constant when I am powering the voltage divider from a pin and another calibration constant when the voltage divider is powered straight from the +5V.

At first I thought I started ADC measuring too fast upon turning the supply pin HIGH but I am getting the same results even if the supply pin is HIGH all the time. I am assuming the voltage drop has something to do with the relatively high resistance of resistor (10k) + LDR (about 47k) but would still like to be sure if that is the cause.

I'd like to power the voltage divider from the pin because that way the device wouldn't drain a battery when not measuring light. If the cause of the voltage/measure drop is really high load impedance I might use a voltage follower or a transistor or simply edit the code to use different calibration constant. In that case (using the circuit without an op amp or a transistor) I'd like to know if there is some reason not to use output pin in such conditions.

This topic has a solution.

Chupo_cro

Last Edited: Wed. Oct 4, 2017 - 09:14 PM
This reply has been marked as the solution.

Chupo_cro wrote:
When I am using an output pin to power the voltage divider, the voltage at the pin supplying power to voltage divider measured with digital multimeter is only 2.8 V instead of Vcc.

And what is your Vcc level?

My guess is that you did not make the pin an output.

Tell AVR model.  Show code; complete test program is best.

Chupo_cro wrote:
I am assuming the voltage drop has something to do with the relatively high resistance of resistor (10k) + LDR (about 47k) but would still like to be sure if that is the cause.

If it were >>low<< resistance, then you would see voltage drop.  As it is, with 5V Vcc and 50000 ohms load, that is ~100uA draw. There should be no [easily measurable?] voltage drop.  For an arbitrary AVR model datasheet:

Looks linear; ~0.15V drop for 5mA so 1/50 of that for 100uA so maybe 3mV?

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.

A 10K R and a 47K LDR, at VCC=3.3V would result in 3.3/57000 or about 58 uA.  Close enough to zero that VOH should still be very nearly VCC.  Unless you've programmed RSTDISBL and are using /RESET as an output (you're not doing that, are you?), then the driver strength is much lower.  It's not spec'd in the datasheet for the 328P, but the t25 shows a very poor strength.  At VCC=3V, VOH is only 2.4V even at IOH=0.

More likely is that you forgot to make the pin an output, and only the pull-up is working for you.  Not enough to fight off the voltage divider.

 "Experience is what enables you to recognise a mistake the second time you make it." "Good judgement comes from experience.  Experience comes from bad judgement." "Wisdom is always wont to arrive late, and to be a little approximate on first possession." "When you hear hoofbeats, think horses, not unicorns." "Fast.  Cheap.  Good.  Pick two." "Read a lot.  Write a lot." "We see a lot of arses on handlebars around here." - [J Ekdahl]

Last Edited: Wed. Oct 4, 2017 - 08:11 PM

theusch wrote:

And what is your Vcc level?

My guess is that you did not make the pin an output.

Tell AVR model.  Show code; complete test program is best.

Yes, you are right - I typed:

`LDR_POWER_DDR |= LDR_POWER_PIN_POS;`

`LDR_POWER_DDR |= (1<<LDR_POWER_PIN_POS);`

Thank you!

I saw that now that I already have stripped the code to send it here so I will send it anyway, maybe someone will use it for something - if nothing else someone might check how to use FDEV_SETUP_STREAM and PSTR and how to use #define guards :-))

Vcc is 5V and the AVR is ATmega328 (I already said the AVR model in the initial post).

Here is the code:

main.c

```#include <avr/io.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

#include "uart.h"

FILE uart_io = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

int main(void) {

init_UART();
stdin = stdout = &uart_io;		// set the streams

while(1) {
_delay_ms(250);
}

return(0);
} // main```

uart.h

```#ifndef UART_H
#define UART_H

void init_UART(void);
void tx(uint8_t data);
uint8_t rx(void);

int uart_putchar(char c, FILE *stream);
int uart_getchar(FILE *stream);

#endif```

uart.c

```#include <avr/io.h>
#include <stdio.h>

#include "uart.h"

//int uart_putchar(char c, FILE *stream);
//int uart_getchar(FILE *stream);

// ATmega128: RXD0 --> PE0
//            TXD0 --> PE1 <-------
// kabel:     TX   --> zelena      |
//            RX   --> bijela <----
void init_UART(void) {

UBRR0H = 0x00;
UBRR0L = 51;						// 51 = 19200 baud @ 16 MHz
UCSR0A &= ~(1<<U2X0);				// disable double speed (if using optiboot)
UCSR0B = (1<<TXEN0)|(1<<RXEN0);		// enable TX & RX
UCSR0C = (3<<UCSZ00);				// 1 stop bit, 8 data bits, no parity, async
}

void tx(uint8_t data) {

while(!(UCSR0A & (1<<UDRE0)))
;				// wait
UDR0 = data;		// send
}

uint8_t rx(void) {

while(!(UCSR0A & (1<<RXC0)))
;				// wait
return UDR0;
}

// for FDEV_SETUP_STREAM
int uart_putchar(char c, FILE *stream) {
// new line
if(c=='\n')
uart_putchar('\r', stream);
// TX
while(!(UCSR0A & (1<<UDRE0)))
;				// wait
UDR0 = c;			// send

return 0;
}

// for FDEV_SETUP_STREAM
int uart_getchar(FILE *stream) {

while(!(UCSR0A & (1<<RXC0)))
;				// wait
return UDR0;
}
```

```#ifndef ADC_H

// PORT & DDR
#define LDR_POWER_PORT			PORTB	// voltage divider power supply
#define LDR_POWER_DDR			DDRB
// bit pos
#define LDR_POWER_PIN_POS		PB1

#endif```

```#include <avr/io.h>
#include <stdio.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

ADMUX  |= (1<<REFS0);								// ref = AVcc
// here an initial ADC conversion could be done

LDR_POWER_DDR |= (1<<LDR_POWER_PIN_POS);	// <-- **** THIS WAS WRONG ****
LDR_POWER_PORT &= ~(1<<LDR_POWER_PIN_POS);	// LDR power supply = OFF

if(ch == 0) {
LDR_POWER_PORT |= (1<<LDR_POWER_PIN_POS);	// LDR power supply = ON
//_delay_ms(1000);
}

ADMUX |= ch;			// set mux
;	// wait

LDR_POWER_PORT &= ~(1<<LDR_POWER_PIN_POS);	// LDR power supply = OFF

```

Chupo_cro

Last Edited: Wed. Oct 4, 2017 - 09:24 PM

joeymorin wrote:

More likely is that you forgot to make the pin an output, and only the pull-up is working for you.  Not enough to fight off the voltage divider.

Yes, that was the problem. Although I didn't forget to assign a value to DDR but rather used pin number insted of mask :-[

Chupo_cro

Yes, that was the problem. Although I didn't forget to assign a value to DDR but rather used pin number insted of mask :-[

There's been a rash of these lately ;-) :

https://www.avrfreaks.net/comment/2287146#comment-2287146

 "Experience is what enables you to recognise a mistake the second time you make it." "Good judgement comes from experience.  Experience comes from bad judgement." "Wisdom is always wont to arrive late, and to be a little approximate on first possession." "When you hear hoofbeats, think horses, not unicorns." "Fast.  Cheap.  Good.  Pick two." "Read a lot.  Write a lot." "We see a lot of arses on handlebars around here." - [J Ekdahl]

Maybe a consequence of wide use of Arduino?

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

ka7ehk wrote:

Maybe a consequence of wide use of Arduino?

I had to laugh when I read that :-) The truth is exactly the opposite. In fact it couldn't be more opposite than that. Although I've been using µCs since 16F84 times (and for the last 8-9 years I've been using AVRs only) I have never ever until a few days ago had any Arduino board nor I have ever written one single line of Arduino code targeted for AVR based boards :-) I do have Arduino IDE installed but solely for the purpose of programming ESP8266. I am writing AVR code every day and my estimation is I wrote about 50000+ lines of code in AVR Studio - one of my recent projects having about 2500 lines of code consisting of 29 .c and .h files.

Recently I ordered a dozen of Arduino Nano and Arduino Pro mini clones because of their small form factor. The first I did was to try blink example from Arduino IDE just to try the bootloader. Then I tried to use a bootloder from command line to upload .hex from AVR Studio and saw it might be a fast way for rapidly uploading the code during development. When the code will be finished I will remove the bootloader, edit the code to work with internal oscillator and burn it 'normally' (through ISP). The way I was working before was to during development use ATmega128 board with JTAG programmer and to finally port the code to AVR that would be used in the device.

BTW, when I saw the original 1KB bootloader that came with the boards can not handle WDT reset I found 256 bytes optiboot which solves that problem. I did occasionally see forum threads mentioning 'optiboot' but have never paid attention because I wasn't using bootloaders. Now I finally know why so many threads about different bootloaders.

Chupo_cro