I
don’t know if this will help, but
I wrote the following program to study and demonstrate the two (I think its
two) wait periods needed in the A to D part in the PIC18F family. Hope
this
helps.
George
;******************************************************************************
; Copy and distribute
freely.
;
; The author of this program clames no
liability from its
use
;
; and makes no clames as to its
reliability.
;
;
;
; If you include your e-mail address
I’ll send you updates and other
;
; programs as I complete
them.
;
; George
Dorian
;
; PO Box
233
;
; Kentfield CA,
94914
;
;
;
; This
program clears the first 0x3FF
bytes of RAM then reads the A to D
;
; converter
MAX_COUNT times. The RAM byte
corresponding to the A to D value ;
; is
incremented each time. For example:
Set a DC voltage on an A to D
;
; channel,
(I’m using ch 0.) If an
A to D reading was 0x13F then that RAM ;
; address
will be
incremented.
;
;
;
; Let this
program run through an emulator
or the ICD 2 debugger (I used the ;
; ICD 2 with
this code, and it works
fine.) for a few seconds, then pause the ;
; run, then
examine RAM locations 0x000
through 0x3FF If you have a good
;
;
anti-aliasing filter and you have a
proper acquisition and conversion time ;
; set up
with the A to D converter then
you should see one RAM location with ;
; the same
value of MAX_COUNT. If you
don’t have this set up right then
;
;
you’ll see some other RAM
locations with
numbers.
;
;
;
; This
allows you to see if there is any
aliasing and if you’re allowing for ;
; proper
acquisition and conversion time
with the A to
D.
;
;
;
; As an
experiment, try reducing ACQ_SET
to a very low number, like 1 or 3 or ;
;
something. You should see a few RAM
locations below the intended location ;
; being
incremented. This is because
you’r not allowing enough acquisition ;
; time for
the A to D
converter.
;
;
;
; This code
was written with a PIC18F452.
Be sure to use a PIC18F chip with ;
; at lest 5
RAM banks. Four banks for the
RAM incrementing and one bank for ;
;
“count” and
“acq_count”. I was using an 8 Meg clock oscillator. Your
MPU ;
; speed will
make a big difference too if
you use a different frequency.
;
;
;
;
;******************************************************************************
LIST
PF452
;directive
to define processor
#include
<P18F452.INC>
;processor
specific variable definitions
;******************************************************************************
;Configuration bits
__CONFIG _CONFIG1H,
_OSCS_OFF_1H & _HS_OSC_1H
__CONFIG _CONFIG2L,
_BOR_OFF_2L & _PWRT_ON_2L
__CONFIG _CONFIG2H,
_WDT_OFF_2H
__CONFIG _CONFIG3H,
_CCP2MX_OFF_3H
__CONFIG _CONFIG4L,
_STVR_OFF_4L & _LVP_OFF_4L & _DEBUG_ON_4L
__CONFIG _CONFIG5L,
_CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L
__CONFIG _CONFIG5H,
_CPB_OFF_5H & _CPD_OFF_5H
__CONFIG _CONFIG6L,
_WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L
__CONFIG _CONFIG6H,
_WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
__CONFIG _CONFIG7L, _EBTR0_OFF_7L
& _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L
__CONFIG _CONFIG7H,
_EBTRB_OFF_7H
;******************************************************************************
MAX_COUNT
equ
0xff
;Do
this many A to D conversions.
ACQ_SET
equ
.20
;Timer
for acquistion time.
A2D_0
equ b'00000000'
A2D_1
equ b'00001000'
A2D_2
equ b'00010000'
A2D_3
equ b'00011000'
A2D_4
equ b'00100000'
A2D_5
equ b'00101000'
A2D_6
equ b'00110000'
A2D_7
equ b'00111000'
;******************************************************************************
;Variable
definitions
CBLOCK
0x400
count
acq_count
ENDC
;******************************************************************************
;Vectors
ORG 0x0000
goto Main
;Reset
vector.
ORG 0x0008
;
goto
High_ISR
;High
priority interrupt vector
ORG 0x0018
;
goto
Low_ISR
;Low
priority interrupt vector and routine
;******************************************************************************
;Start of
main program
Main:
movlw
0x04
;Set
BSR to Bank 4. (Only used for 'count' and
'aqu_count')
movwf BSR,
ACCESS
clrf count
clrf acq_count
lfsr FSR0,
0x00
;Clear RAM.
Clear_RAM_Loop
clrf POSTINC0,
ACCESS
;Clear RAM pointed to by INDF register and inc.
movlw 0x00
cpfseq FSR0L,
ACCESS
bra Clear_RAM_Loop
movlw 0x04
cpfseq FSR0H,
ACCESS
bra Clear_RAM_Loop
movlw
b'11001110'
;setup
A/D converter.
movwf ADCON1,
ACCESS
Loop
movlw b'10000001'
|
A2D_0
;Select A/D channel 0.
movwf ADCON0,
ACCESS
movlw
ACQ_SET
;Wait
for aquisition time, then...
movwf acq_count
Acq_Loop
decfsz acq_count, F
bra Acq_Loop
bsf ADCON0,
GO_DONE,
ACCESS ;
start conversion.
AD_Wait
btfsc ADCON0,
GO_DONE,
ACCESS
;Did A/D conversion compleat?
bra
AD_Wait
;
No, loop back.
movff ADRESL,
FSR0L
;Load A/D output to FSR0, then...
movff ADRESH,
FSR0H
incf INDF0,
F,
ACCESS
; incroment the RAM byte corisponding to A/D
reading.
incf count,
F
;Have we compleated n A/D conversions?
movlw MAX_COUNT
cpfseq count
bra Loop
;
No, continue.
End_Loop
bra End_Loop
END
-----Original
Message-----
From: scubagreg7777777
[mailto:n...@yahoogroups.com]
Sent: Sunday, December 05, 2004
3:55 PM
To: p...@yahoogroups.com
Subject: [piclist] A/D conversion
problems on ADC_CHAN1 and ADC_CHAN2
This is an update to my earlier posted problem. I
have now changed my
openADC() function call to only use 1 channel, and
rely on the
setADCChannel() function. It looks like
this:
OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST &
ADC_8ANA_0REF,ADC_CH0 &
ADC_INT_OFF );
I have not experienced any success yet. When
putting a 5v signal on
pin 3 (ADC_CHAN1) and receive values of 377 to
3FF. This, itself is
strange, as I can verify with a multimeter that
the 5v signal is
almost identical to the 5v powering the chip ( +/-
0.01V).
However, when I apply a ground signal to pin 3, I
receive an ADC value
of 0x2AF, which is far too high. I have verified
that it is indeed a
~0V signal going into pin 3.
Any help is appreciated. I also have increased my
delay loop in the
checkAdc() function to cycle 1800 times, from 180
times.
Thanks,
Greg
-----------------------
Hi everyone,
I'm still quite new to micros, and am doing a
project on the
PIC18F452. I am experiencing some troubles with
ADC conversion, and
think that it is a simple solution, but I'm
not
sure what it is. I
tried to provide all the pertienent info, and
explain my problem. If
someone can please take a look at it, and let me
know what I'm doing
wrong I would really appreciate it.
==============================================
========= H/W and S/W setup =========
- PIC18f452 running on a 4MhZ
oscillator
- using PICDEM 2 Board and PCB I
created
- MCC18 C compiler
- MPLAB 6.4
I am doing three A/D conversions on PORT A. In all
three cases, I
take the hex value returned from the A/D
conversion and, using
thresholds, assign a discrete "digital"
value for use in my main program.
I am experiencing some troubles with accuracy of
the ADC.
==============================================
========= What I have done so far
=========
- double checked my sample time (ADC_FOSC / Ta/d )
value. From the
18F452 datasheet (page 188) I selected a healthy
buffer time, using
TOSC32 (my PIC is running off a 4Mhz oscillator),
so in the code I
used ADC_FOSC_32 for my configuration bit (page 16
in the MCC18
libraries pdf file).
- Right before doing the conversion, I am using
setChanADC to
specificy which pin on PORTA I want to do the
conversion for
- although there are other operations between the
conversions, I
created a no-op delay loop that cycles through 180
operations after my
setChanAdc() function call. I am assuming 1
instruction per 2.5e-7
second, at 4Mhz. I read in the datasheet (page
187) that there is a
A/D changing time, and recall reading somewhere
else in the datasheet
that it is typically 20us. Therefore the no-op
loop alone exceeds
this 20us requirement.
- calculated my desired hex value for Vx [ ( V /
Vdd) * 1023 ]
---- convert answer to hex ---> Hex value
wanted from A/D conversion
- have finally gotten so frustrated/baffled, that
I hooked up my
18f452 onto the PICDEM 2 board in debug mode, and
am looking at the
result of my A/D conversion in the software window
with breakpoints.
==============================================
========= Explanation of Trouble
=========
I am NOT having trouble with this conversion. It
is on pin2, which is
ADC_CHAN0 / PORTAbits.RA0. The first conversion is
the voltage off a
POT directly to pin2. Values can range from ~0v to
~5v. When using
the PICDEM 2 board in debug mode, I watch the
window for my ADC value,
and it increases and decreases in a manner that
corresponds with the
voltage changed by the pot.
The second conversion is one I am having trouble
with (the 3rd is the
same nature as the second, and have excluded it
from my question). I
am now running my 18F452 on the PICDEM board with
MPLAB 6.4, looking
at the value returned from the A/D conversion (in
my code, it is the
last function call and the variable is
'a2dResult'). This takes place
in the function call checkLight(). When I start up
my code in debug
mode, I begin simple testing and put 5v (my Vdd)
onto pin 3 /
ADC_CHAN1. With breakpoints and the MPLAB Watch
window I see that the
returned value is an expected 0x3FF. I then try
the same, by applying
0v on pin 3. Then the A/D conversion returns an
expected 0x000 value.
However, I placed a voltage divider on my PICDEM
board, and tried to
measure the voltage, and I get a hex value
returned to the variable
'a2dResult'. After that, if I reapply 5v
or 0v to
pin 3 (ADC_CHAN1) I
no longer get the expected 0x3FF or 0x000 value,
or anything remotely
close to it. The readings for ADC_CHAN1 become
very unpredictable,
however the A/D conversions for ADC_CHAN0 (pin 2
w/ the POT) remain
stable and continue to be accurate.
I read in the datasheet that the maximum impedance
for analog sources
is 2.5Kohm, but I am not sure if this. What I
would like to do is to
be able to accurately read off ADC_CHAN1 and
ADC_CHAN2 in my program.
I am not sure if I am doing something wrong with
my code, hardware
setup, or what. I have a suspicion it is software,
as my hardware
circuits are quite simple. If anyone can help,
please let me know.
Thanks,
Greg
==============================================
========= Code =========
(some of the formatting might get lost when I
click submit - sorry!)
/* Include Libraries */
#include <p18f452.h> /* for TRISB and PORTB
declarations */
#include <adc.h> /* A/D library
*/
#include <stdlib.h> /* Standard Library
*/
/**********************************************/
/* Function Prototypes */
int checkSpeed( void );
void delay(int, int);
void checkLight( void );
int checkAdc( int );
/***********************************************/
/* Variable Declaration */
/* */
/* main() */
int test = 0; // test variable used in main to
determine if Ra1 is
detecting high load (temp)
int dipVal = 0; // value returned from checkDip()
function call
int speedVal = 0; // speed setting returned
from
checkSpeed() function call
int onTime = 0; // max amount of time a particular
channel/light
can be turned on
int offTime = 0; // amount of time a channel/light
will be turned off
int delayCounter = 0; // counter variable, useed
in output
display engine for on and off time
int speedCounter = 1; // used in nested loop to
get around max
numeric value -- full explanation in dev
notes
int curOutput = 1; // current chanel being
output
/* checkSpeed() */
int a2dSpeed = 0 ; // value obtained from a2d
conversion
int userInputSpeed = 0; // speed setting, inferred
from a2dSpeed
value, returned to main
// 1 = slow, 2 = medium, 3 = fast
/* delay() */
int i = 0; // counter, used for delay
loop
int j = 1; // counter, used for number of loops --
speed control
/* checkLight() */
//macros
int bright = 1; // alias used for code
readability, and
quick changes
int nightTime = 0; // macro definition --> for
code
readability --> digital value of a2dLightResult
value
int dayTime = 2; // macro definition --> for
code
readability --> digital value of a2dLightResult
value
//counters in state tests
int brightTestCount = 0;
int darkTestCount = 0;
//current light value in state tests
int a2dLightResult; // Hex value obtained from ADC
reading on
channel 1 (pin 3)
int currentLight = 0; // digital value (night/day)
of
a2dLightResult which is the current light
reading
//threshold settings
int lightThreshold = 0x01F; // light threshold.
346+ = nighttime,
346- = daytime
int maxLightCount = 15; // maximum number of
consecutive
light/dark test results allowed
/* checkAdc */
int temp = 0; // counter used for ADC delay
loop
int adcDelay = 180; // delay required for adc
reading
// 20uS wait time + generious safety margin of
50%
int a2dResult = 0; // result obtained from A/D
conversion
void main( void )
{
/* Initialize Configuration */
TRISA = 0b00000111; // configs first 3 ports of
PORTA for INPUT --
used for checkSpeed()
TRISC = 0xFF; // configs PORTC for INPUT -- used
for checkDip()
TRISD = 0x00; // configs PORTD for OUTPUT -- used
for light
output
TRISB = 0x00; // configs PORTB to all output
pins
/* configure A/D convertors */
/* detailled explanation is located at: p 16-18
in
MPLAB-C18-Libraries.pdf */
/* ADC_FOSC_32 -> a/d clock source uses
FOSC/32
ADC_RIGHT_JUST -> result in least significant
bits
ADC_8ANA_0REF -> VREF+ = Vdd and VREF- = Vss
(both analog) / in my
case Vdd = ~5v and Vss = ~0v
ADC_CH# -> the channel being used
ADC_INT_OFF -> disable interrupts
*/
/* ADC_CH0 -> speed */
OpenADC( ADC_FOSC_32 & ADC_RIGHT_JUST &
ADC_8ANA_0REF,ADC_CH0 &
ADC_CH1 & ADC_CH2 & ADC_INT_OFF ); /*
checkSpeed() */
/* main program */
while(1)
{
/* (re)initialize values */
speedVal = 0;
dipVal = 0;
/* obtain user input */
checkLight(); // detects amount of ambient
light
speedVal = checkSpeed(); // check speed
setting
} /* end while(1) */
} /* end main() */
/***************************************************
Function: checkSpeed()
Arguments: none
Return: int userInputSpeed -> digitized value
of user's speed selection
(1 = slow, 2 = medium, 3 = fast)
I/O Pins Used: PORTA -> RA0
Description: checkSpeed() checks PORTA.RA0 and
through a series of if
statements,
converts the voltage into one of 3 values and
returns this
value
****************************************************/
int checkSpeed ( void)
{
a2dSpeed = checkAdc(ADC_CH0); // check ADC on
channel A0,
which is pin 2
/* Interpret a2d value into slow/medium/fast speed
*/
if( a2dSpeed <= 341) // slow
setting
userInputSpeed = 1;
else if( (a2dSpeed <= 682) && (a2dSpeed
>= 342) ) // medium setting
userInputSpeed = 2;
else if ( (a2dSpeed <= 1023) &&
(a2dSpeed >= 683) ) // fast setting
userInputSpeed = 3;
else
userInputSpeed = -1; // signifies error w/ a2d
conversion
return userInputSpeed; /* return obtained value
*/
} /* end checkSpeed() */
void checkLight( void )
{
/* (re)init values */
a2dLightResult = -1;
currentLight = -1;
/* read ADC value */
a2dLightResult = checkAdc( ADC_CH1 ); // obtain
ADC reading
from channel 1 (pin 3)
/* give a2dLightResults a finite, digital value of
'night' or 'day' */
if(a2dLightResult >= 0x1F0) //
nighttime
PORTB = 1;
if(a2dLightResult < 0x1F0) //
daytime
PORTB = 15;
}
int checkAdc( int portaChan )
{
// (re)init variables
a2dResult = -1; // result of adc
read
temp = 0; // counter used in adc delay
loop
/* AtoD Conversion */
/* CloseADC() is not used, as nowhere in the MCC18
libraries
documentation, or PIC18F452
datasheet
does it suggest leaving an A/D converter on is
harmful or
discouraged. Opening the A/D
converter
once (in main()'s init period, and leaving it
open
saves some
computational time
*/
SetChanADC( portaChan ); // Open ADC channel
specified by user
/* research timing constraings when using
SetChanADC function call */
/* p187 - 188 in pic18f452 datasheet
*/
while(temp < adcDelay) // temporary
solution
temp++;
ConvertADC(); // Start conversion
while( BusyADC() ); // Wait for
completion
a2dResult = ReadADC(); // Read result
return a2dResult;
}
to
unsubscribe, go to http://www.yahoogroups.com
and follow the instructions