CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Sensor Interface with PIC16F877A and setting ADC thresholds

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
boogajamooga



Joined: 24 Mar 2011
Posts: 5

View user's profile Send private message

Sensor Interface with PIC16F877A and setting ADC thresholds
PostPosted: Mon Apr 18, 2011 7:32 am     Reply with quote

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?)
SherpaDoug



Joined: 07 Sep 2003
Posts: 1640
Location: Cape Cod Mass USA

View user's profile Send private message

PostPosted: Mon Apr 18, 2011 8:11 am     Reply with quote

The A/D will default to 8 bits. That 8 bit value (256) corresponds to the Vref of your A/D. What voltage do you have your A/D Vref set to? It is likely the supply voltage of your PIC (either 5V or 3V) unless you have set it otherwise. If 256 A/D counts represents 5V then 10 counts will represent 200mV, and 20 counts for 400mV.

256 * 200mV / 5V = 10.24 counts
_________________
The search for better is endless. Instead simply find very good and get the job done.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group