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

Reading AD channels data to detect sensor errors

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



Joined: 09 Jan 2012
Posts: 45

View user's profile Send private message Send e-mail

Reading AD channels data to detect sensor errors
PostPosted: Thu Oct 08, 2020 4:50 am     Reply with quote

Hello,
i am trying to write a code that can frequently read each analog input and use it to detect an input error or a sensor failure.

Below is the code for scanning the analog inputs
Code:

void get_analog_data (void)
{
 
   analog_data[a2d_chan] = read_adc() ; //read last value
   a2d_chan++ ;
      if (a2d_chan > LAST_CHANNEL)
         a2d_chan = 0 ;                     //select the next channel
         set_adc_channel(a2d_chan) ;       //circularly read the analog channels
         
}


however in the main loop, after calling it, it fails to work as expect. Below is the program
Code:

#include <16f877.h>
#device adc=10
#device *=16
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES HS                       //High speed Osc (> 4mhz)
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOBROWNOUT                 //Reset when brownout detected
#FUSES NOPUT                    //No Power Up Timer
#FUSES NODEBUG                  //No Debug mode for ICD
#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#use delay(clock=20000000)
#use fast_io(A)


//************************ Varriables Declaration ***************************//
#define STATUS_LED         PIN_C2
#define START_BUTTON      PIN_B0
#define RESET_BUTTON       PIN_B1


/*********** BRAKE voltage min 1.75V ******/
#define BRAKE_MIN (int16)((1.75/5.0)*1023)

/******** 4.25V is the most to be read from the Brake */
#define BRAKE_MAX (int16)((4.25/5.0)*1023)

enum {BATTERY , BRAKE, TEMP , AUX_INPUT } ; // analog data channel s
#define LAST_CHANNEL AUX_INPUT
int a2d_chan, BRAKE_FAULT;
int1 flag_error, flag_system_fault;
int16 analog_data[LAST_CHANNEL+1] ;


void get_analog_data (void)
{
 
   analog_data[a2d_chan] = read_adc() ; //read last value
   a2d_chan++ ;
      if (a2d_chan > LAST_CHANNEL)
         a2d_chan = 0 ;                     //select the next channel
         set_adc_channel(a2d_chan) ;       //circularly read the analog channels
         
}

void main()
{
   
   setup_spi(spi_ss_disabled);
   setup_timer_0(RTCC_INTERNAL);
   setup_timer_1(t1_disabled);
   setup_timer_2(t2_disabled,0,1);
   setup_adc(adc_clock_internal);
   setup_ccp1(ccp_off);
   setup_ccp2(ccp_off);
   setup_adc(ADC_CLOCK_DIV_8 );     // Setup ADC
   setup_adc_ports(ALL_ANALOG);
   
  while(1)
  {
   get_analog_data() ; //circularly service the A/D channels
     
      if((analog_data[BRAKE]< BRAKE_MIN) || (analog_data[BRAKE] > BRAKE_MAX))
         {
          flag_system_fault = 1 ;          //set fault flag
          flag_error = BRAKE_FAULT ;       //Brake input error detected
          output_bit(STATUS_LED , 1 ) ; // status light ON
       
         }

   }
}


How can it be able to make this code work,
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Thu Oct 08, 2020 6:44 am     Reply with quote

OK.
First, change your ADC channel setup to use 'AN0_AN1_AN2_AN3_AN4'
instead of 'ALL_ANALOGS'. You are setting lots of unwanted pins up as
analog inputs which will increase noise in the ADC. This still leaves one
extra pin selected, but a lot better than having lots selected.

Then your SPI setup is wrong. Second person today making the same
error. The setting to turn off the spi is:

setup_spi(FALSE);

You are enabling the SPI with the slave select disabled....

Then your ADC clock setting is wrong. At 20MHz, you need to be using
ADC_CLOCK_DIV_32, not 'internal'. Internal is not recommended for
use above 1MHz. You currently have two clock lines, the first selecting
internal, and the second /8. Both are wrong. Remove both and just have
one line selecting /32.

Then you are not allowing enough time for acquisition between selecting
the channel and reading. The chip needs a minimum of 19.72uSec
between the instruction that selects the channel and actually taking the
reading. You have a few instructions to the loop, but probably no more
than a couple of uSec.

Also, as shown, your very first reading has no ADC channel selected....
colesha



Joined: 09 Jan 2012
Posts: 45

View user's profile Send private message Send e-mail

PostPosted: Mon Oct 12, 2020 9:29 am     Reply with quote

Ttelmah wrote:
OK.
First, change your ADC channel setup to use 'AN0_AN1_AN2_AN3_AN4'
instead of 'ALL_ANALOGS'. You are setting lots of unwanted pins up as
analog inputs which will increase noise in the ADC. This still leaves one
extra pin selected, but a lot better than having lots selected.

Then your SPI setup is wrong. Second person today making the same
error. The setting to turn off the spi is:

setup_spi(FALSE);

You are enabling the SPI with the slave select disabled....

Then your ADC clock setting is wrong. At 20MHz, you need to be using
ADC_CLOCK_DIV_32, not 'internal'. Internal is not recommended for
use above 1MHz. You currently have two clock lines, the first selecting
internal, and the second /8. Both are wrong. Remove both and just have
one line selecting /32.

Then you are not allowing enough time for acquisition between selecting
the channel and reading. The chip needs a minimum of 19.72uSec
between the instruction that selects the channel and actually taking the
reading. You have a few instructions to the loop, but probably no more
than a couple of uSec.

Also, as shown, your very first reading has no ADC channel selected....


Thanks Ttelmah for the guidelines. I managed to set the PIC as per your suggestion and it worked as expected.

Quote:

Also, as shown, your very first reading has no ADC channel selected....


Am using the enumeration which has all the adc channels set and read in here
Code:

void get_analog_data (void)
{
 
   analog_data[a2d_chan] = read_adc() ; //read last value
   a2d_chan++ ;
      if (a2d_chan > LAST_CHANNEL)
         a2d_chan = 0 ;                     //select the next channel
         set_adc_channel(a2d_chan) ;       //circularly read the analog channels
         
}


The channels are automatically selected from this enumeration
Code:

enum {BATTERY , BRAKE, TEMP , AUX_INPUT } ; // analog data channel s
#define LAST_CHANNEL AUX_INPUT
int a2d_chan;
int16 analog_data[LAST_CHANNEL+1] ;


Thanks
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Mon Oct 12, 2020 10:03 am     Reply with quote

The point is that the first time you do the 'read' no set_adc_channel
has been called. So the first read will return garbage. After that it'll
all start working fine. You set the next channel at the exit from the routine.

Glad you have it working now.
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