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. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there
    Well you are still using the averaging code?

    Average over a much longer operiod of time, like average 32 samples over 1 whole second.

    If the "slosh" frequency is very slow (ie large container) then average over a longer time still.
     
  2. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    Yeah i am still using the averaging code....i never implement Noggins digital filter because the liquid level eventually displays the "height" the user enters as the liquid level...Im stumped over why that happens....

    Yeah OK......................I will try averaging over 32 samples, Thanx
     
  3. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    Uhmmm i tried that, highlighted in red below, but i get compiler errors

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

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

    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 the 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//////////////////////////
       
    ///////////INITIALISING PORTS, REGISTERS, CLOCK/////////////////

    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

    }
    /////////////////////////End INITIALISING PORTS, REGISTERS, CLOCK///////////////////////

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

    //This function determines which button the user pressed.  It assigns the variable "temp" a number
    //which corresponds to a certain button press. Example if "temp" equals:
    //1---->ENTER/SETTINGS button was pressed
    //2---->HOME button was pressed
    //3---->INCREASE button was pressed
    //4---->DECREASE button was pressed


    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;
    }//
    //////////////////End WaitForInput///////////////////

    //////////////////////////////////////////////////////userMenu///////////////////////////////////////////////////////

    //This is the User Menu.  Once the "ENTER/SETTINGS" button is pressed, the user enters this menu.
    // This menu promps the user to enter the HEIGHT(ie. The distance between the IR sensor & the base of the container)
    //
    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 button 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)
                           
                        GODONE=1;                   // initiate conversion on the channel 0
                        while(GODONE) continue;     // Wait convertion done
                        adc_temp[x] = (ADRESH << 8) | ADRESL;
                        x++;
                        x = (x & 0x03); //(or bcf x,2 or x.F2=0 on a better compiler)
                        //Now average the readings
    [B][COLOR="Red"]                    adc_actual = (adc_temp[0] + adc_temp[1] + adc_temp[2]+ adc_temp[3]+ adc_temp[4]+ adc_temp[5]+ adc_temp[6]+ adc_temp[7]+ adc_temp[8]+ adc_temp[9]+adc_temp[10]+ adc_temp[11]+adc_temp[12]+ adc_temp[13]+ adc_temp[14]+adc_temp[15]+adc_temp[16]+adc_temp[17]+ adc_temp[18]+ adc_temp[19]+ adc_temp[20]+adc_temp[21]+ adc_temp[22]+ adc_temp[23]+ adc_temp[24]+ adc_temp[25]+ adc_temp[26]+ adc_temp[27]+ adc_temp[28]+ adc_temp[29]+ adc_temp[30]+ adc_temp[31]  +2) / 32;[/COLOR][/B]
                       
                   
                                       

                        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)
    }
    //////////////////////End userMenu///////////////////////////

    /////////////////////EnterScreen/////////////////////////////

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

    ////////////////////////ShowDigits////////////////////////////
    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
    }
    ////////////////////End ShowDigits////////////////////////////
       

    ///////////////////////calc_distance//////////////////////////
    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 = (adc_actual >> 8) & 0x00FF;
        math = (math * 256);
        math += adc_actual & 0x00FF;

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


        // 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';  //
    }
     
    ////////////////////End calc_distance//////////////////////////

    ///////////////////////user_input//////////////////////////////

    unsigned char user_input(void) 
    {
        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 by displaying "OK"
                lcd_goto_L1();
                lcd_puts("      OK       ");
                break;


    //The User will be prompted to enter the "HEIGHT" in userMenu(). The LCD will Display:

    //          HEIGHT     
    //      Press Up/Down

    //Up------->represented by INCREASE Button
    //Down----->represented by DECREASE Button
    // The user can enter "HEIGHT" values from [0-99]cm because
    //  MyMinVal = 0;
    //  MyMaxVal = 99;

    ///Now the variable MyVal is used in user_input() to represent this "HEIGHT" value.


    //If User presses the INCREASE button:
            case 3:
                if(MyVal < MyMaxVal)    //checks if MyVal<99
                    MyVal++;            //Increases MyVal when INCREASE button is pressed
                EnterScreen();          //Displays "[cm]" in Line 1
                ShowDigits(MyVal);      //Splits MyVal into 2 separate digits, then convert digits to ASCII
                                        //so it can be displayed on  the LCD screen
                break;

    //If the User presses the DECREASE button:
            case 4:
                if(MyVal > MyMinVal)    //checks if MyVal>0
                    MyVal--;            //Decreases MyVal when DECREASE button is pressed
                EnterScreen();          //Displays "[cm]" in Line 1
                ShowDigits(MyVal);      //Splits MyVal into 2 separate digits, then convert digits to ASCII
                                        //so it can be displayed on  the LCD screen
                break;             
            default:
                break;
          }
        }
        DelayMs(250);                   //switch debouncing        
        DelayMs(250);                   //switch debouncing
           
        return MyVal;//This will return MyVal which represents the "HEIGHT".  The height var will be assigned myVal in home_screen()
                     //height = user_input() in home_screen.  This will be used in calc_distance() to calculate the Liquid Leval.
    }

    /////////////////////////End user_input//////////////////////////////


    ///////////////////////////home_screen///////////////////////////////
    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 of the button the user presses

        while(input_sw != 1)            //Wait until ENTER button 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 of the button the user presses


    }
    ///////////////////////////End home_screen///////////////////////////////

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

    compile errors
    ok so I'm guessing that the array cant hold 32 values because its capacity doesn't cater for that.............what am i doing wrong? . Im still new to programming with the PIC, have mercy:confused:
     
  4. dave

    Dave New Member

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


     
  5. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,161
    Likes:
    340
    Location:
    Brisbane Australia

    I'm guessing, as I don't use the HiTech compiler, that it doesn't like lines as long as,
    Code (text):

        adc_actual = (adc_temp[0] + adc_temp[1] + adc_temp[2]+ adc_temp[3]+ adc_temp[4]+ adc_temp[5]+ adc_temp[6]+ adc_temp[7]+ adc_temp[8]+ adc_temp[9]+adc_temp[10]+ adc_temp[11]+adc_temp[12]+ adc_temp[13]+ adc_temp[14]+adc_temp[15]+adc_temp[16]+adc_temp[17]+ adc_temp[18]+ adc_temp[19]+ adc_temp[20]+adc_temp[21]+ adc_temp[22]+ adc_temp[23]+ adc_temp[24]+ adc_temp[25]+ adc_temp[26]+ adc_temp[27]+ adc_temp[28]+ adc_temp[29]+ adc_temp[30]+ adc_temp[31]  +2) / 32;
     
    Try using a loop to add up your values,
    Code (text):

        x = (x & 0x1f);             //wrap x so x = 0 to 31
        adc_actual=0;       //initialise total
        for(i=0;i<32;i++){          //loop 32 times
        adc_actual+=adc_temp[i];//add all the values
        }
        adc_actual/=32;             //and divide by 32
    I didn't check if it is safe to use i as it is a global variable. I also assume x is not used elsewhere in the program.

    Mike.
     
  6. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    i didnt use a loop because of the +2
    (..............adc_temp[30]+ adc_temp[31] +2) / 32;


    Thanx though Pommie, i did think about using a loop as well, seems more efficient .

    Does THAT +2 make a significant difference if I omit it???

    Ill try the loop idea later without adding the 2.
     
    Last edited: Oct 15, 2009
  7. Pommie

    Pommie Well-Known Member Most Helpful Member

    Joined:
    Mar 18, 2005
    Messages:
    10,161
    Likes:
    340
    Location:
    Brisbane Australia
    The +2 is to eliminate rounding errors and is half the number of samples so should actually be changed to 16. If you still want to use it then you can change the code to be,
    Code (text):

        x = (x & 0x1f);             //wrap x so x = 0 to 31
        adc_actual=[COLOR="Red"]16[/COLOR];         //initialise total
        for(i=0;i<32;i++){          //loop 32 times
        adc_actual+=adc_temp[i];//add all the values
        }
        adc_actual/=32;             //and divide by 32
     
    In reality it will not make much difference.

    Mike.
     
    Last edited: Oct 15, 2009
  8. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    I tried your method Pommie, its the same as MR RB's.

    Then I tried MR RB method, he averaged by 4.

    I averaged by 10 numbers, hi-tech allows that.....however the sensor gives incorrect values for a SOLID white object

    then i averaged by 8, then 6, then 5 & it had the same outcome......

    BUT when i average by 4 as MR RB did then the readings are accurate for solid objects....
    that means i cant average by more than 4 samples to get rid of fluctuations from the liquid surface:eek:

    Now what options does that leave me with in order to get rid of fluctuating readings from liquid surfaces????



    by the way hi-tech allows an array to have a max of 30 values, thats why 32 samples were giving compile errors.
     
  9. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    Is there a possible way for me to modulate the transmitting signal.
    Then receive the modulated signal
    Then demodulate the signal to receive the output voltage from the sharp sensor.

    Now this will give instantaneous measurements...but this may include possible fluctuating measurements...
    So i should include a loop in the programming for calculating the moving average of the displayed measurements...

    That should eliminate unwanted signals and well as unstable measurements...

    What do you'll think???


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

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

    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 the 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//////////////////////////
       
    ///////////INITIALISING PORTS, REGISTERS, CLOCK/////////////////

    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

    }
    /////////////////////////End INITIALISING PORTS, REGISTERS, CLOCK///////////////////////

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

    //This function determines which button the user pressed.  It assigns the variable "temp" a number
    //which corresponds to a certain button press. Example if "temp" equals:
    //1---->ENTER/SETTINGS button was pressed
    //2---->HOME button was pressed
    //3---->INCREASE button was pressed
    //4---->DECREASE button was pressed


    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;
    }//
    //////////////////End WaitForInput///////////////////

    //////////////////////////////////////////////////////userMenu///////////////////////////////////////////////////////

    //This is the User Menu.  Once the "ENTER/SETTINGS" button is pressed, the user enters this menu.
    // This menu promps the user to enter the HEIGHT(ie. The distance between the IR sensor & the base of the container)
    //
    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 button 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)
                           
                        GODONE=1;                   // initiate conversion on the channel 0
                        while(GODONE) continue;     // Wait convertion done
                        adc_temp[x] = (ADRESH << 8) | ADRESL;
                        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]+adc_temp[4] +2.5) / 5;
     
                   
                                       

                        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)
    }
    //////////////////////End userMenu///////////////////////////

    /////////////////////EnterScreen/////////////////////////////

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

    ////////////////////////ShowDigits////////////////////////////
    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
    }
    ////////////////////End ShowDigits////////////////////////////
       

    ///////////////////////calc_distance//////////////////////////
    /*RomanBlack.com 19th July 2009.
    uses my "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*/


    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 = (adc_actual >> 8) & 0x00FF;
        math = (math * 256);
        math += adc_actual & 0x00FF;

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


        // 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';  //
    }
     
    ////////////////////End calc_distance//////////////////////////

    ///////////////////////user_input//////////////////////////////

    unsigned char user_input(void) 
    {
        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 by displaying "OK"
                lcd_goto_L1();
                lcd_puts("      OK       ");
                break;


    //The User will be prompted to enter the "HEIGHT" in userMenu(). The LCD will Display:

    //          HEIGHT     
    //      Press Up/Down

    //Up------->represented by INCREASE Button
    //Down----->represented by DECREASE Button
    // The user can enter "HEIGHT" values from [0-99]cm because
    //  MyMinVal = 0;
    //  MyMaxVal = 99;

    ///Now the variable MyVal is used in user_input() to represent this "HEIGHT" value.


    //If User presses the INCREASE button:
            case 3:
                if(MyVal < MyMaxVal)    //checks if MyVal<99
                    MyVal++;            //Increases MyVal when INCREASE button is pressed
                EnterScreen();          //Displays "[cm]" in Line 1
                ShowDigits(MyVal);      //Splits MyVal into 2 separate digits, then convert digits to ASCII
                                        //so it can be displayed on  the LCD screen
                break;

    //If the User presses the DECREASE button:
            case 4:
                if(MyVal > MyMinVal)    //checks if MyVal>0
                    MyVal--;            //Decreases MyVal when DECREASE button is pressed
                EnterScreen();          //Displays "[cm]" in Line 1
                ShowDigits(MyVal);      //Splits MyVal into 2 separate digits, then convert digits to ASCII
                                        //so it can be displayed on  the LCD screen
                break;             
            default:
                break;
          }
        }
        DelayMs(250);                   //switch debouncing        
        DelayMs(250);                   //switch debouncing
           
        return MyVal;//This will return MyVal which represents the "HEIGHT".  The height var will be assigned myVal in home_screen()
                     //height = user_input() in home_screen.  This will be used in calc_distance() to calculate the Liquid Leval.
    }

    /////////////////////////End user_input//////////////////////////////


    ///////////////////////////home_screen///////////////////////////////
    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 of the button the user presses

        while(input_sw != 1)            //Wait until ENTER button 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 of the button the user presses


    }
    ///////////////////////////End home_screen///////////////////////////////

    //////////////////////main//////////////////////
    void main(void)
    {  
        init(); // initialise I/O ports, LCD
        while(1){
        home_screen();
     
                 
     
       }  
    }
    //////////////////End main//////////////////////
     
     
    Last edited: Oct 15, 2009
  10. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there
    Pommie's code in post186 looks good. Just make sure adc_actual is a long type variable.

    The sensor has a time limit between changing output samples, there's not point averaging too quickly. Also you should average over a much longer total period than any one ripple or "slosh". If you use Pommie's averaging code you could just put a 30mS delay in the loop (between each ADC reading) so that will be about 32 samples over 1 second.
     
  11. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    I made the changes you suggested in RED HIGHLIGHT below.....using Pommies code. However the SENSOR stops taking continuous readings. When the measuring process starts, its just STUCK on 1 reading....the readings are not changing when i move an object up and down under the sensor.:confused:Whats the problem? i changed adc_actual to long int. Is averaging by 32 samples slowing down the sensor drastically ???..............


    The same thing happened Yesterday when i used MR RB's averaging method with 30 samples instead of 4.....

    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 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[32];[/B][/COLOR]     // used for voltage calculations
    long int [COLOR="Red"][B]adc_actual;[/B][/COLOR]
    unsigned char NumDec;
    unsigned char NumSep[2];
       
    unsigned char i,j,k,x;

    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 the 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//////////////////////////
       
    ///////////INITIALISING PORTS, REGISTERS, CLOCK/////////////////

    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

    }
    /////////////////////////End INITIALISING PORTS, REGISTERS, CLOCK///////////////////////

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

    //This function determines which button the user pressed.  It assigns the variable "temp" a number
    //which corresponds to a certain button press. Example if "temp" equals:
    //1---->ENTER/SETTINGS button was pressed
    //2---->HOME button was pressed
    //3---->INCREASE button was pressed
    //4---->DECREASE button was pressed


    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;
    }//
    //////////////////End WaitForInput///////////////////

    //////////////////////////////////////////////////////userMenu///////////////////////////////////////////////////////

    //This is the User Menu.  Once the "ENTER/SETTINGS" button is pressed, the user enters this menu.
    // This menu promps the user to enter the HEIGHT(ie. The distance between the IR sensor & the base of the container)
    //
    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 button 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)
                           
                        GODONE=1;                   // initiate conversion on the channel 0
                        while(GODONE) continue;     // Wait convertion done
                        adc_temp[x] = (ADRESH << 8) | ADRESL;
                        x++;
                        x = (x & 0x03); //(or bcf x,2 or x.F2=0 on a better compiler)
                        //Now average the readings
                    [B][COLOR="Red"]    x = (x & 0x1f);             //wrap x so x = 0 to 31
                        adc_actual=16;          //initialise total
                        for(i=0;i<32;i++){          //loop 32 times
                            adc_actual+=adc_temp[i];//add all the values
                            DelayMs(30);   
                          }
                        adc_actual/=32;             //and divide by 32
    [/COLOR][/B]
     
                   
                                       

                        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)
    }
    //////////////////////End userMenu///////////////////////////

    /////////////////////EnterScreen/////////////////////////////

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

    ////////////////////////ShowDigits////////////////////////////
    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
    }
    ////////////////////End ShowDigits////////////////////////////
       

    ///////////////////////calc_distance//////////////////////////
    /*RomanBlack.com 19th July 2009.
    uses my "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*/


    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 = (adc_actual >> 8) & 0x00FF;
        math = (math * 256);
        math += adc_actual & 0x00FF;

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


        // 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';  //
    }
     
    ////////////////////End calc_distance//////////////////////////

    ///////////////////////user_input//////////////////////////////

    unsigned char user_input(void) 
    {
        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 by displaying "OK"
                lcd_goto_L1();
                lcd_puts("      OK       ");
                break;


    //The User will be prompted to enter the "HEIGHT" in userMenu(). The LCD will Display:

    //          HEIGHT     
    //      Press Up/Down

    //Up------->represented by INCREASE Button
    //Down----->represented by DECREASE Button
    // The user can enter "HEIGHT" values from [0-99]cm because
    //  MyMinVal = 0;
    //  MyMaxVal = 99;

    ///Now the variable MyVal is used in user_input() to represent this "HEIGHT" value.


    //If User presses the INCREASE button:
            case 3:
                if(MyVal < MyMaxVal)    //checks if MyVal<99
                    MyVal++;            //Increases MyVal when INCREASE button is pressed
                EnterScreen();          //Displays "[cm]" in Line 1
                ShowDigits(MyVal);      //Splits MyVal into 2 separate digits, then convert digits to ASCII
                                        //so it can be displayed on  the LCD screen
                break;

    //If the User presses the DECREASE button:
            case 4:
                if(MyVal > MyMinVal)    //checks if MyVal>0
                    MyVal--;            //Decreases MyVal when DECREASE button is pressed
                EnterScreen();          //Displays "[cm]" in Line 1
                ShowDigits(MyVal);      //Splits MyVal into 2 separate digits, then convert digits to ASCII
                                        //so it can be displayed on  the LCD screen
                break;             
            default:
                break;
          }
        }
        DelayMs(250);                   //switch debouncing        
        DelayMs(250);                   //switch debouncing
           
        return MyVal;//This will return MyVal which represents the "HEIGHT".  The height var will be assigned myVal in home_screen()
                     //height = user_input() in home_screen.  This will be used in calc_distance() to calculate the Liquid Leval.
    }

    /////////////////////////End user_input//////////////////////////////


    ///////////////////////////home_screen///////////////////////////////
    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 of the button the user presses

        while(input_sw != 1)            //Wait until ENTER button 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 of the button the user presses


    }
    ///////////////////////////End home_screen///////////////////////////////

    //////////////////////main//////////////////////
    void main(void)
    {  
        init(); // initialise I/O ports, LCD
        while(1){
        home_screen();
     
                 
     
       }  
    }
    //////////////////End main//////////////////////
     
     
  12. Mr RB

    Mr RB Well-Known Member

    Joined:
    Jul 22, 2008
    Messages:
    4,716
    Likes:
    194
    Location:
    Out there
    :D
    You need to actually TEST the adc voltage in the loop, so you test it 32 times.

    You are testing it BEFORE the loop, then just adding the same value 32 times.
     
  13. fantabulous68

    fantabulous68 Member

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

    :eek: I did that in RED highlight below? I tested it & its uhmmmmm still stuck on1 reading

    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 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[32];     // used for voltage calculations
    long int adc_actual;
    unsigned char NumDec;
    unsigned char NumSep[2];
       
    unsigned char i,j,k,x;

    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 the 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//////////////////////////
       
    ///////////INITIALISING PORTS, REGISTERS, CLOCK/////////////////

    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

    }
    /////////////////////////End INITIALISING PORTS, REGISTERS, CLOCK///////////////////////

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

    //This function determines which button the user pressed.  It assigns the variable "temp" a number
    //which corresponds to a certain button press. Example if "temp" equals:
    //1---->ENTER/SETTINGS button was pressed
    //2---->HOME button was pressed
    //3---->INCREASE button was pressed
    //4---->DECREASE button was pressed


    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;
    }//
    //////////////////End WaitForInput///////////////////

    //////////////////////////////////////////////////////userMenu///////////////////////////////////////////////////////

    //This is the User Menu.  Once the "ENTER/SETTINGS" button is pressed, the user enters this menu.
    // This menu promps the user to enter the HEIGHT(ie. The distance between the IR sensor & the base of the container)
    //
    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 button 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]
                        //Now average the readings
                        x = (x & 0x1f);             //wrap x so x = 0 to 31
                        adc_actual=16;          //initialise total
                        for(i=0;i<32;i++){          //loop 32 times


                            // read the ADC voltage RA1 (Sharp GP2 sensor)
                           
                            GODONE=1;                   // initiate conversion on the channel 0
                            while(GODONE) continue;     // Wait convertion done
                            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[i];//add all the values
                            DelayMs(30);   
                          }
                            adc_actual/=32;             //and divide by 32[/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)
    }
    //////////////////////End userMenu///////////////////////////

    /////////////////////EnterScreen/////////////////////////////

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

    ////////////////////////ShowDigits////////////////////////////
    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
    }
    ////////////////////End ShowDigits////////////////////////////
       

    ///////////////////////calc_distance//////////////////////////
    /*RomanBlack.com 19th July 2009.
    uses my "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*/


    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 = (adc_actual >> 8) & 0x00FF;
        math = (math * 256);
        math += adc_actual & 0x00FF;

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


        // 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';  //
    }
     
    ////////////////////End calc_distance//////////////////////////

    ///////////////////////user_input//////////////////////////////

    unsigned char user_input(void) 
    {
        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 by displaying "OK"
                lcd_goto_L1();
                lcd_puts("      OK       ");
                break;


    //The User will be prompted to enter the "HEIGHT" in userMenu(). The LCD will Display:

    //          HEIGHT     
    //      Press Up/Down

    //Up------->represented by INCREASE Button
    //Down----->represented by DECREASE Button
    // The user can enter "HEIGHT" values from [0-99]cm because
    //  MyMinVal = 0;
    //  MyMaxVal = 99;

    ///Now the variable MyVal is used in user_input() to represent this "HEIGHT" value.


    //If User presses the INCREASE button:
            case 3:
                if(MyVal < MyMaxVal)    //checks if MyVal<99
                    MyVal++;            //Increases MyVal when INCREASE button is pressed
                EnterScreen();          //Displays "[cm]" in Line 1
                ShowDigits(MyVal);      //Splits MyVal into 2 separate digits, then convert digits to ASCII
                                        //so it can be displayed on  the LCD screen
                break;

    //If the User presses the DECREASE button:
            case 4:
                if(MyVal > MyMinVal)    //checks if MyVal>0
                    MyVal--;            //Decreases MyVal when DECREASE button is pressed
                EnterScreen();          //Displays "[cm]" in Line 1
                ShowDigits(MyVal);      //Splits MyVal into 2 separate digits, then convert digits to ASCII
                                        //so it can be displayed on  the LCD screen
                break;             
            default:
                break;
          }
        }
        DelayMs(250);                   //switch debouncing        
        DelayMs(250);                   //switch debouncing
           
        return MyVal;//This will return MyVal which represents the "HEIGHT".  The height var will be assigned myVal in home_screen()
                     //height = user_input() in home_screen.  This will be used in calc_distance() to calculate the Liquid Leval.
    }

    /////////////////////////End user_input//////////////////////////////


    ///////////////////////////home_screen///////////////////////////////
    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 of the button the user presses

        while(input_sw != 1)            //Wait until ENTER button 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 of the button the user presses


    }
    ///////////////////////////End home_screen///////////////////////////////

    //////////////////////main//////////////////////
    void main(void)
    {  
        init(); // initialise I/O ports, LCD
        while(1){
        home_screen();
     
                 
     
       }  
    }
    //////////////////End main//////////////////////
     
     
    Last edited: Oct 16, 2009
  14. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    Whats the difference between Noggins filter for reducing fluctuations &
    The averaging method to reduce fluctuating readings?
    Which is better and why?
     
  15. fantabulous68

    fantabulous68 Member

    Joined:
    Feb 20, 2007
    Messages:
    323
    Likes:
    0
    I don't need the part Highlighted in red Right?Its unnecessary since I'm only displaying the tens and units column of the Liquid Level only in another function


    Code (text):
    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 = (adc_actual >> 8) & 0x00FF;
        math = (math * 256);
        math += adc_actual & 0x00FF;

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


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

        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';  //
    }
     
    ////////////////////End calc_distance//////////////////////////



    another function:
    Code (text):

                        lcd_data(LLHigh);
                        lcd_data(LLLow);
                        lcd_puts(" [cm] ");    
     
     

Share This Page