|
|
View previous topic :: View next topic |
Author |
Message |
colesha
Joined: 09 Jan 2012 Posts: 45
|
Reading AD channels data to detect sensor errors |
Posted: Thu Oct 08, 2020 4:50 am |
|
|
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
|
|
Posted: Thu Oct 08, 2020 6:44 am |
|
|
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
|
|
Posted: Mon Oct 12, 2020 9:29 am |
|
|
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
|
|
Posted: Mon Oct 12, 2020 10:03 am |
|
|
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. |
|
|
|
|
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
|