#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; // used for voltage calculations
unsigned char NumDec;
unsigned char NumSep[2];
unsigned char i,j,k;
//char temp[8];
//[/b]
unsigned char height=50;
unsigned char range;
unsigned char area;
unsigned char SensorPos=10;
//[/b] New Vars
char input_sw;
char mnuPOS;
unsigned char MyVal;
unsigned char MyValLCD[2];
unsigned char MyMaxVal;
unsigned char MyMinVal;
unsigned long bres; // for bresenham 2-second timer system
unsigned char ;
#define HOME_SW RC2 //HOME switch
#define INCREASE_SW RC3 //INCREASE switch
#define DECREASE_SW RC4 //DECREASE switch
#define ENTERSETTINGS_SW RA4 //ENTERSETTINGS switch
///////////////////////CONVERT FLOAT TO STRING///////////////////
// This function was taken from the CAVR library. It was modified slightly
// to suit our design.
void FloatToStr(float n, char str[])
{
float scale;
unsigned char d,f;
f=0;i=0;
if (n<0.0) {n=-n; str[f]='-'; f++;};
n=n+0.005;
scale=1.0;
while (n>=scale) {scale=scale*10.0; ++i;};
if (i==0) {str[f]='0'; f++;}
else
while (i--)
{
scale=floor(0.5+scale/10.0);
d=(unsigned char) (n/scale);
str[f]=d+'0';
n=n-scale*d;
f++;
};
str[f]='.';
f++;
for (j=0;j<=1;j++) //2 decimal points
{
n=n*10.0;
d=(unsigned char) n;
str[f]=d+'0';
n=n-d;
f++;
};
str[f]='\0';
}
///////////////////END CONVERT FLOAT TO STRING///////////////////
/////////////////////////////DELAY///////////////////////////////
void DelayMs(unsigned char cnt)
{
#if XTAL_FREQ <= 2MHZ
do {
DelayUs(996);
} while(--cnt);
#endif
#if XTAL_FREQ > 2MHZ
unsigned char p;
do {
p = 4;
do {
DelayUs(250);
} while(--p);
} while(--cnt);
#endif
}
void DelayS(unsigned char cnt)
{
for (j=0; j<(cnt*10); j++)
DelayMs(100);
}
///////////////////////////DELAY END/////////////////////////////
//////////////////////////////LCD SETUP//////////////////////////
/* send a command to the LCD */
void lcd_cmd(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
LCD_RS = 0; //write instruction
PORTB = (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB = ((c << 4) & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
}
/* send data to the LCD */
void lcd_data(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
PORTB = 0x00;
LCD_RS = 1; //write data
PORTB |= (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB &= 0x00; //load upper nibble on LCD data lines
PORTB |= ( (c << 4) & 0xF0);
LCD_STROBE(); //send instruction to LCD
}
/*Clear the LCD*/
void lcd_clear(void)
{
lcd_cmd(0x01); //command to clear LCD
}
/*write a string of chars to the LCD*/
void lcd_puts(const char s[])
{
j = -1;
while(s[++j]!=('\0')) // send characters until null character reached
lcd_data(s[j]);
}
/*go to beginning of line 1*/
void lcd_goto_L1(void)
{
lcd_cmd(0b10000000); // command to go to line 1
}
/*go to beginning of line 2*/
void lcd_goto_L2(void)
{
lcd_cmd(0b11000000); // command to go to line 2
}
/*move cursor "x" positions to the right*/
void lcd_cursor(unsigned char x)
{
lcd_cmd(((x)&0x7F)|0x80);
}
/*initialise the LCD - put into 4 bit mode*/
void lcd_init(void)
{
LCD_RS = 0;
LCD_EN = 0;
DelayMs(20); //wait for LCD startup
lcd_cmd(0x02);
lcd_cmd(0x28); // 4-bit mode
lcd_cmd(0x08); // display off
lcd_cmd(0x01); // clear display
lcd_cmd(0x0C); // disp. on, cursor off, cursor blink off
lcd_cmd(0x06); // entry mode
lcd_cmd(0x80); // initialise DDRAM address to zero
}
//////////////////////////LCD SETUP END//////////////////////////
void init(void)
{
// setup the PIC 16f690
OSCCON = 0x72; // internal osc, 8MHz
PORTA = 0;
TRISA = 0b10010010; // RA7 high imp, RA3 is serial out, RA4 button input
PORTB = 0; // PORTB not used
WPUB = 1; // PORTB pullups ON
RABPU = 0;
/* 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)
GODONE=1; // initiate conversion on the channel 0
while(GODONE) continue; // Wait convertion done
calc_distance(); // convert ADC value to distance
lcd_goto_L2(); //Only change line 2
//[b]
if(posneg == 'p')
lcd_data('+');
else
lcd_data('-');
//[/b]
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;
//[b]
posneg = 'p';
if((LiquidLevel < 0) || (LiquidLevel > 0xFF00)){
LiquidLevel = -LiquidLevel ;
posneg = 'n';
}
//[/b]
//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
*/
}
}
Code:
typdef struct filter_type
{
Uint16 accumulator;
Uint16 output;
Uint8 shift_value;
Uint8 initialized;
};
filter_type adc_filter;
[COLOR="Red"]void Init_Filter( filter_type *filter, Uint8 shift )[/COLOR]
{
filter->initialized = FALSE;
filter->shift_value = shift;
}
[COLOR="Red"]void Update_Filter( filter_type *filter, Uint16 new_value )[/COLOR]
{
if (filter->initialized != TRUE)
{
filter->output = new_value;
filter->accumulator = new_value << filter->shift_value;
filter->initialized = TRUE;
}
else
{
filter->accumulator -= filter->output;
filter->accumulator += new_value;
filter->output = filter->accumulator >> filter->shift_value;
}
}
#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; // used for voltage calculations
unsigned char NumDec;
unsigned char NumSep[2];
unsigned char i,j,k;
//char temp[8];
//[/b]
unsigned char height=50;
unsigned char range;
unsigned char area;
unsigned char SensorPos=10;
//[/b] New Vars
char input_sw;
char mnuPOS;
unsigned char MyVal;
unsigned char MyValLCD[2];
unsigned char MyMaxVal;
unsigned char MyMinVal;
unsigned long bres; // for bresenham 2-second timer system
unsigned char ;
#define HOME_SW RC2 //HOME switch
#define INCREASE_SW RC3 //INCREASE switch
#define DECREASE_SW RC4 //DECREASE switch
#define ENTERSETTINGS_SW RA4 //ENTERSETTINGS switch
///////////////////////CONVERT FLOAT TO STRING///////////////////
// This function was taken from the CAVR library. It was modified slightly
// to suit our design.
void FloatToStr(float n, char str[])
{
float scale;
unsigned char d,f;
f=0;i=0;
if (n<0.0) {n=-n; str[f]='-'; f++;};
n=n+0.005;
scale=1.0;
while (n>=scale) {scale=scale*10.0; ++i;};
if (i==0) {str[f]='0'; f++;}
else
while (i--)
{
scale=floor(0.5+scale/10.0);
d=(unsigned char) (n/scale);
str[f]=d+'0';
n=n-scale*d;
f++;
};
str[f]='.';
f++;
for (j=0;j<=1;j++) //2 decimal points
{
n=n*10.0;
d=(unsigned char) n;
str[f]=d+'0';
n=n-d;
f++;
};
str[f]='\0';
}
///////////////////END CONVERT FLOAT TO STRING///////////////////
/////////////////////////////DELAY///////////////////////////////
void DelayMs(unsigned char cnt)
{
#if XTAL_FREQ <= 2MHZ
do {
DelayUs(996);
} while(--cnt);
#endif
#if XTAL_FREQ > 2MHZ
unsigned char p;
do {
p = 4;
do {
DelayUs(250);
} while(--p);
} while(--cnt);
#endif
}
void DelayS(unsigned char cnt)
{
for (j=0; j<(cnt*10); j++)
DelayMs(100);
}
///////////////////////////DELAY END/////////////////////////////
//////////////////////////////LCD SETUP//////////////////////////
/* send a command to the LCD */
void lcd_cmd(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
LCD_RS = 0; //write instruction
PORTB = (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB = ((c << 4) & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
}
/* send data to the LCD */
void lcd_data(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
PORTB = 0x00;
LCD_RS = 1; //write data
PORTB |= (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB &= 0x00; //load upper nibble on LCD data lines
PORTB |= ( (c << 4) & 0xF0);
LCD_STROBE(); //send instruction to LCD
}
/*Clear the LCD*/
void lcd_clear(void)
{
lcd_cmd(0x01); //command to clear LCD
}
/*write a string of chars to the LCD*/
void lcd_puts(const char s[])
{
j = -1;
while(s[++j]!=('\0')) // send characters until null character reached
lcd_data(s[j]);
}
/*go to beginning of line 1*/
void lcd_goto_L1(void)
{
lcd_cmd(0b10000000); // command to go to line 1
}
/*go to beginning of line 2*/
void lcd_goto_L2(void)
{
lcd_cmd(0b11000000); // command to go to line 2
}
/*move cursor "x" positions to the right*/
void lcd_cursor(unsigned char x)
{
lcd_cmd(((x)&0x7F)|0x80);
}
/*initialise the LCD - put into 4 bit mode*/
void lcd_init(void)
{
LCD_RS = 0;
LCD_EN = 0;
DelayMs(20); //wait for LCD startup
lcd_cmd(0x02);
lcd_cmd(0x28); // 4-bit mode
lcd_cmd(0x08); // display off
lcd_cmd(0x01); // clear display
lcd_cmd(0x0C); // disp. on, cursor off, cursor blink off
lcd_cmd(0x06); // entry mode
lcd_cmd(0x80); // initialise DDRAM address to zero
}
//////////////////////////LCD SETUP END//////////////////////////
void init(void)
{
// setup the PIC 16f690
OSCCON = 0x72; // internal osc, 8MHz
PORTA = 0;
TRISA = 0b10010010; // RA7 high imp, RA3 is serial out, RA4 button input
PORTB = 0; // PORTB not used
WPUB = 1; // PORTB pullups ON
RABPU = 0;
/* 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;
}//
[COLOR="Red"]
typdef struct filter_type
{
Uint16 accumulator;
Uint16 output;
Uint8 shift_value;
Uint8 initialized;
};
filter_type adc_filter;
void Init_Filter( filter_type *filter, Uint8 shift )
{
filter->initialized = FALSE;
filter->shift_value = shift;
}
void Update_Filter( filter_type *filter, Uint16 new_value )
{
if (filter->initialized != TRUE)
{
filter->output = new_value;
filter->accumulator = new_value << filter->shift_value;
filter->initialized = TRUE;
}
else
{
filter->accumulator -= filter->output;
filter->accumulator += new_value;
filter->output = filter->accumulator >> filter->shift_value;
}
}
[/COLOR]
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)
GODONE=1; // initiate conversion on the channel 0
while(GODONE) continue; // Wait convertion done
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;
// 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
*/
}
}
#include <pic.h>
#include "pic.h"
#include "delay.h"
#include "math.h"
#include <stdio.h>
#include <stdlib.h>
[COLOR="Red"]
typdef struct filter_type
{
Uint16 accumulator;
Uint16 output;
Uint8 shift_value;
Uint8 initialized;
};
filter_type adc_filter;[/COLOR]
[COLOR="Red"]void Init_Filter( filter_type *filter, Uint8 shift );
void Update_Filter( filter_type *filter, Uint16 new_value );[/COLOR]
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; // used for voltage calculations
unsigned char NumDec;
unsigned char NumSep[2];
unsigned char i,j,k;
//char temp[8];
//[/b]
unsigned char height=50;
unsigned char range;
unsigned char area;
unsigned char SensorPos=10;
//[/b] New Vars
char input_sw;
char mnuPOS;
unsigned char MyVal;
unsigned char MyValLCD[2];
unsigned char MyMaxVal;
unsigned char MyMinVal;
unsigned long bres; // for bresenham 2-second timer system
unsigned char ;
#define HOME_SW RC2 //HOME switch
#define INCREASE_SW RC3 //INCREASE switch
#define DECREASE_SW RC4 //DECREASE switch
#define ENTERSETTINGS_SW RA4 //ENTERSETTINGS switch
///////////////////////CONVERT FLOAT TO STRING///////////////////
// This function was taken from the CAVR library. It was modified slightly
// to suit our design.
void FloatToStr(float n, char str[])
{
float scale;
unsigned char d,f;
f=0;i=0;
if (n<0.0) {n=-n; str[f]='-'; f++;};
n=n+0.005;
scale=1.0;
while (n>=scale) {scale=scale*10.0; ++i;};
if (i==0) {str[f]='0'; f++;}
else
while (i--)
{
scale=floor(0.5+scale/10.0);
d=(unsigned char) (n/scale);
str[f]=d+'0';
n=n-scale*d;
f++;
};
str[f]='.';
f++;
for (j=0;j<=1;j++) //2 decimal points
{
n=n*10.0;
d=(unsigned char) n;
str[f]=d+'0';
n=n-d;
f++;
};
str[f]='\0';
}
///////////////////END CONVERT FLOAT TO STRING///////////////////
/////////////////////////////DELAY///////////////////////////////
void DelayMs(unsigned char cnt)
{
#if XTAL_FREQ <= 2MHZ
do {
DelayUs(996);
} while(--cnt);
#endif
#if XTAL_FREQ > 2MHZ
unsigned char p;
do {
p = 4;
do {
DelayUs(250);
} while(--p);
} while(--cnt);
#endif
}
void DelayS(unsigned char cnt)
{
for (j=0; j<(cnt*10); j++)
DelayMs(100);
}
///////////////////////////DELAY END/////////////////////////////
//////////////////////////////LCD SETUP//////////////////////////
/* send a command to the LCD */
void lcd_cmd(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
LCD_RS = 0; //write instruction
PORTB = (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB = ((c << 4) & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
}
/* send data to the LCD */
void lcd_data(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
PORTB = 0x00;
LCD_RS = 1; //write data
PORTB |= (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB &= 0x00; //load upper nibble on LCD data lines
PORTB |= ( (c << 4) & 0xF0);
LCD_STROBE(); //send instruction to LCD
}
/*Clear the LCD*/
void lcd_clear(void)
{
lcd_cmd(0x01); //command to clear LCD
}
/*write a string of chars to the LCD*/
void lcd_puts(const char s[])
{
j = -1;
while(s[++j]!=('\0')) // send characters until null character reached
lcd_data(s[j]);
}
/*go to beginning of line 1*/
void lcd_goto_L1(void)
{
lcd_cmd(0b10000000); // command to go to line 1
}
/*go to beginning of line 2*/
void lcd_goto_L2(void)
{
lcd_cmd(0b11000000); // command to go to line 2
}
/*move cursor "x" positions to the right*/
void lcd_cursor(unsigned char x)
{
lcd_cmd(((x)&0x7F)|0x80);
}
/*initialise the LCD - put into 4 bit mode*/
void lcd_init(void)
{
LCD_RS = 0;
LCD_EN = 0;
DelayMs(20); //wait for LCD startup
lcd_cmd(0x02);
lcd_cmd(0x28); // 4-bit mode
lcd_cmd(0x08); // display off
lcd_cmd(0x01); // clear display
lcd_cmd(0x0C); // disp. on, cursor off, cursor blink off
lcd_cmd(0x06); // entry mode
lcd_cmd(0x80); // initialise DDRAM address to zero
}
//////////////////////////LCD SETUP END//////////////////////////
void init(void)
{
// setup the PIC 16f690
OSCCON = 0x72; // internal osc, 8MHz
PORTA = 0;
TRISA = 0b10010010; // RA7 high imp, RA3 is serial out, RA4 button input
PORTB = 0; // PORTB not used
WPUB = 1; // PORTB pullups ON
RABPU = 0;
/* 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;
}//
[COLOR="Red"]
void Init_Filter( filter_type *filter, Uint8 shift )
{
filter->initialized = FALSE;
filter->shift_value = shift;
}
void Update_Filter( filter_type *filter, Uint16 new_value )
{
if (filter->initialized != TRUE)
{
filter->output = new_value;
filter->accumulator = new_value << filter->shift_value;
filter->initialized = TRUE;
}
else
{
filter->accumulator -= filter->output;
filter->accumulator += new_value;
filter->output = filter->accumulator >> filter->shift_value;
}
}
[/COLOR]
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)
GODONE=1; // initiate conversion on the channel 0
while(GODONE) continue; // Wait convertion done
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;
// 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
*/
}
}
void Init_Filter( filter_type *filter, Uint8 shift );
void Update_Filter( filter_type *filter, Uint16 new_value );
void Init_Filter( filter_type *filter, unsigned char shift );
void Update_Filter( filter_type *filter, unsigned int new_value );
void Init_Filter( filter_type *filter, Uint8 shift )
{
filter->initialized = FALSE;
filter->shift_value = shift;
}
void Update_Filter( filter_type *filter, Uint16 new_value )
{
if (filter->initialized != TRUE)
{
filter->output = new_value;
filter->accumulator = new_value << filter->shift_value;
filter->initialized = TRUE;
}
else
{
filter->accumulator -= filter->output;
filter->accumulator += new_value;
filter->output = filter->accumulator >> filter->shift_value;
}
}
void Init_Filter( filter_type *filter, unsigned char shift )
{
filter->initialized = FALSE;
filter->shift_value = shift;
}
void Update_Filter( filter_type *filter, unsigned int new_value )
{
if (filter->initialized != TRUE)
{
filter->output = new_value;
filter->accumulator = new_value << filter->shift_value;
filter->initialized = TRUE;
}
else
{
filter->accumulator -= filter->output;
filter->accumulator += new_value;
filter->output = filter->accumulator >> filter->shift_value;
}
}
typdef struct filter_type
{
Uint16 accumulator;
Uint16 output;
Uint8 shift_value;
Uint8 initialized;
};
filter_type adc_filter;
typdef struct filter_type
{
unsigned int accumulator;
unsigned int output;
unsigned char shift_value;
unsigned char initialized;
};
filter_type adc_filter;
#include <pic.h>
#include "pic.h"
#include "delay.h"
#include "math.h"
#include <stdio.h>
#include <stdlib.h> //
#define FALSE 0
#define TRUE 1
struct filter_type {
unsigned int accumulator;
unsigned int output;
unsigned char shift_value;
unsigned char initialized;
} ;
struct filter_type adc_filter;
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; // used for voltage calculations
unsigned char NumDec;
unsigned char NumSep[2];
unsigned char i,j,k;
//char temp[8];
//[/b]
unsigned char height=50;
unsigned char range;
unsigned char area;
unsigned char SensorPos=10;
//[/b] New Vars
char input_sw;
char mnuPOS;
unsigned char MyVal;
unsigned char MyValLCD[2];
unsigned char MyMaxVal;
unsigned char MyMinVal;
unsigned long bres; // for bresenham 2-second timer system
unsigned char ;
#define HOME_SW RC2 //HOME switch
#define INCREASE_SW RC3 //INCREASE switch
#define DECREASE_SW RC4 //DECREASE switch
#define ENTERSETTINGS_SW RA4 //ENTERSETTINGS switch
///////////////////////CONVERT FLOAT TO STRING///////////////////
// This function was taken from the CAVR library. It was modified slightly
// to suit our design.
void FloatToStr(float n, char str[])
{
float scale;
unsigned char d,f;
f=0;i=0;
if (n<0.0) {n=-n; str[f]='-'; f++;};
n=n+0.005;
scale=1.0;
while (n>=scale) {scale=scale*10.0; ++i;};
if (i==0) {str[f]='0'; f++;}
else
while (i--)
{
scale=floor(0.5+scale/10.0);
d=(unsigned char) (n/scale);
str[f]=d+'0';
n=n-scale*d;
f++;
};
str[f]='.';
f++;
for (j=0;j<=1;j++) //2 decimal points
{
n=n*10.0;
d=(unsigned char) n;
str[f]=d+'0';
n=n-d;
f++;
};
str[f]='\0';
}
///////////////////END CONVERT FLOAT TO STRING///////////////////
/////////////////////////////DELAY///////////////////////////////
void DelayMs(unsigned char cnt)
{
#if XTAL_FREQ <= 2MHZ
do {
DelayUs(996);
} while(--cnt);
#endif
#if XTAL_FREQ > 2MHZ
unsigned char p;
do {
p = 4;
do {
DelayUs(250);
} while(--p);
} while(--cnt);
#endif
}
void DelayS(unsigned char cnt)
{
for (j=0; j<(cnt*10); j++)
DelayMs(100);
}
///////////////////////////DELAY END/////////////////////////////
//////////////////////////////LCD SETUP//////////////////////////
/* send a command to the LCD */
void lcd_cmd(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
LCD_RS = 0; //write instruction
PORTB = (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB = ((c << 4) & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
}
/* send data to the LCD */
void lcd_data(unsigned char c)
{
DelayMs(2); //wait for LCD to be ready shorter delay
PORTB = 0x00;
LCD_RS = 1; //write data
PORTB |= (c & 0xF0); //load upper nibble on LCD data lines
LCD_STROBE(); //send instruction to LCD
PORTB &= 0x00; //load upper nibble on LCD data lines
PORTB |= ( (c << 4) & 0xF0);
LCD_STROBE(); //send instruction to LCD
}
/*Clear the LCD*/
void lcd_clear(void)
{
lcd_cmd(0x01); //command to clear LCD
}
/*write a string of chars to the LCD*/
void lcd_puts(const char s[])
{
j = -1;
while(s[++j]!=('\0')) // send characters until null character reached
lcd_data(s[j]);
}
/*go to beginning of line 1*/
void lcd_goto_L1(void)
{
lcd_cmd(0b10000000); // command to go to line 1
}
/*go to beginning of line 2*/
void lcd_goto_L2(void)
{
lcd_cmd(0b11000000); // command to go to line 2
}
/*move cursor "x" positions to the right*/
void lcd_cursor(unsigned char x)
{
lcd_cmd(((x)&0x7F)|0x80);
}
/*initialise the LCD - put into 4 bit mode*/
void lcd_init(void)
{
LCD_RS = 0;
LCD_EN = 0;
DelayMs(20); //wait for LCD startup
lcd_cmd(0x02);
lcd_cmd(0x28); // 4-bit mode
lcd_cmd(0x08); // display off
lcd_cmd(0x01); // clear display
lcd_cmd(0x0C); // disp. on, cursor off, cursor blink off
lcd_cmd(0x06); // entry mode
lcd_cmd(0x80); // initialise DDRAM address to zero
}
//////////////////////////LCD SETUP END//////////////////////////
void init(void)
{
// setup the PIC 16f690
OSCCON = 0x72; // internal osc, 8MHz
PORTA = 0;
TRISA = 0b10010010; // RA7 high imp, RA3 is serial out, RA4 button input
PORTB = 0; // PORTB not used
WPUB = 1; // PORTB pullups ON
RABPU = 0;
/* 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 Init_Filter( struct filter_type *filter, unsigned char shift )
{
filter->initialized = FALSE;
filter->shift_value = shift;
}
void Update_Filter( struct filter_type *filter, unsigned int new_value )
{
if (filter->initialized != TRUE)
{
filter->output = new_value;
filter->accumulator = new_value << filter->shift_value;
filter->initialized = TRUE;
}
else
{
filter->accumulator -= filter->output;
filter->accumulator += new_value;
filter->output = filter->accumulator >> filter->shift_value;
}
}
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)
GODONE=1; // initiate conversion on the channel 0
while(GODONE) continue; // Wait convertion done
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;
// 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
*/
}
}
Build D:\Micro\PIC\help01\main for device 16F690
Using driver C:\Program Files\HI-TECH Software\PICC\PRO\9.65\bin\picc.exe
Make: The target "D:\Micro\PIC\help01\ssome.p1" is out of date.
Executing: "C:\Program Files\HI-TECH Software\PICC\PRO\9.65\bin\picc.exe" --pass1 D:\Micro\PIC\help01\ssome.c -q --chip=16F690 -P --runtime=default --opt=default -D__DEBUG=1 -g --asmlist "--errformat=Error [%n] %f; %l.%c %s" "--msgformat=Advisory[%n] %s" "--warnformat=Warning [%n] %f; %l.%c %s"
Executing: "C:\Program Files\HI-TECH Software\PICC\PRO\9.65\bin\picc.exe" -omain.cof -mmain.map --summary=default --output=default ssome.p1 --chip=16F690 -P --runtime=default --opt=default -D__DEBUG=1 -g --asmlist "--errformat=Error [%n] %f; %l.%c %s" "--msgformat=Advisory[%n] %s" "--warnformat=Warning [%n] %f; %l.%c %s"
HI-TECH C PRO for the PIC10/12/16 MCU family (Lite) V9.65PL1
Copyright (C) 1984-2009 HI-TECH SOFTWARE
(1273) Omniscient Code Generation not available in Lite mode (warning)
Warning [765] D:\Micro\PIC\help01\ssome.c; 466. degenerate unsigned comparison
Memory Summary:
Program space used 6D0h ( 1744) of 1000h words ( 42.6%)
Data space used 3Fh ( 63) of 100h bytes ( 24.6%)
EEPROM space used 0h ( 0) of 100h bytes ( 0.0%)
Configuration bits used 0h ( 0) of 1h word ( 0.0%)
ID Location space used 0h ( 0) of 4h bytes ( 0.0%)
Running this compiler in PRO mode, with Omniscient Code Generation enabled,
produces code which is typically 52% smaller than in Lite mode.
The HI-TECH C PRO compiler output for this code could be 906 words smaller.
See http://microchip.htsoft.com/portal/pic_pro for more information.
Loaded D:\Micro\PIC\help01\main.cof.
********** Build successful! **********
Clean: Deleting intermediary and output files.
Clean: Deleted file "F:\irMPLAB\ctest.obj".
Clean: Deleted file "F:\irMPLAB\ctest.sdb".
Clean: Deleted file "F:\irMPLAB\ctest.rlf".
Clean: Deleted file "F:\irMPLAB\ctest.lst".
Clean: Deleted file "F:\irMPLAB\ctest.cof".
Clean: Deleted file "F:\irMPLAB\ctest.hex".
Clean: Deleted file "F:\irMPLAB\ctest.sym".
Clean: Deleted file "F:\irMPLAB\ctest.map".
Clean: Deleted file "F:\irMPLAB\ctest.hxl".
Clean: Deleted file "F:\irMPLAB\startup.lst".
Clean: Deleted file "F:\irMPLAB\startup.rlf".
Clean: Done.
Build F:\irMPLAB\ctest for device 16F690
Using driver C:\Program Files\HI-TECH Software\PICC\lite\9.60\bin\picc.exe
Executing: "C:\Program Files\HI-TECH Software\PICC\lite\9.60\bin\picc.exe" -C F:\irMPLAB\ctest.c -q --chip=16F690 -P --runtime=default --opt=default -D__DEBUG=1 -g --asmlist "--errformat=Error [%n] %f; %l.%c %s" "--msgformat=Advisory[%n] %s" "--warnformat=Warning [%n] %f; %l.%c %s"
Warning [176] F:\irMPLAB\ctest.c; 214.0 missing newline
Executing: "C:\Program Files\HI-TECH Software\PICC\lite\9.60\bin\picc.exe" -octest.cof -mctest.map --summary=default --output=default ctest.obj --chip=16F690 -P --runtime=default --opt=default -D__DEBUG=1 -g --asmlist "--errformat=Error [%n] %f; %l.%c %s" "--msgformat=Advisory[%n] %s" "--warnformat=Warning [%n] %f; %l.%c %s"
HI-TECH PICC-Lite COMPILER (Microchip PICmicro) V9.60
Copyright (C) 1984-2006 HI-TECH SOFTWARE
Memory Usage Map:
Program space:
CODE used 443h ( 1091) of 800h words ( 53.3%)
CONST used 0h ( 0) of 800h words ( 0.0%)
ENTRY used 16h ( 22) of 800h words ( 1.1%)
STRING used 1Fh ( 31) of 800h words ( 1.5%)
Data space:
BANK0 used 23h ( 35) of 60h bytes ( 36.5%)
BANK1 used 0h ( 0) of 50h bytes ( 0.0%)
COMBANK used 0h ( 0) of 10h bytes ( 0.0%)
EEPROM space:
EEDATA used 0h ( 0) of 100h bytes ( 0.0%)
ID Location space:
IDLOC used 0h ( 0) of 4h bytes ( 0.0%)
Configuration bits:
CONFIG used 0h ( 0) of 1h word ( 0.0%)
Summary:
Program space used 478h ( 1144) of 800h words ( 55.9%)
Data space used 23h ( 35) of B0h bytes ( 19.9%)
EEPROM space used 0h ( 0) of 100h bytes ( 0.0%)
ID Location space used 0h ( 0) of 4h bytes ( 0.0%)
Configuration bits used 0h ( 0) of 1h word ( 0.0%)
Loaded F:\irMPLAB\ctest.cof.
********** Build successful! **********
I added the code in RED Highlight below...I just want to know if im using it in the correct place...// Whenever you read your adc, just call Update_Filter( &adc_filter, adc_value ).
//Wherever you perform a calculation on the ADC value, use adc_filter.output instead.
#include <pic.h>
#include "pic.h"
#include "delay.h"
#include "math.h"
#include <stdio.h>
#include <stdlib.h> //
#define FALSE 0
#define TRUE 1
struct filter_type {
unsigned int accumulator;
unsigned int output;
unsigned char shift_value;
unsigned char initialized;
} ;
struct filter_type adc_filter;
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; // used for voltage calculations
unsigned char NumDec;
unsigned char NumSep[2];
unsigned char i,j,k;
unsigned char height=50;
unsigned char range=10;
unsigned char area;
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 Init_Filter( struct filter_type *filter, unsigned char shift )
{
filter->initialized = FALSE;
filter->shift_value = shift;
}
void Update_Filter( struct filter_type *filter, unsigned int new_value )
{
if (filter->initialized != TRUE)
{
filter->output = new_value;
filter->accumulator = new_value << filter->shift_value;
filter->initialized = TRUE;
}
else
{
filter->accumulator -= filter->output;
filter->accumulator += new_value;
filter->output = filter->accumulator >> filter->shift_value;
}
}
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="DarkOrchid"][B]// Whenever you read your adc, just call Update_Filter( &adc_filter, adc_value ).[/B][/COLOR]
GODONE=1; // initiate conversion on the channel 0
while(GODONE) continue; // Wait convertion done
[COLOR="Red"][B]Update_Filter( &adc_filter, adc_value );[/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
[COLOR="DarkOrchid"][B]//Wherever you perform a calculation on the ADC value, use adc_filter.output instead.[/B][/COLOR]
// math = ADRESH;
[COLOR="Red"][B] math=adc_filter.output;[/B][/COLOR]
math = (math * 256);
// math += ADRESL;
[COLOR="Red"][B]math +=adc_filter.output;[/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
}
//*********************************************************
/* Junebug_Serial4.c RomanBlack.com 19th July 2009.
uses "zero error 1 second timer"
system to generate a 2 second interval, then every
2 seconds it reads an analog voltage from a
Sharp GP2 distance sensor and converts it to decimal
distance, then sends that data to a LCD
Code for MikroC, config handled by MikroC compiler;
_INTI02_OSC_1H
_WDT_OFF_2H
-MCLRE_ON_3H
_LVP_OFF_4L
_PWRT_ON_2L
*/
//*********************************************************
void main(void)
{
init(); // initialise I/O ports, LCD
while(1){
home_screen();
}
}
[COLOR="DarkOrchid"][B]//Wherever you perform a calculation on the ADC value, use adc_filter.output instead.[/B][/COLOR]
// math = ADRESH;
[COLOR="Red"][B] math=adc_filter.output;[/B][/COLOR]
math = (math * 256);
// math += ADRESL;
[COLOR="Red"][B]math +=adc_filter.output;[/B][/COLOR]
Not sure what the structure accomplishes heh
Code:
typdef struct filter_type
{
Uint16 accumulator;
Uint16 output;
Uint8 shift_value;
Uint8 initialized;
};
filter_type adc_filter;
void Init_Filter( filter_type *filter, Uint8 shift )
{
filter->initialized = FALSE;
filter->shift_value = shift;
}
void Update_Filter( filter_type *filter, Uint16 new_value )
{
if (filter->initialized != TRUE)
{
filter->output = new_value;
filter->accumulator = new_value << filter->shift_value;
filter->initialized = TRUE;
}
else
{
filter->accumulator -= filter->output;
filter->accumulator += new_value;
filter->output = filter->accumulator >> filter->shift_value;
}
}
Whenever you read your adc, just call Update_Filter( &adc_filter, adc_value ). Wherever you perform a calculation on the ADC value, use adc_filter.output instead.
I haven't read your code, so I'm not positive that this is in any way helpful at all.
MR RB:Not sure what the structure accomplishes heh
You should average a number of sensor readings to smooth it out (Noggin already gave a method).
What is adc_value?
for(x=0;x<3;x++){
GODONE=1;
while(GODONE) continue;
adc_temp[x] = (ADRESH << 4) | ADRESL;
DelayMs(100);
}
//Now average the readings
adc_actual = (adc_temp[0] + adc_temp[1] + adc_temp[2]) / 3;
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?