boogajamooga
Joined: 24 Mar 2011 Posts: 5
|
Sensor Interface with PIC16F877A and setting ADC thresholds |
Posted: Mon Apr 18, 2011 7:32 am |
|
|
I am doing a project where I take the input of an LV-MAX Sonar Sensor, which has an analog output voltage ranging from 0 to 600mV and send it to the ADC on the PIC16F877A. The sensor measures the water level in a tank by calculating the distance from the roof of tank to the water level. Based on this distance, it outputs an analog voltage that ranges from 0 to 600mV (which corresponds to its max range of 3meters). So, in my program, I want to split the tank into 3 sections, a low threshold, mid threshold, and upper threshold each symbolizing water levels in the tank. So, once the sensor hits those thresholds, it will send that voltage to the ADC and output a digital low or high (low if the water level is below the threshold, high if it is above the threshold). I was wondering how to configure the ADC to basically split the sensor's 0-600mV into 3 parts (for example, the lower threshold would be voltages in the range of: 0-200mv, the middle threshold would be voltages from 201mv- 400mv, and the upper threshold would be 401mv-600mv). I currently have read_adc() configured to an 8-bit ADC. Right now, the ADC reads the value properly, but logically does not output the correct digital value based on the current water level in the tank since I do not know what to set the threshold as. So, is there any formula for this to do it in C-programming? Thanks for any advice.
So here is my code for the program that I have done to give you an idea of what exactly my purpose is:
Note: i know to set the ADC to an 8-bit value, you're supposed to use the #device adc=8, but i was wondering if you don't specify, what does the complier set the default ADC to? 8 bits? or 10bits? (i am using compiler version 4.064)
Code: | #include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#USE RS232(BAUD=9600, XMIT=PIN_B0) //used to set up transmitter
#define THRESHOLDLOW 25 (this is the part i need help with, what values do i put here?)
#define THRESHOLDMID 100 (this is the part i need help with, what values do i put here?)
#define THRESHOLDUPPER 200 (this is the part i need help with, what values do i put here?)
//Delay Values
//5 mins in normal mode
#define NORMDELAY 1
//3 mins in rising mode but below middle threshold so need to poll a bit faster to see when you hit mid level of tank
#define MIDDELAY 1
//1 min in rising mode but inbetween middle and high threshold so need to poll even faster to see when you hit high level of tank to prevent overflow
#define HIGHDELAY 1
//function prototypes
int ADC_threshold(int);
int main(){
//set_tris_d(0b01000000);
//output_d(0b11111111);
unsigned char Rising = 0; //starting state of the tank is full
setup_adc_ports(ALL_ANALOG); //all ports set to analog w/ Vcc as ref voltage
setup_adc(ADC_CLOCK_DIV_32); //use the external 20mhz clock
set_adc_channel(0); //sets it to read the analog value of the source tank at pin RA0
delay_ms(20); //allow some delay time in order for the PIC to set up the ADC after initializing the ports/clock
//hardcode transmitter to stay on channel 0 that has frequency 903.37 Hz using parallel selection
output_high(PIN_B0); //PIN CS0
output_low(PIN_B1); //PIN CS1
output_high(PIN_B2); //PIN CS2
delay_ms(10); //after setting channel, wait for delay which is minimum 1.5ms
output_high(PIN_C1); // disable transmitter as initialize state
output_low(PIN_C2); //enable sensor before entering state machine to take measurements for ADC comparison
delay_ms(100); //wait standard time to allow sensor initialization and reading take place
while(1){
if((ADC_threshold(THRESHOLDLOW) == 0) && (Rising == 0)){ //case where your current water level is below the threshhold and are still draining water
output_high(PIN_C7); //turn on led 1 at pin RC7
Rising = 1; //set rising to equal 1 to know you are now filling the tank
output_high(PIN_C1); //before data can be transmitted, enable transmitter
delay_ms(500); //wait for transmitter to turn on
//write to UART reg 0x00 000000000 to turn motor on (you're new RS-232 encoded digital data)
output_low(PIN_D2); //PortDBits2 = 1; send signal to transmitter to turn motor on
delay_ms(1);
output_low(PIN_C1); //disable transmitter
delay_ms(500); //delay used for debugging
output_low(PIN_C7); //turn off led 1 at pin RC7
delay_ms(500); //delay used for debugging
}
//normal usage situation
else if(Rising == 0){ //case where you are using up water
output_high(PIN_D4); //turn on led 2 at pin RD4
delay_ms(100); //delay used for debugging
output_high(PIN_C2); //PortCBits2 = 1; disables sensor
// delay_ms(500); //delay used for debugging (used for LED on PIN C2)
// NOT USING output_high(PIN_D2); //PortDBits2 = 1; send signal to transmitter to turn motor off
delay_ms(NORMDELAY); //delay_ms(normaldelay ~5mins); (the amount of time you want to poll)
output_low(PIN_C2); //PortCbits2 = 0; enables sensor;
delay_ms(100); //wait required time for sensor to send reading
// delay_ms(100); //delay used for debugging
output_low(PIN_D4); //turn off led 2 at pin RD4
delay_ms(100); //delay used for debugging
}
//case where you are below the middle threshold of tank
while(ADC_threshold(THRESHOLDMID) == 0 && Rising == 1){
output_high(PIN_D5); //turn on led 3 at pin RD5
output_high(PIN_C2); //PortCBits2 = 1; disables sensor
// NOT USING output_low(PIN_D2); //PortDBits2 = 0; send signal to transmitter to turn motor on
delay_ms(MIDDELAY); //contains polling rate for that middle area of tank
output_low(PIN_C2); //PortCbits2 = 0; enables sensor
delay_ms(100); //wait required time for sensor to send reading
delay_ms(100); //delay used for debugging
output_low(PIN_D5); //turn off led 3 at pin RD5
delay_ms(100); //delay used for debugging
}
//this next chunk allows you to put an even smaller delay value as the water level gets closer and closer to the top of the high threshold of the tank
while((ADC_threshold(THRESHOLDMID) == 1) && (ADC_threshold(THRESHOLDUPPER) == 0) && (Rising == 1)){ //so you are at or above middle threshold level but below upper threshold level and in rising mode
output_high(PIN_D6); //turn on led 4 at pin RD6
output_high(PIN_C2); //PortCBits2 = 1; disables sensor;
// NOT USING output_low(PIN_C2); //PortDBits2 = 0; send signal to transmitter to turn motor on
delay_ms(HIGHDELAY); //contains faster polling rate value for area above middle and below high level of tank
output_low(PIN_C2); //PortCbits2 = 0; enables sensor
delay_ms(100); //wait required time for sensor to send reading
delay_ms(100); //delay used for debugging
output_low(PIN_D6); //turn off led 4 at pin RD6
delay_ms(100); //delay used for debugging
}
if((ADC_threshold(THRESHOLDUPPER) == 1) && (Rising == 1)){ //if water level of tank is >= high threshold of tank
output_high(PIN_D7); //turn on led 5 at pin RD7
// output_high(PIN_C2); //PortCBits2 = 1; disables sensor
// delay_ms(100); //delay used for debugging (put this for LED on PIN C2 and for LED on PIN D7)
output_high(PIN_C1); //before data can be transmitted, enable transmitter
// delay_ms(500); //delay used for debugging (put this for LED on PIN C2)
delay_ms(1); //allow some delay for the transmitter to turn on
//write to UART reg 0x01 00000001 to turn motor off
// NOT USING output_high(PIN_D2); //PortDBits2 = 1; send signal to transmitter to turn motor off
output_high(PIN_D2); //PortDBits2 = 1; send signal to transmitter to turn motor off
delay_ms(1); //delay to send serial data before turning transmitter off
delay_ms(500); //delay used for debugging
output_low(PIN_C1); //disable transmitter
Rising = 0; //set case to now where tank is being drained after sucessfully filling tank to top
output_low(PIN_D7); //turn off led 5 at pin RD7
}
}
return 0;
}
//Returns 0 if the current value is below the parameter theshold value. 1 otherwise
int ADC_threshold(int thresh){ //unsigned char makes it an 16-bit value, int makes the threshold variable a 16-bit value
if(read_adc() < thresh) //compare the converted analog value to the middle value in hex between 0v and 5v
return 0; //sets the variable to which it returns to a digital low
else
return 1; //sets the variable to which it returns to a digital high
} |
So, the main part I need help with is, figuring out what values to put for the #defines of the 3 threshold values, which is this part of my code:
Code: | #define THRESHOLDLOW 25 (this is the part i need help with, i put random values to make it work, but what values do i put here? is there a specific formula to calibrate the 8-bit ADC w/ voltage levels in the mv range of 0-600mv?)
#define THRESHOLDMID 100 (this is the part i need help with, i put random values to make it work, but what values do i put here? is there a specific formula to calibrate the 8-bit ADC w/ voltage levels in the mv range of 0-600mv?)
#define THRESHOLDUPPER 200 (this is the part i need help with, i put random values to make it work, but what values do i put here? is there a specific formula to calibrate the 8-bit ADC w/ voltage levels in the mv range of 0-600mv?)
|
|
|