1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

READING A PUSHBUTTON & display on LCD

Discussion in 'Microcontrollers' started by fantabulous68, Sep 9, 2009.

  1. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    Im trying to use your method of averaging, i included it in RED highlight below....but i keep getting a pointer error...Could you please tell me what im doing wrong?


    Code (text):

    math = ADRESH;
        math = (math * 256);
        math += ADRESL;


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

    void userMenu(char pos); //  
    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(char expire);  
    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 posneg;
    unsigned char LLHigh, LLLow;
    unsigned int LiquidLevel;


         

    #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,[COLOR="Red"][B]adc_temp,adc_actual;  [/B][/COLOR]    // used for voltage calculations


    unsigned char NumDec;
    unsigned char NumSep[2];
       
    unsigned char i,j,k[COLOR="Red"][B],x;[/B][/COLOR]
    //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;


        /* Init ADC */
        ADCON0 = 0b10000101;    // bit 7 right justify,analogue channel select bits bits5-2  0001=AN1,ADC ON, RA1 is ADC input
        ADCON1 = 0b00100000;    //bits6-4  fosc/32
        ADON=1;                 // turn on the A2D conversion module

       
        ANSEL=0x02;            //set RA1 as analog input for GP2 sensor
        ANSELH=0x00;

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



        MyVal = 0; //initializn these variables here
        MyMinVal = 0;
        MyMaxVal = 99;
     
        TRISB=0x00;
        TRISC=0xFC;
       
        lcd_init(); //call LCD initialisation

    }
    //EDITED this a bit. now if expire input is set it will leave loop with a 0
    //instead of rechecking this will be useful for display your measured data and
    //waiting for user to exit.
    char WaitForInput(char expire){
    char done;
    char temp;
    done = 0;
    temp = 0;
    while(!done){
        if(!ENTERSETTINGS_SW){
            while(ENTERSETTINGS_SW);
            temp = 1;
            done = 0xff;
        }

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

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

        if(!DECREASE_SW){
            while(DECREASE_SW);
            temp = 4;
            done = 0xff;
        }
        if(expire == 1) break;
    }//end of while
        DelayMs(150);    //debounce
        return temp;
    }//
    void userMenu(char pos){
        unsigned int delaytime = 100000; // 100ms CHANGE THIS FOR YOUR BELOW DELAY
        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;                          //
            case 3:
                lcd_puts("   MEASURED   ");
                 while(WaitForInput(1) != 2){       //Wait for user to press enter to leave loop

                    // 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 >= delaytime )      // if reached 2 seconds!
                    {
                        bres -= delaytime ; // subtract 2 seconds, keep error
               

                        [COLOR="Red"][B]// read the ADC voltage RA1 (Sharp GP2 sensor)
                                for(x=0;x<3;x++){
                        GODONE=1;                   // initiate conversion on the channel 0
                        while(GODONE) continue;     // Wait convertion done
                        adc_temp[x] = (ADRESH << 4) | ADRESL;
                                            DelayMs(100);
                                      }
                        //Now average the readings
                                            adc_actual = (adc_temp[0] + adc_temp[1] + adc_temp[2]) / 3;

                        calc_distance();            // convert ADC value to distance[/B][/COLOR]

                        lcd_goto_L2();              //Only change line 2
    //
                        if(posneg == 'p')
                            lcd_data('+');
                        else
                            lcd_data('-');
    //
                        lcd_data(LLHigh);
                        lcd_data(LLLow);
                        lcd_puts(" [cm] ");         //comment this out if you want
                   }
            }
            lcd_goto_L1();
            lcd_puts(" Loading Home ");
            lcd_goto_L2();
            lcd_puts("              ");
            DelayS(1);
            break;
        }

        if(pos == 3) return;
        lcd_goto_L2();
        lcd_puts("Press Up/Down"); //home screen message (line 2)
    }

    // New Menu System
    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
    }

     
    void calc_distance(void)
    {
        unsigned int tmp;
    unsigned int mathKeep;      // used for voltage calculations backup
        // 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

        // load ADC value in 16bit math var
        math = ADRESH;
        math = (math * 256);
        math += ADRESL;

        // 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

        //Create a copy of math for more use
        mathKeep = math;
        //LiquidLevel=height-; 

        // convert from 0-99 to 2 decimal digits, 0-99cm
        cm10=0;
        while(math >= 10)
        {
            cm10++;
            math -= 10;
        }
        cm = math;

        math = mathKeep;    //Now our original data is back and can be used.
        //This will check if negative
        LiquidLevel=height-math;   

    //
        posneg = 'p';
            if((LiquidLevel < 0) || (LiquidLevel > 0xFF00)){
            LiquidLevel = -LiquidLevel ;
            posneg = 'n';
        }
    //
        //if below zero which will be in the 0xFFFF range i just chose any 0xFFxx number :D
          //LiquidLevel is higher than 09 so spilt the variable LiquidLevel into 2 //
          LLHigh = ( LiquidLevel / 10 ) + '0'; //
          LLLow = ( LiquidLevel % 10 ) + '0';  //
         


    }
     //
    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(0);
           
          switch(input_sw){
            case 1:
                done = 0xff;            //This tells us the user finished entering
                lcd_goto_L1();
                lcd_puts("      OK       "); //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;
          }
         
        }
        DelayMs(250);
        DelayMs(250);
        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(0);

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

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

        userMenu(2);
        DelayMs(2);             //shorter delay
        area = user_input();    //The HEIGHT var will have the myVal
    //
        userMenu(3);
        DelayMs(2);             //shorter delay
        input_sw = 0;           //Reset the value

    //Waits for user to press ENTER to show home screen
    /*
    "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();

     /*// 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
               
            // read the ADC voltage RA1 (Sharp GP2 sensor)
            GODONE=1;   // initiate conversion on the channel 0
            while(GODONE) continue;  // Wait convertion done
            calc_distance();        // convert ADC value to distance
        //  LiquidLevel=height-;
        //  lcd_clear();                // Using the new menu you can erase or
        //  lcd_data(cm10 + '0');
        //  lcd_data(cm + '0');
         //   lcd_goto_L2();
           // lcd_puts("[cm] ");            //comment this out if you want
    */
     
         
           
                 
     
       }
    }
     
     
    Last edited: Sep 24, 2009
  2. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    im going to try the 2 methods suggested to see which gives me a more accurate measurement...

    Methods being:
    1. Your Averaging of 3 adc values
    2. Noggins Digital filter
     
  3. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,022
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    You need to change the declaration to,
    Code (text):

    unsigned int math,adc_temp[COLOR="Red"][3][/COLOR],adc_actual;      // used for voltage calculations
     
    Also, shouldn't this line
    Code (text):

    adc_temp[x] = (ADRESH << 4) | ADRESL;
     
    be,
    Code (text):

    adc_temp[x] = (ADRESH << [COLOR="Red"]8[/COLOR]) | ADRESL;
     
    Mike.
     
  4. dave

    Dave New Member

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


     
  5. fantabulous68

    fantabulous68 Member

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

    Thanks Pommie
     
  6. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    How do i split adc_actual into a high and low so i can assign it to math in the calc_distance function?
    Code (text):


    [COLOR="DarkOrchid"][B] // load ADC value in 16bit math var[/B][/COLOR]
        [COLOR="Red"][B]math = ADRESH;
        math = (math * 256);
        math += ADRESL;[/B][/COLOR]
    I highlighted the code below:

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

    void userMenu(char pos); //  
    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(char expire);  
    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 posneg;
    unsigned char LLHigh, LLLow;
    unsigned int LiquidLevel;


         

    #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,adc_temp[3],adc_actual;       // used for voltage calculations


    unsigned char NumDec;
    unsigned char NumSep[2];
       
    unsigned char i,j,k,x;
    //char temp[8];

    unsigned char height=50;
    unsigned char range;
    unsigned char area;
    unsigned char SensorPos=10;
    // 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;


        /* Init ADC */
        ADCON0 = 0b10000101;    // bit 7 right justify,analogue channel select bits bits5-2  0001=AN1,ADC ON, RA1 is ADC input
        ADCON1 = 0b00100000;    //bits6-4  fosc/32
        ADON=1;                 // turn on the A2D conversion module

       
        ANSEL=0x02;            //set RA1 as analog input for GP2 sensor
        ANSELH=0x00;

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



        MyVal = 0; //initializn these variables here
        MyMinVal = 0;
        MyMaxVal = 99;
     
        TRISB=0x00;
        TRISC=0xFC;
       
        lcd_init(); //call LCD initialisation

    }
    //EDITED this a bit. now if expire input is set it will leave loop with a 0
    //instead of rechecking this will be useful for display your measured data and
    //waiting for user to exit.
    char WaitForInput(char expire){
    char done;
    char temp;
    done = 0;
    temp = 0;
    while(!done){
        if(!ENTERSETTINGS_SW){
            while(ENTERSETTINGS_SW);
            temp = 1;
            done = 0xff;
        }

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

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

        if(!DECREASE_SW){
            while(DECREASE_SW);
            temp = 4;
            done = 0xff;
        }
        if(expire == 1) break;
    }//end of while
        DelayMs(150);    //debounce
        return temp;
    }//
    void userMenu(char pos){
        unsigned int delaytime = 100000; // 100ms CHANGE THIS FOR YOUR BELOW DELAY
        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;                          //
            case 3:
                lcd_puts("   MEASURED   ");
                 while(WaitForInput(1) != 2){       //Wait for user to press enter to leave loop

                    // 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 >= delaytime )      // if reached 2 seconds!
                    {
                        bres -= delaytime ; // subtract 2 seconds, keep error
               

                        // read the ADC voltage RA1 (Sharp GP2 sensor)
                                for(x=0;x<3;x++){
                        GODONE=1;                   // initiate conversion on the channel 0
                        while(GODONE) continue;     // Wait convertion done
                        adc_temp[x] = (ADRESH << 8) | ADRESL;
                                            DelayMs(100);
                                      }
                        //Now average the readings
                                            [COLOR="Red"][B]adc_actual = (adc_temp[0] + adc_temp[1] + adc_temp[2]) / 3;[/B][/COLOR]

                        calc_distance();            // convert ADC value to distance

                        lcd_goto_L2();              //Only change line 2
    //
                        if(posneg == 'p')
                            lcd_data('+');
                        else
                            lcd_data('-');
    //
                        lcd_data(LLHigh);
                        lcd_data(LLLow);
                        lcd_puts(" [cm] ");         //comment this out if you want
                   }
            }
            lcd_goto_L1();
            lcd_puts(" Loading Home ");
            lcd_goto_L2();
            lcd_puts("              ");
            DelayS(1);
            break;
        }

        if(pos == 3) return;
        lcd_goto_L2();
        lcd_puts("Press Up/Down"); //home screen message (line 2)
    }

    // New Menu System
    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"][B]void calc_distance(void)[/B][/COLOR]
    {
        unsigned int tmp;
    unsigned int mathKeep;      // used for voltage calculations backup
        // 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

    [COLOR="DarkOrchid"][B] // load ADC value in 16bit math var[/B][/COLOR]
        [COLOR="Red"][B]math = ADRESH;
        math = (math * 256);
        math += ADRESL;[/B][/COLOR]

        // 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

        //Create a copy of math for more use
        mathKeep = math;
        //LiquidLevel=height-; 

        // convert from 0-99 to 2 decimal digits, 0-99cm
        cm10=0;
        while(math >= 10)
        {
            cm10++;
            math -= 10;
        }
        cm = math;

        math = mathKeep;    //Now our original data is back and can be used.
        //This will check if negative
        LiquidLevel=height-math;   

    //
        posneg = 'p';
            if((LiquidLevel < 0) || (LiquidLevel > 0xFF00)){
            LiquidLevel = -LiquidLevel ;
            posneg = 'n';
        }
    //
        //if below zero which will be in the 0xFFFF range i just chose any 0xFFxx number :D
          //LiquidLevel is higher than 09 so spilt the variable LiquidLevel into 2 //
          LLHigh = ( LiquidLevel / 10 ) + '0'; //
          LLLow = ( LiquidLevel % 10 ) + '0';  //
         


    }
     //
    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(0);
           
          switch(input_sw){
            case 1:
                done = 0xff;            //This tells us the user finished entering
                lcd_goto_L1();
                lcd_puts("      OK       "); //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;
          }
         
        }
        DelayMs(250);
        DelayMs(250);
        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(0);

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

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

        userMenu(2);
        DelayMs(2);             //shorter delay
        area = user_input();    //The HEIGHT var will have the myVal
    //
        userMenu(3);
        DelayMs(2);             //shorter delay
        input_sw = 0;           //Reset the value

    //Waits for user to press ENTER to show home screen
    /*
    "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();
     
                 
     
       }
    }
     
     
  7. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,022
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    You can just do, math=adc_actual;

    Mike.
     
  8. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Try :
    Code (text):


        // load ADC value in 16bit math var
        math = (adc_actual >> 8) & 0x00FF;
        math = (math * 256);
        math += adc_actual & 0x00FF;

     
     
  9. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there

    I prefer this technique; it only needs to take 1 new reading, then averages that with the 3 previous readings.

    Code (text):

        GODONE=1;
        while(GODONE) continue;
        adc_temp[x] = (ADRESH << 8) | ADRESL;
        x++;
        x = (x & 0x03); //(or bcf x,2 or x.F2=0 on a better compiler)

        adc_actual = (adc_temp[0] + adc_temp[1] + adc_temp[2]
             + adc_temp[3] +2) / 4;
     
    Also note the +2 (ie +4/2) in the averaging calc to remove your averaging rounding down error. :)
     
    Last edited: Sep 24, 2009
  10. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    if your taking 1 new reading and average it with last actual reading then you might have big error there not in code but actual data


    If reading 1 was 10 CM
    If reading 2 was 9 CM
    If new reading is 2 CM

    Your average is:
    10 + 9 + 2 + 2 = 23 / 4 = 5.75

    Now is that anything near the 2 that was read ?

    also change :
    adc_temp[x] = (ADRESH << 4) | ADRESL;

    to

    adc_temp[x] = (ADRESH << 8) | ADRESL;
     
    Last edited: Sep 24, 2009
  11. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there
    Sure, but in most cases you read the sensor constantly, as part of a timed loop process. So the 4 readings in the circular buffer are always the 4 most recent readings.

    Then whenever you need to "read" the filtered ADC value you just average the readings that are already in the circular buffer.
     
  12. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US
    Just 1 more thing :D

    What would the first reading average out with ? 0 + 0 + 3 + 2 ? (3 = new reading)
    then the second 0 + 3 + 4 + 2 (4 = new reading)
     
    Last edited: Sep 24, 2009
  13. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there
    Hehe well...
    1. that's exactly the same issue you mentioned in your other post (not 1 "more" thing)
    2. that is EXACTLY what filter averaging does; average the most recent values it has available

    Are we having a circular argument about a circular buffer??? :eek:
    :D
     
  14. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    :rolleyes:So whose method should i use?:rolleyes:
    lol You'll know we girls can never make our mind up....now im faced with 2 ways of averaging values....what to do???...now i need help to decide:D:D:D
     
    Last edited: Sep 24, 2009
  15. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,022
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    It doesn't matter which you use, RB's is a little more efficient. However, you may not need to average at all, the error in the line,
    Code (text):

    adc_temp[x] = (ADRESH << 4) | ADRESL;
     
    would be enough to throw your readings off by a lot.

    Mike.
     
    Last edited: Sep 24, 2009
  16. AtomSoft

    AtomSoft Well-Known Member

    Joined:
    Feb 7, 2008
    Messages:
    5,670
    Likes:
    41
    Location:
    Brooklyn, NY US

    Hehe yeah i usually forget things like that but placing a BOLD would help too :D

    Code (text):

    adc_temp[x] = (ADRESH <<[B] [COLOR="Red"]4[/COLOR][/B]) | ADRESL;
     
    to

    Code (text):

    adc_temp[x] = (ADRESH << [B][COLOR="Red"]8[/COLOR][/B]) | ADRESL;
     
    ...Pommie hows it going? Anything new?
     
    Last edited: Sep 24, 2009
  17. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,022
    Likes:
    317
    Location:
    Brisbane Australia
    ONLINE
    Hi Jason,

    It's going good. Just writing a BoostC menu system. Will post it in a day or so.

    Mike.
     
  18. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    :):):)Thanx Pommie...AtomSoft & Mr RB.:):):)
    Yeah i made the changes in highlight below...i hope its fine to say that this method of averaging is ready to be tested as well....:)

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

    void userMenu(char pos); //  
    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(char expire);  
    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 posneg;
    unsigned char LLHigh, LLLow;
    unsigned int LiquidLevel;


         

    #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,adc_temp[3],adc_actual;       // used for voltage calculations


    unsigned char NumDec;
    unsigned char NumSep[2];
       
    unsigned char i,j,k,x;
    //char temp[8];

    unsigned char height=50;
    unsigned char range;
    unsigned char area;
    unsigned char SensorPos=10;
    // 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;


        /* Init ADC */
        ADCON0 = 0b10000101;    // bit 7 right justify,analogue channel select bits bits5-2  0001=AN1,ADC ON, RA1 is ADC input
        ADCON1 = 0b00100000;    //bits6-4  fosc/32
        ADON=1;                 // turn on the A2D conversion module

       
        ANSEL=0x02;            //set RA1 as analog input for GP2 sensor
        ANSELH=0x00;

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



        MyVal = 0; //initializn these variables here
        MyMinVal = 0;
        MyMaxVal = 99;
     
        TRISB=0x00;
        TRISC=0xFC;
       
        lcd_init(); //call LCD initialisation

    }
    //EDITED this a bit. now if expire input is set it will leave loop with a 0
    //instead of rechecking this will be useful for display your measured data and
    //waiting for user to exit.
    char WaitForInput(char expire){
    char done;
    char temp;
    done = 0;
    temp = 0;
    while(!done){
        if(!ENTERSETTINGS_SW){
            while(ENTERSETTINGS_SW);
            temp = 1;
            done = 0xff;
        }

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

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

        if(!DECREASE_SW){
            while(DECREASE_SW);
            temp = 4;
            done = 0xff;
        }
        if(expire == 1) break;
    }//end of while
        DelayMs(150);    //debounce
        return temp;
    }//
    void userMenu(char pos){
        unsigned int delaytime = 100000; // 100ms CHANGE THIS FOR YOUR BELOW DELAY
        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;                          //
            case 3:
                lcd_puts("   MEASURED   ");
                 while(WaitForInput(1) != 2){       //Wait for user to press enter to leave loop

                    // 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 >= delaytime )      // if reached 2 seconds!
                    {
                        bres -= delaytime ; // subtract 2 seconds, keep error
               





       

       



                        // read the ADC voltage RA1 (Sharp GP2 sensor)
                           [COLOR="Red"][B]
                        GODONE=1;                   // initiate conversion on the channel 0
                        while(GODONE) continue;     // Wait convertion done
                        [COLOR="SeaGreen"]adc_temp[x] = (ADRESH << 8) | ADRESL;[/COLOR]
                        x++;
                        x = (x & 0x03); //(or bcf x,2 or x.F2=0 on a better compiler)
                        //Now average the readings
                        adc_actual = (adc_temp[0] + adc_temp[1] + adc_temp[2]+ adc_temp[3] +2) / 4;
                       [/B][/COLOR]
                   
                                       

                        calc_distance();            // convert ADC value to distance

                        lcd_goto_L2();              //Only change line 2
    //
                        if(posneg == 'p')
                            lcd_data('+');
                        else
                            lcd_data('-');
    //
                        lcd_data(LLHigh);
                        lcd_data(LLLow);
                        lcd_puts(" [cm] ");         //comment this out if you want
                   }
            }
            lcd_goto_L1();
            lcd_puts(" Loading Home ");
            lcd_goto_L2();
            lcd_puts("              ");
            DelayS(1);
            break;
        }

        if(pos == 3) return;
        lcd_goto_L2();
        lcd_puts("Press Up/Down"); //home screen message (line 2)
    }

    // New Menu System
    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
    }

       
    void calc_distance(void)
    {
        unsigned int tmp;
        unsigned int mathKeep;      // used for voltage calculations backup
        // 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

        // load ADC value in 16bit math var
        //math = ADRESH;
        //math = (math * 256);
        //math += ADRESL;

        [COLOR="DarkOrchid"][B]// load ADC value in 16bit math var
        math = (adc_actual >> 8) & 0x00FF;
        math = (math * 256);
        math += adc_actual & 0x00FF;[/B][/COLOR]


        // 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

        //Create a copy of math for more use
        mathKeep = math;
        //LiquidLevel=height-; 

        // convert from 0-99 to 2 decimal digits, 0-99cm
        cm10=0;
        while(math >= 10)
        {
            cm10++;
            math -= 10;
        }
        cm = math;

        math = mathKeep;    //Now our original data is back and can be used.
        //This will check if negative
        LiquidLevel=height-math;   

    //
        posneg = 'p';
            if((LiquidLevel < 0) || (LiquidLevel > 0xFF00)){
            LiquidLevel = -LiquidLevel ;
            posneg = 'n';
        }
    //
        //if below zero which will be in the 0xFFFF range i just chose any 0xFFxx number :D
          //LiquidLevel is higher than 09 so spilt the variable LiquidLevel into 2 //
          LLHigh = ( LiquidLevel / 10 ) + '0'; //
          LLLow = ( LiquidLevel % 10 ) + '0';  //
         


    }
     //
    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(0);
           
          switch(input_sw){
            case 1:
                done = 0xff;            //This tells us the user finished entering
                lcd_goto_L1();
                lcd_puts("      OK       "); //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;
          }
         
        }
        DelayMs(250);
        DelayMs(250);
        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(0);

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

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

        userMenu(2);
        DelayMs(2);             //shorter delay
        area = user_input();    //The HEIGHT var will have the myVal
    //
        userMenu(3);
        DelayMs(2);             //shorter delay
        input_sw = 0;           //Reset the value

    //Waits for user to press ENTER to show home screen
    /*
    "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();
     
                 
     
       }
    }
     

     
    Last edited: Sep 24, 2009
  19. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    OK so i finally tested the "infrared liquid level detector" out with the last code that i posted on this thread....(averaging the 4 sensor readings)

    i used a clear glass vessel. NO FLOATER. The sensor was Perpendicular to the surface of the liquid(Used a level Eye to verify this)

    Tested 3 different liquids:
    1. water,
    2. handy andy(thick white liquid),
    3. sunlight liquid(thick green liquid)

    The readings are more stable than before(prior tests i conducted) even when measuring the varying liquid level of water. Not fluctuating as much.

    1. Inaccurate reading with water
    2. Accurate reading with thick white liquid
    3. Inaccurate reading with thick green liquid
     
    Last edited: Oct 1, 2009
  20. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there
    You can't use a level eye to set the sensor angle! The infrared beam may not come out at exactly 90 degrees to the sensor casing.

    I was able to get to get good readings from the water surface but had to hold the sensor at just the right angle where it got good readings. It's very close to perpendicular but you need to "tweak" the angle until it works, then keep it at that same angle.

    The reflected signal is small from the water surface, and it's very flat (very good mirror) so it reflects the beam back in a very small area, so the sensor angle is critical.
     
  21. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    Does that mean i got 2 keep tweaking it for different liquids as well???So every liquid got to be held at a fixed angle at which it works?????

    Im asking because i will have to demonstrate the project....& external examiners are usually not very patient people.....

    Or maybe i can get a stand with a rotating tuner i can attach the sensor to-that will enable me to change the angle....?????
     
    Last edited: Oct 1, 2009

Share This Page