infrared Liquid level detector-SharpGP2D12

Discussion in 'Microcontrollers' started by fantabulous68, Aug 28, 2009.

Joined:
Jun 21, 2006
Messages:
5,897
Likes:
502
Location:
Cleveland, OH, USA
I am assuming the x-axis is the depth of water in its container. Correct?

Did you keep the distance to the water surface constant? That value should be kept constant...actually, I suggest using 2 distances, like 10 cm and 20 to 30 cm, if it is not too hard to do that. Since your detector is fixed, just lower the vessel. Can you get a "lab jack" to do that?

Nice touch using both a plastic and a glass container. The glass has a very high refractive index, so will reflect differently than the plastic will at the liquid-container interface.

John

2. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0
Yes it is........uhmmmm no lab jack at my disposal...(use shoe boxes and text books to stack up)

Tonight i am going to take readings for all those liquids i did b4(its 10:40 now)....but by varying the depth of the liquid...and keeping the distance to the surface fixed.....

i got to practice my presentation and my exams start next month....
I need to make a study time table...time management!very important

Joined:
Jun 21, 2006
Messages:
5,897
Likes:
502
Location:
Cleveland, OH, USA
Just looked at the datasheet and some other information about the GP2D12 sensor. Based on that, I recommend increasing your minimal fixed distance from 10 cm to 12 to 14 cm. Then, pick a longer distance that is 10 to 13 cm more than your minimum distance for your second point (if you do the experiment as suggested awhile back). The reasons to avoid 10 cm exactly are: 1) it is the minimum distance; 2) there is rapid drop off at shorter distances; and 3) there is variation between devices (devices are characterized for quality control at about 24 cm). So, going to a slightly greater minimal distance will reduce unknown variability due to working at the device's extreme lower limit. You don't want to go too far, because the response curve flattens, which will increase your imprecision, and band spread of the IR beam will make edge effects more prominent. That is, you will have to use a larger diameter container for the liquid. Beam diameter vs. distance is shown in some of the technical sheets.

John

Joined:
Jan 12, 1997
Messages:
-
Likes:
0

5. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0

the glass vessel and sensor were at a fixed distance apart, took readings of the depth of the water which I varied...I did not move the sensor or the vessel once i started taking readings-the sensor was positioned over the center of the glass vessel.....see attached document...only problem is....the longest glass vessel i got is 21.5cm----so i took 3 readings for each case:

10cm fixed

12cm fixed

14cm fixed

Attached Files:

• fixed distances.doc
File size:
80 KB
Views:
102
Last edited: Sep 13, 2009

Joined:
Jun 21, 2006
Messages:
5,897
Likes:
502
Location:
Cleveland, OH, USA
I am very confused by that chart. You say, "10 cm fixed" but show 3 readings at different distances. Distance to what? You did triplicate readings. Does each point represent the average?

What does this mean:
Are you measuring from the top of the glass container, the top of the liquid, or the bottom of the glass container? All three "variations" are identical. Is that a typo?

John

7. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0
thats a typo coz i cut and paste......its 10cm, 12cm and 14cm................let me change that on the document....

The graphs are correctly labled

8. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0
sensor<-------10cm--------->top of glass This was the fixed distance
Then i took 3 readings from the sensor to the surface of the water at THAT fixed distance and plotted a graph

and i repeated this at 12cm.......................then again for 14cm

Last edited: Sep 13, 2009
9. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0
WATER 10*away
[
Code (text):
distance   output V
30         0.509
20         0.724
13         0.725
Eg.
sensor<-------10cm--------->top of glass This was the fixed distance

Then i took 3 readings from the sensor to the surface of the water at THAT fixed distance and plotted a graph

and i repeated this at 12cm.......................then again for 14cm

Last edited: Sep 13, 2009
10. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0
Oh i have to be going now...its 23:55 and i wake @5:00 to get ready for uni and leave home at 6:15...Take care Jpanhalt....i will see your response at uni tomorrow....thanks for all your input....

Joined:
Jun 21, 2006
Messages:
5,897
Likes:
502
Location:
Cleveland, OH, USA
Can you find a light-gray or white piece of cardboard? Get as big a piece as practical, at least 20 cm X 20 cm. Flat, stiff, card stock would be best.

Take multiple measurements at 12, 20, 30 cm from your detector. let's see what your best-case reproducibility is. I suspect it is pretty good. If not, then you need to look for problems in the basic sensor setup.

Assuming that reproducibility with the cardboard is good, then lets return to your liquid surface. Off hand, those results do not look too good, but don't despair. I think it is the set up you are using, which is why reproducibility seems so poor.

Let's focus only on water for now -- wine is later

Do you have a cooking pot or aquarium -- anything -- that is much bigger in diameter than the drinking glass you are using. If you can get something about 20 cm or more in diameter, use it. Hopefully, it will be at least 10 cm high. Place your sensor 20 to 25 cm form the bottom of that container. Take a blank measurement of the empty pot. Then add 2 cm of water, take 3 measurements and average them, if they are relatively close to each other. Otherwise, report what the 3 values are. Then add 5 MORE cm of water and repeat. Keep adding water and taking measurements until the water is at the top of the pot.

For now, be sure to let any ripples in the water settle. If you get an unusual reading, check for ripples, and record your data.

It is getting late for you now, I understand. But, I will check in tomorrow several times.

John

12. Mr RBWell-Known Member

Joined:
Jul 22, 2008
Messages:
4,716
Likes:
194
Location:
Out there
That chart doesn't look too good. If the voltage readings are correct for the blue chart it seems to be measuring the bottom of the vessel.

My 80cm Sharp sensor is currently soldered onto a robot and he might get a phobia if I go suspending him head first over a bucket of water...

I do have a few 30cm Sharp sensors spare, if fantabulous can't start to get some logical looking readings (and better labeled charts! ) I can fill a bucket with water and connect it up.

13. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0
lol thats after I PASS....

Pot Yes aquarium no.....My cat would eat the fish

Sorry i'll improve on that....too eager to post my data here

Ok im going to get my hands on that cardboard and pot when i get home.......and try again....(But tomorrow i have a practical on SQUIDS....and i get home at 16:30 from uni....uhmmmm i got to do my pre-prac lol or they will kick us out of the lab)....so do forgive me if i dont post any results today....

Joined:
Jun 21, 2006
Messages:
5,897
Likes:
502
Location:
Cleveland, OH, USA
Don't worry. Get what needs to be done, like studying for an exam, done first.

BTW, when is the IR/liquid-level project due? In one of your earliest posts, you indicated it was at least several weeks away.

John

15. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0

the attached pic shows put a cap from the i/o line to ground.....

would it really make a difference in my readings that i placed the cap right at the sensor power between +5v and ground .....and not as shown in the pic???

Attached Files:

• irc.gif
File size:
3 KB
Views:
217

Joined:
Jan 4, 2007
Messages:
21,187
Likes:
644
Location:
Ex Yorks' Hants UK
hi,
The caps on the wrong pins.!!
Should be +V and 0V common

17. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0
Well...we have different phases....1, 2, 3(final)

first phse is done....
second phase is in october and so are exams...........

2nd phase is a full paper design.....
1. Report
2. Presentation
3. Breadboard version of the design must be working(OR will get zero for demonstration)

But Ill be over with exams in the 1st week then i can give all my attention to design

Last edited: Sep 14, 2009
18. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0
Thanks Eric...lol( just checking)

19. fantabulous68Member

Joined:
Feb 20, 2007
Messages:
323
Likes:
0
I tried programming the (pic16f690)GP2 sensor with MR RB code for the (pic18F) today and tried displaying just the distance to an object for now....

when i power up the LCD displays random numbers

now when i put a page & hold it steady....i get

EG.

010101010101010
010101010101010

i keep moving it away and...

020202020202020
020202020202020

030303030303030
030303030303030

till.....

090909090909090
090909090909090

THEN
000000000000000
000000000000000

and it repeats the sequence as i move away

010101010101010
010101010101010...............

and so on......

BTW

(it does not go to 111111111111111
111111111111111)

and 1212121212121212
1212121212121212 .....etc)

i just measured manually with a ruler to verify the values....its accurate

meaning....
the sensor has a min range of 10 cm......
so when the page is 10cm away it displays....

000000000000000
000000000000000

and if it 5cm away from the min range(ie. 15cm)

then it display:

050505050505050
050505050505050

and i measured this with a ruler and it gives 15cm

here is the code.....ONLY the Highlighted RED code is the parts dealing with ADC

Could some1 please tell me why its giving me such a long measured value??? Its the 1st time i tried using ADC

Code (text):
#include <pic.h>
#include "pic.h"
#include "delay.h"
#include "math.h"
#include <stdio.h>
#include <stdlib.h> //

void FloatToStr(float , char[]);
void DelayMs(unsigned char);
void lcd_cmd(unsigned char);
void lcd_data(unsigned char);
void lcd_clear(void);
void lcd_puts(const char[]);
void lcd_goto_L1(void);
void lcd_goto_L2(void);
void lcd_cursor(unsigned char);
void lcd_init(void);
void init(void);
char WaitForInput(void);
unsigned char user_input(void);
void home_screen(void);
void EnterHeight(void);
void EnterScreen(void);
void ShowDigits(unsigned char val);
void calc_distance(void);
void main(void);

unsigned char cm2LCD;

unsigned char cmHigh, cmLow;

#define LCD_RS RC0      //LCD RS pin
#define LCD_EN RC1      //LCD EN pin
#define LCD_STROBE()    LCD_EN = 1; asm("nop"); asm("nop"); LCD_EN = 0

unsigned char cm10;     //
unsigned char cm;       //
unsigned int math;      // used for voltage calculations
unsigned char NumDec;
unsigned char NumSep[2];

unsigned char i,j,k;
//char temp[8];
//[/b]
unsigned char height=50;
unsigned char range;
unsigned char area;
unsigned char SensorPos=10;
//[/b] New Vars
char input_sw;

char mnuPOS;

unsigned char MyVal;
unsigned char MyValLCD[2];
unsigned char MyMaxVal;
unsigned char MyMinVal;
unsigned long bres;     // for bresenham 2-second timer system

unsigned char ;

#define HOME_SW RC2             //HOME switch
#define INCREASE_SW RC3         //INCREASE switch
#define DECREASE_SW RC4         //DECREASE switch
#define ENTERSETTINGS_SW RA4    //ENTERSETTINGS switch

///////////////////////CONVERT FLOAT TO STRING///////////////////
// This function was taken from the CAVR library. It was modified slightly
// to suit our design.
void FloatToStr(float n, char str[])
{
float scale;
unsigned char d,f;
f=0;i=0;
if (n<0.0) {n=-n; str[f]='-'; f++;};
n=n+0.005;
scale=1.0;
while (n>=scale) {scale=scale*10.0; ++i;};
if (i==0) {str[f]='0'; f++;}
else
while (i--)
{
scale=floor(0.5+scale/10.0);
d=(unsigned char) (n/scale);
str[f]=d+'0';
n=n-scale*d;
f++;
};

str[f]='.';
f++;
for (j=0;j<=1;j++) //2 decimal points
{
n=n*10.0;
d=(unsigned char) n;
str[f]=d+'0';
n=n-d;
f++;
};
str[f]='\0';
}
///////////////////END CONVERT FLOAT TO STRING///////////////////

/////////////////////////////DELAY///////////////////////////////
void DelayMs(unsigned char cnt)
{
#if XTAL_FREQ <= 2MHZ
do {
DelayUs(996);
} while(--cnt);
#endif

#if    XTAL_FREQ > 2MHZ
unsigned char   p;
do {
p = 4;
do {
DelayUs(250);
} while(--p);
} while(--cnt);
#endif
}

void DelayS(unsigned char cnt)
{
for (j=0; j<(cnt*10); j++)
DelayMs(100);
}
///////////////////////////DELAY END/////////////////////////////

//////////////////////////////LCD SETUP//////////////////////////
/* send a command to the LCD */
void lcd_cmd(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
LCD_RS = 0;  //write instruction
PORTB = (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB = ((c << 4) & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
}

/* send data to the LCD */
void lcd_data(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
PORTB = 0x00;
LCD_RS = 1; //write data
PORTB |= (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB &= 0x00; //load upper nibble on LCD data lines
PORTB |= ( (c << 4) & 0xF0);
LCD_STROBE(); //send instruction to LCD
}

/*Clear the LCD*/
void lcd_clear(void)
{
lcd_cmd(0x01); //command to clear LCD
}

/*write a string of chars to the LCD*/
void lcd_puts(const char s[])
{
j = -1;
while(s[++j]!=('\0')) // send characters until null character reached
lcd_data(s[j]);
}

/*go to beginning of line 1*/
void lcd_goto_L1(void)
{
lcd_cmd(0b10000000); // command to go to line 1
}

/*go to beginning of line 2*/
void lcd_goto_L2(void)
{
lcd_cmd(0b11000000); // command to go to line 2
}

/*move cursor "x" positions to the right*/
void lcd_cursor(unsigned char x)
{
lcd_cmd(((x)&0x7F)|0x80);
}

/*initialise the LCD - put into 4 bit mode*/
void lcd_init(void)
{
LCD_RS = 0;
LCD_EN = 0;
DelayMs(20); //wait for LCD startup
lcd_cmd(0x02);

lcd_cmd(0x28);  // 4-bit mode
lcd_cmd(0x08);  // display off
lcd_cmd(0x01);  // clear display
lcd_cmd(0x0C);  // disp. on, cursor off, cursor blink off
lcd_cmd(0x06);  // entry mode
lcd_cmd(0x80);  // initialise DDRAM address to zero
}
//////////////////////////LCD SETUP END//////////////////////////

void init(void)
{

// setup the PIC 16f690
OSCCON = 0x72;          // internal osc, 8MHz
PORTA = 0;
TRISA = 0b10010010;     // RA7 high imp, RA3 is serial out, RA4 button input

PORTB = 0;              // PORTB not used
WPUB = 1;               // PORTB pullups ON
RABPU = 0;

[COLOR="Red"]
ADCON0 = 0b10000101;    // bit 7 right justify,analogue channel select bits bits5-2  0001=AN1,ADC ON, RA1 is ADC input
ADON=1;                 // turn on the A2D conversion module

ANSELH=0x00;

T1CON = 0b00010001;     // TMR1 is ON, 1:2 prescale, =1MHz
T2CON = 0b00000101;     // TMR2 is ON, 1:4 prescale, =1MHz[/COLOR]

MyVal = 0; //initializn these variables here
MyMinVal = 0;
MyMaxVal = 99;

TRISB=0x00;
TRISC=0xFC;

lcd_init(); //call LCD initialisation
}

char WaitForInput(void){
char done;
char temp;
done = 0;

while(!done){
if(!ENTERSETTINGS_SW){
temp = 1;
done = 0xff;
}

if(!HOME_SW){
temp = 2;
done = 0xff;
}

if(!INCREASE_SW){
temp = 3;
done = 0xff;
}

if(!DECREASE_SW){
temp = 4;
done = 0xff;
}
}//end of while
DelayMs(150);    //debounce
return temp;
}//
lcd_clear();
lcd_goto_L1();

switch(pos){
case 0:
lcd_puts("    HEIGHT    ");
break;
case 1:
lcd_puts("    RANGE     ");
break;
case 2:
lcd_puts(" SURFACE AREA ");
break;
}

lcd_goto_L2();
lcd_puts("Press Up/Down"); //home screen message (line 2)
}
void EnterHeight(void){
lcd_clear();
lcd_goto_L1();
lcd_puts(" ENTER HEIGHT ");
lcd_goto_L2();
lcd_puts("Press Up/Down"); //home screen message (line 2)
}

void EnterScreen(void){
lcd_clear();
lcd_goto_L1();
lcd_puts(" [cm] ");
}

void ShowDigits(unsigned char val){

MyValLCD[0] = val /10;    //returns the quotient (if temp = 35 the result is 3)
MyValLCD[1] = val % 10;     //Returns remainder   (if temp = 35 the result is 5)

MyValLCD[0] += 0x30;    //to ASCII
MyValLCD[1] += 0x30;    //to ASCII

EnterScreen();
lcd_goto_L2();
lcd_data(MyValLCD[0]);  //to LCD
lcd_data(MyValLCD[1]);  //to LCD
}

[COLOR="Red"]void calc_distance(void)[/COLOR]
{
// from the transeiver datasheet the analog voltage is
// the inverse of distance, so distance can be calculated
// d = (1 / volts) then just scaled to suit the transeiver

math = (math * 256);

// now invert it; (1 / volts) use (6050 / volts) for scaling
math = (6050 / math);
if(math >= 2) math -=2;     // fix linear error (-2)
if(math > 99) math = 99;    // max limit at 99cm

// convert from 0-99 to 2 decimal digits, 0-99cm
cm10=0;
while(math >= 10)
{
cm10++;
math -= 10;
}
cm = math;
}
//
unsigned char user_input(void)      //This will return what we want
{
char done = 0;

MyVal = 0;          //Start on 0
while(done == 0){
input_sw = WaitForInput();

switch(input_sw){
case 1:
done = 0xff;            //This tells us the user finished entering
lcd_goto_L1();
lcd_puts("     Done!      "); //home screen message (line 1)
break;
case 3:
if(MyVal < MyMaxVal)
MyVal++;
EnterScreen();
ShowDigits(MyVal);
break;
case 4:
if(MyVal > MyMinVal)
MyVal--;
EnterScreen();
ShowDigits(MyVal);
break;
default:
break;
}

}
DelayS(1);
return MyVal;
}

void home_screen(void){
mnuPOS = 0;
lcd_clear();
lcd_goto_L1();
lcd_puts("INFRARED LIQUID"); //home screen message (line 1)
lcd_goto_L2();
lcd_puts("LEVEL DETECTOR"); //home screen message (line 2)

input_sw = 0;           //Reset the value

while(input_sw != 1)    //Wait until enter is pressed
input_sw = WaitForInput();

DelayMs(2);             //shorter delay
height = user_input();  //The HEIGHT var will have the myVal

DelayMs(2);             //shorter delay
range = user_input();   //The HEIGHT var will have the myVal

DelayMs(2);             //shorter delay
area = user_input();    //The HEIGHT var will have the myVal
/*
"enter height"
call enter/settings (which is now user input function in new code)
height=MyVal

"enter range"
call user_input
range=MyVal

"enter surface area"
call user_input
area=MyVal
*/
}

//*********************************************************
/*  Junebug_Serial4.c    RomanBlack.com 19th July 2009.

uses "zero error 1 second timer"
system to generate a 2 second interval, then every
2 seconds it reads an analog voltage from a
Sharp GP2 distance sensor and converts it to decimal
distance, then sends that data to a LCD

Code for MikroC, config handled by MikroC compiler;
_INTI02_OSC_1H
_WDT_OFF_2H
-MCLRE_ON_3H
_LVP_OFF_4L
_PWRT_ON_2L
*/
//*********************************************************

void main(void)
{
init(); // initialise I/O ports, LCD
while(1){
//  home_screen();

[COLOR="Red"]// wait for 2 seconds, uses TMR1 free running at 1Mhz
while(!TMR1IF)  // wait for TMR1 overflow
TMR1IF = 0;     // clear overflow flag

bres += 65536;          // add 65536uS to bres value
if(bres >= 2000000)     // if reached 2 seconds!
{
bres -= 2000000;    // subtract 2 seconds, keep error

GODONE=1;   // initiate conversion on the channel 0
while(GODONE) continue;  // Wait convertion done
calc_distance();        // convert ADC value to distance

//CM is higher than 09 so spilt the variable CM into 2
cmHigh = ( ( cm >> 4 ) & 0x0F ) + 0x30;
cmLow = ( cm & 0x0F ) + 0x30;

lcd_data(cmHigh);
lcd_data(cmLow);
[/COLOR]

}

}
}

Last edited: Sep 16, 2009
20. AtomSoftWell-Known Member

Joined:
Feb 7, 2008
Messages:
5,670
Likes:
41
Location:
Brooklyn, NY US
Its not giving you a long value lol its looping. Try Clearing the LCD before the loop like:

Code (text):

void main(void)
{
init(); // initialise I/O ports, LCD
while(1){
//  home_screen();

// wait for 2 seconds, uses TMR1 free running at 1Mhz
while(!TMR1IF)  // wait for TMR1 overflow
TMR1IF = 0;     // clear overflow flag

bres += 65536;          // add 65536uS to bres value
if(bres >= 2000000)     // if reached 2 seconds!
{
bres -= 2000000;    // subtract 2 seconds, keep error

GODONE=1;   // initiate conversion on the channel 0
while(GODONE) continue;  // Wait convertion done
calc_distance();        // convert ADC value to distance

//CM is higher than 09 so spilt the variable CM into 2
cmHigh = ( ( cm >> 4 ) & 0x0F ) + 0x30;
cmLow = ( cm & 0x0F ) + 0x30;//[b]
lcd_data(cmHigh);
lcd_data(cmLow);

}  //END OF IF
}//END OF WHILE(1)
}//END OF MAIN

21. AtomSoftWell-Known Member

Joined:
Feb 7, 2008
Messages:
5,670
Likes:
41
Location:
Brooklyn, NY US
Sorry i made a few mistakes in my PM code:

Code (text):

void main(void)
{
init();       //initialise I/O ports, LCD
while(1){
//home_screen();

//wait for 2 seconds, uses TMR1 free running at 1Mhz
while(!TMR1IF);             // wait for TMR1 overflow [b] forgot to place ; here[/b]
TMR1IF = 0;         // clear overflow flag

bres += 65536;      // add 65536uS to bres value
if(bres >= 2000000)     // if reached 2 seconds!
{
bres -= 2000000;      // subtract 2 seconds, keep error

GODONE=1;         // initiate conversion on the channel 0
while(GODONE) continue; // Wait convertion done
calc_distance();      // convert ADC value to distance

//CM is higher than 09 so spilt the variable CM into 2 //[b]
cmHigh = ( cm / 10 ) + '0'; // My Mistake this will get you true
cmLow = ( cm % 10 ) + '0';  // values