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 CCS Technical Support

Auto calibration of line sensor
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
srikrishna



Joined: 06 Sep 2017
Posts: 82

View user's profile Send private message

Auto calibration of line sensor
PostPosted: Sat Oct 28, 2017 1:15 pm     Reply with quote

I tried to convert Arduino calibration example to ccs c. In this method i have taken 1 sensor readings for five seconds during the startup, and tracks the highest and lowest values it gets. These sensor readings during the first five seconds of the sketch execution define the minimum and maximum of expected values for the readings taken during the loop. Then i mapped the next incoming reading based on maximum and minimum value taken before.
Code:

#include <18f2550.h>
#device adc=10
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#FUSES HS,NOWDT
#USE delay(clock=20M)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,PARITY=N,BITS=8)
#USE TIMER(TIMER=1,TICK=1s,BITS=16,NOISR)

unsigned int16 tick_difference(unsigned int16 current,unsigned int16 previous)
{
return (current - previous);
}
 
double map(double value, float min, float max, float y_min, float y_max)//function definition
{                   
    return (y_min + (((y_max - y_min)/(max - min)) * (value - min)));
   


void main(void)
{
double d;
int16 sensorMin =1023 ;        // minimum sensor value
int16 sensorMax =0 ;           // maximum sensor value
int16 sensorValue;

setup_adc_ports(AN0);
//setup_adc(ADC_CLOCK_INTERNAL);
setup_adc(ADC_CLOCK_DIV_32);
unsigned int16 current_tick, previous_tick;
current_tick = previous_tick = get_ticks();

 while(1)
{
 current_tick= get_ticks();
if (tick_difference(current_tick, previous_tick) <5) //take sensor reading for 5 second
{
 set_adc_channel(0);
 sensorValue = read_adc();
 delay_us(15);
 if (sensorValue> sensorMax)
     {
      sensorMax = sensorValue;
    }
  if (sensorValue < sensorMin)
  {
      sensorMin = sensorValue;
    }
    output_toggle(PIN_B0);
 
delay_ms(300);
}

   set_adc_channel(0);
    sensorValue = read_adc();/// again take the sensor value while running
    delay_us(15);
   
    d = map(sensorValue,sensorMin,sensorMax,0,1023);//function call(calling the map function)
   
    printf("%f \r\n",d);
    delay_ms(1000);
 }
}


The problem is while tracking the highest and lowest value the line sensor the sensor also takes readings and mapped into some garbage reading before the actual minimum and maximum value is determined. Any suggestion?


Last edited by srikrishna on Wed Nov 08, 2017 1:06 am; edited 3 times in total
temtronic



Joined: 01 Jul 2010
Posts: 9246
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Oct 28, 2017 1:55 pm     Reply with quote

this...
setup_adc(ADC_CLOCK_INTERNAL);
... is probably not the correct option.

'internal' is usually only chosen when the PIC is asleep.

You should look at the 'speed chart' in the ADC section...

With any analog capturing ,it's best to take an 'olympic' average.
srikrishna



Joined: 06 Sep 2017
Posts: 82

View user's profile Send private message

PostPosted: Sat Oct 28, 2017 2:39 pm     Reply with quote

temtronic wrote:
this...
setup_adc(ADC_CLOCK_INTERNAL);
... is probably not the correct option.

'internal' is usually only chosen when the PIC is asleep.

You should look at the 'speed chart' in the ADC section...

With any analog capturing ,it's best to take an 'olympic' average.



what do you mean by asleep??

I have found the following mode in .h file of pic 18f2550

Quote:
// Constants used for SETUP_ADC() are:
#define ADC_OFF 0 // ADC Off
#define ADC_CLOCK_DIV_2 0x100
#define ADC_CLOCK_DIV_4 0x04
#define ADC_CLOCK_DIV_8 0x01
#define ADC_CLOCK_DIV_16 0x05
#define ADC_CLOCK_DIV_32 0x02
#define ADC_CLOCK_DIV_64 0x06
#define ADC_CLOCK_INTERNAL 0x07 // Internal 2-6us


In the list which one should i use??
temtronic



Joined: 01 Jul 2010
Posts: 9246
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Oct 28, 2017 3:14 pm     Reply with quote

You need to download the Microchip datasheet for that PIC. When you look at the ADC section, there will be a chapter about selecting the ADC clock rate.

From my memory, I believe div_8 or div_16 would be appropriate. This PC is NOT my PIC machine, so I can't easily confirm.

Just get the datasheet, read the chapter.


Asleep, means the PIC has gone into 'sleep' mode, again, read the datasheet. Yes, I KNOW 500-800 pages is a LOT to read, but just read a chapter at a time....most you can 'skim' over BUT when possible read the entire datasheet.

Jay
srikrishna



Joined: 06 Sep 2017
Posts: 82

View user's profile Send private message

PostPosted: Sat Oct 28, 2017 3:30 pm     Reply with quote

OK. But how to solve the above problem
temtronic



Joined: 01 Jul 2010
Posts: 9246
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Oct 28, 2017 8:02 pm     Reply with quote

I'd have the program print out ( send data to PC) for EVERY reading. That way you can determine if it's actually a bad ADC reading( sensor problem) or a 'math' ( computational) problem.

Without seeing the data I don't know where the 'bad' number is from
1) bad sensor wiring
2) EMI
3) incorrect calculations( 'math' )
4) bad logic

BTW the ADC setup is still incorrect

Jay
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sat Oct 28, 2017 9:20 pm     Reply with quote

Quote:

I have taken 1 sensor readings for five seconds during the startup.

The problem is while tracking the highest and lowest value the sensor also
takes readings and mapped into some garbage reading before the actual
minimum and maximum value is determined

Don't take readings until the calibration is done.
Do the calibration for 5 seconds. Then take readings and call the map()
function.
srikrishna



Joined: 06 Sep 2017
Posts: 82

View user's profile Send private message

PostPosted: Mon Oct 30, 2017 3:25 pm     Reply with quote

PCM programmer wrote:

Don't take readings until the calibration is done.
Do the calibration for 5 seconds. Then take readings and call the map()
function.

I have to get calibration data Before the while loop And save the data. But how can i did that ? The #use timer option needed a while loop to perform operation.

So while taking reading for calibration it also takes reading for mapping.
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Tue Oct 31, 2017 2:29 am     Reply with quote

You do one _then_ then other.

Have a loop that exits after five seconds. Then take a set of perhaps eight readings, average and store these, then enter the main sampling loop.
srikrishna



Joined: 06 Sep 2017
Posts: 82

View user's profile Send private message

PostPosted: Tue Oct 31, 2017 9:12 pm     Reply with quote

Ttelmah wrote:
You do one _then_ then other.

Have a loop that exits after five seconds. Then take a set of perhaps eight readings, average and store these, then enter the main sampling loop.


I don't want to use a for loop. Any other suggestion??
RF_Developer



Joined: 07 Feb 2011
Posts: 839

View user's profile Send private message

PostPosted: Wed Nov 01, 2017 4:39 am     Reply with quote

srikrishna wrote:

I don't want to use a for loop. Any other suggestion??


What's the problem with using a for loop? It seems to me that you may not understand what these control structures, while loops, for loops etc, actually do. These are not special to particular tasks; #use timer option did NOT need a while loop to perform operation, but the example shows it using one. You can use while loops for all sorts of other things, and you can have as many as you need.

As Ttelmah says, you write code that calibrates for five seconds, and then when that's done, dooes the actual measuring. Two distinct phases of operation. Your original code is trying to do both at the same time. Using simple C control statements to do that is trivial.
jeremiah



Joined: 20 Jul 2010
Posts: 1358

View user's profile Send private message

PostPosted: Wed Nov 01, 2017 10:42 am     Reply with quote

srikrishna wrote:
Ttelmah wrote:
You do one _then_ then other.

Have a loop that exits after five seconds. Then take a set of perhaps eight readings, average and store these, then enter the main sampling loop.


I don't want to use a for loop. Any other suggestion??


You don't have to use a for loop. Read carefully what Ttelmah (and RF_Developer) just said. They are suggesting splitting up the process into two steps: calibration and data collection. Whether you use a for loop, while loop, etc. is up to you. I'll give you an uncompiled/untested example so you can see what they mean.

I would recommend creating a calibration type:
Code:

typedef struct{
   unsigned int16 min;
   unsigned int16 max;
} calibration_t;


and then a calibrate function
Code:

void calibrate_adc(calibration_t * calibration_data){
   unsigned int16 current_tick;
   unsigned int16 starting_tick;
   unsigned int16 sensor_value;

   unsigned int16 max = 0;
   unsigned int16 min = 1023;

   set_adc_channel(0);
   delay_us(15);

   current_tick  = get_ticks();
   starting_tick = current_tick;

   //get as many readings as you can.  the more the
   //merrier
   while(tick_difference(current_tick,starting_tick) < 5){
      sensor_value = read_adc();
      if(sensor_value > max){
         max = sensor_value;
      }
      if(sensor_value < min){
         min = sensor_value;
      }
      output_toggle(PIN_B0);
      current_tick = get_ticks();
   }
   
   calibration_data->min = min;
   calibration_data->max = max;
}


Then you can simplify your main pretty easily:
Code:

void main(void){
   calibration_t cal;
   unsigned int16 sensor_value;
   double map_result;

   setup_adc_ports(AN0);
   setup_adc(ADC_CLOCK_DIV_32);

   delay_ms(1000);  //some delay to stabilize sensor

   calibrate_adc(&cal);  //takes about 5 secs

   //next two lines not technically needed
   //since you only have one ADC and it
   //was set in calibrate_adc(), but here
   //for later expansion
   set_adc_channel(0);
   delay_us(15);

   
   while(TRUE){
      sensor_value = read_adc();
      map_result = map(sensor_value,cal.min,cal.max,0,1023);
      printf("%f \r\n",map_result);
      delay_ms(1000);
   }

}


Again, all untested/uncompiled. Just wanted to you give you a feeler for how it might look.

EDIT: added delay before calibration per Ttelmah's suggestion


Last edited by jeremiah on Wed Nov 01, 2017 2:28 pm; edited 1 time in total
Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Wed Nov 01, 2017 1:36 pm     Reply with quote

Jeremiah has covered it very well.
However I would pause for a short while _before_ starting the actual calibration.

PIC's wake up very quickly. They wake when the supply is still well below it's full voltage. The sensor itself will take some time to stabilise when switched on. The supply will not be up to a stable working level when the PIC actually starts. You should not do anything for perhaps 500mSec, before actually starting the calibration. There also needs to be a slight delay in the loop to allow the ADC to re-acquire.
An Arduino takes a lot longer to start than a PIC. About 8 seconds!...
srikrishna



Joined: 06 Sep 2017
Posts: 82

View user's profile Send private message

PostPosted: Wed Nov 01, 2017 4:01 pm     Reply with quote

Thanks to all for responding and helping me
Code:
#include <18f2550.h>
#device adc=10
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#FUSES HS,NOWDT
#USE delay(clock=20M)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7,PARITY=N,BITS=8)
#USE TIMER(TIMER=1,TICK=1s,BITS=16,NOISR)

unsigned int16 tick_difference(unsigned int16 current,unsigned int16 previous)
{
return (current - previous);
}
 
double map(double value, float min, float max, float y_min, float y_max)//function definition
{                   
    return (y_min + (((y_max - y_min)/(max - min)) * (value - min)));
   

typedef struct{
   unsigned int16 min;
   unsigned int16 max;
} calibration_t;

void calibrate_adc(calibration_t *calibration_data)
{
   unsigned int16 current_tick;
   unsigned int16 starting_tick;
   unsigned int16 sensor_value;

   unsigned int16 max = 0;
   unsigned int16 min = 1023;

   set_adc_channel(0);
   delay_us(15);

   starting_tick = current_tick  = get_ticks();
    current_tick = get_ticks();

   //get as many readings as you can.  the more the
   //merrier
   while(tick_difference(current_tick,starting_tick) < 30)
   {
      sensor_value = read_adc();
      delay_us(15);
      if(sensor_value > max){
         max = sensor_value;
      }
      if(sensor_value < min){
         min = sensor_value;
      }
      output_toggle(PIN_B0);
      current_tick = get_ticks();
   }
   
   calibration_data->min = min; //a->b is just short for (*a).b in every way (same for functions: a->b() is short for (*a).b()).
   calibration_data->max = max; //(*calibration_data).max,
}
void main(void)
{
   calibration_t cal;
   unsigned int16 sensor_value;
   double map_result;

   setup_adc_ports(AN0);
   setup_adc(ADC_CLOCK_DIV_32);

   delay_ms(1000);  //some delay to stabilize sensor

   calibrate_adc(&cal);  //takes about 5 secs

   //next two lines not technically needed
   //since you only have one ADC and it
   //was set in calibrate_adc(), but here
   //for later expansion
   set_adc_channel(0);
   delay_us(15);

   
   while(TRUE){
      sensor_value = read_adc();
      delay_us(15);
      map_result = map(sensor_value,cal.min,cal.max,0,1023);
      printf("%f \r\n",map_result);
      delay_ms(1000);
   }

Ttelmah



Joined: 11 Mar 2010
Posts: 19552

View user's profile Send private message

PostPosted: Thu Nov 02, 2017 1:14 am     Reply with quote

and is it working?. ...
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
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