Continue to Site

# Displaying AVR ADC value in LUX on the LCD

Status
Not open for further replies.

#### ArdyNT

##### Full Member level 2
Need Help: Displaying AVR ADC value in LUX on the LCD

The following equation is derived from the datasheet of photo-resistor:

E[lux] = 10000 / (R[kΩ]*10)^(4/3)

It clearly shows the relation between RESISTANCE and LUX, NOT relation between ADC and LUX

My problem is how do I use this equation in my code so I can change the 10bit ADC value of my avr into LUX.
I got confuse since the ADC value is not equal to the resistance, right?

Here is part of my code (codevisionavr):

Code:
    while (1)
{
ldr1=read_adc(0);   // [I][COLOR="#00FF00"]I need it to be LUX, help me to modify it[/COLOR][/I]
lcd_gotoxy(0,0);
sprintf(buf,"L1:%d%d%d%d",ldr1/1000,(ldr1%1000)/100,(ldr1%1000%100)/10,ldr1%1000%100%10);
lcd_puts(buf);

lcd_gotoxy(9,0);
sprintf(buf,"L2:%d%d%d%d",ldr2/1000,(ldr2%1000)/100,(ldr2%1000%100)/10,ldr2%1000%100%10);
lcd_puts(buf);
}

Thanks..

Last edited:

The ADC always measures a voltage, then depending on where this voltage is measured you can calculate different things.

If you want to find the resistance you place the unknown resistor in series with a known resistor and create a voltage divider connected to a known voltage.

Have you used a voltage divider , post a schematic.

Yes, I've used voltage divider. Here it is:

and it should be like this right:

Vout = 5 x [ (10 000)/(LDR + 10 000) ]

Yes your equation is correct so , LDR= (50000/Vout)-10000

- - - Updated - - -

If you combine these two equations you get

ArdyNT

### ArdyNT

Points: 2
I'm sorry, I still got confuse.

Right now I have three equations:

1. E[lux] = 10000 / (R[kΩ]*10)^(4/3)

2. Vdvd = 5 x [ (10 000)/(LDR + 10 000) ]

3. ADC = (Vdvd * 1023)/V.ref

The problem is, how can I modify my code to display "E[lux]"

If so then the 2 and 3 are combined and Resistance equals LDR= (10230000/ADC) - 10000

If you get an ADC result of 400 then LDR= (10230000/400) - 10000 = 15575 ohm

Then use this Resistance in the LUX equation

Yes, I connected the Vref pin to 5 Volt.

Ok, now I understand how it works. Next, I modify the code to be like this:

Code:
while (1)
{
ldr1=(10230000/a) - 10000;
Lux=10000/((ldr1*10)^(4/3));   [I][COLOR="#FF0000"]  // No sure about this line, is it right ? (also previously ldr1 is in k.Ohm in eq. 1)[/COLOR][/I]

lcd_gotoxy(0,0);
sprintf(buf,"L1:%d%d%d%d",Lux/1000,(Lux%1000)/100,(Lux%1000%100)/10,Lux%1000%100%10);
lcd_puts(buf);
}

Last edited:

Lux=10000/((ldr1*10)^(4/3));

Note that in an equation like this the calculation will be done using integers, this means that 4/3 will be truncated and will give a result of 1.
For floats you have to use 4.0/3 or typacast (float)4/3.

The symbol ^ will also not work as intended, this is the XOR symbol in C not power, for power check the math.h library https://www.nongnu.org/avr-libc/user-manual/group__avr__math.html

Ok, thanks alexan, I'll check it first

Sorry, my mistake

I didn't see it.

I tried this:

Code:
#include <mega8535.h>
#include <stdio.h>
#include <delay.h>
#include <math.h>

unsigned char buf[10];

unsigned int a;
volatile unsigned int ldr1;
float x;
float lux;

// Alphanumeric LCD functions
#include <lcd.h>
#asm
.equ __lcd_port=0x15 ;PORTC
#endasm

{
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Wait for the AD conversion to complete
}

void main(void)
{
PORTA=0xFF;
DDRA=0x00;

SFIOR&=0xEF;

lcd_init(16);

while (1)
{
ldr1 = (10230000/a) - 10000;
x = 4.0/3.0;
lux = 10000/(pow((ldr1*10),x));

lcd_gotoxy(0,0);
sprintf(buf,"L1:%d%d%d%d",lux/1000,(lux%1000)/100,(lux%1000%100)/10,lux%1000%100%10);
lcd_puts(buf);
}
}

But I got error message: "Error: operand types 'float' and 'int' are incompatible with the '%' or '%=' operator"

For float modulo there is a function in math.h

bu it makes no sense to use it for what you are trying to do.

I would suggest you use sprintf (I mean the float version %f) to convert the number to ASCII string

- - - Updated - - -

The other solution is to multiply the float with a power of 10 (depending on the significant digits you want) and convert it to an integer (truncate the remaining decimal digits using typecasting) which can then be converted using the modulo process you do

Ough, I got confuse now.
Seems I like I dont know so many things yet.

Is there any other sources with clear explanation or maybe some simple examples related with this math operations?

The conversion of a float using sprintf is like
Code:
char my_string[16];
float my_float=123.456789;

// one way to convert the float to string is
sprintf(my_string,"%f",my_float);  // you will get "123.456789"

// the other way is to use a specified number of decimals
sprintf(my_string,"%.2f",my_float);  // you will get "123.45"

The other way you say you prefer is to mupliply 123.456789*1000 , then typecast it (uint32_t)1234567 ad then convert it using midulo

To use sprintf with floats you have to add :
the libraries libprintf_flt.a and libm.a (in that order), and

- - - Updated - - -

for float sprintf in AVR refer to

This is the new one, using the second suggested solution:
Code:
#include <mega8535.h>
#include <stdio.h>
#include <delay.h>
#include <math.h>
#include <stdlib.h>

char str[100];
unsigned int a1;
float a2;
float x;
float lux;
int m1;
float d1;
int m2;

// Alphanumeric LCD functions
#include <lcd.h>
#asm
.equ __lcd_port=0x15 ;PORTC
#endasm

{
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Wait for the AD conversion to complete
}

void main(void)
{
PORTA=0xFF;
DDRA=0x00;

SFIOR&=0xEF;

lcd_init(16);

while (1)
{
a2 = (10230000/a1) - 10000;
x = 4.0/3.0;
lux = 10000/(pow((a2*10000),x));  [COLOR="#00FF00"]// Let say the result is xxx,yyyy[/COLOR]

m1 = lux;                        [COLOR="#00FF00"]// Get the integer part (xxx)[/COLOR]
d1 = lux - m1;                 [COLOR="#00FF00"]// Get the fractional part (0.yyyy)[/COLOR]
m2 = trunc(d1*10000);     [COLOR="#00FF00"]// Turn into integer (yyyy)[/COLOR]

lcd_gotoxy(0,0);
sprintf(str,"L1:%d.%04d\n", m1,m2);
lcd_puts(str);
}
}

First: Am I doing it right?
Second: I got this problem now=> Error: undefined symbol 'trunc'

I'm sorry, I just get your updated post, so I did something a bit different. (internet conn. problem)

Last edited:

trunc is defined in math.h so I'm not sure of the problem but it is not needed .

The decimals will be truncated anyway when you typecast the number and store it in the integer
m2 = (int)(d1*10000); // only the integer part will be stored in m2

I'm not sure why you have used signed types for m1 and m2 , do you expect negative lux?

I would suggest
Code:
unsigned int m1, m2;
m2 = (unsigned int)(d1*10000);

sprintf(str,"L1:%u.%04u\n", m1,m2);

No no, no negative lux, I'll change it. My mistake.

Well, I removed trunc and follow your suggestion. I got no error now but the LCD displays "L1:0.0000" all the time even I changed the resistance.

and next I just want to know what is the difference between:

Code:
sprintf(str,"L1:%u.%04u\n", m1,m2);
with
Code:
sprintf(str,"L1:%d.%04d\n", m1,m2);

d is for signed, u is for unsigned.
You can read any sprintf tutorial to see all the parameter explanation.

Put manually a value instead of the ADC result in the equation and see if you get a result.
For example use 511.

Ok, I will.

I tested this:

Code:
        a1 = read_adc(0);
a2 = (10230000/a1) - 10000;
x = 4.0/3.0;
lux = 123.5656       [COLOR="#FF0000"]// I change this[/COLOR]

m1 = lux;               // Get the integer part (xxx)
d1 = lux - m1;          // Get the fractional part (0.yyyy)
m2 = d1*10000;          // Turn into integer (yyyy)

lcd_gotoxy(0,0);
sprintf(str,"L1:%u.%04u\n", m1,m2);
lcd_puts(str);

And I got the right display. but when I change it back to
Code:
lux = 10000/(pow((a2*10000),x));

it display 0.0000 again. Is the way I write the exponent right?

Status
Not open for further replies.