PDA

View Full Version : A/D conversion with PIC18F67J50



ScaleRobotics
- 6th May 2009, 19:11
I am having a heck of a time getting A/D conversion to work with the pic18f67j50. I know I am probably missing something basic from rtfm.

In desperation, I have tried to copy some C demo code (that is working on my hardware), and translate the basic setup to picbasic pro. My hardware is the Olimex PIC_LCD3310 located here http://www.olimex.com/dev/pic-lcd3310.html

I have the display working. Right now I just have an analog operator issue.

Here is my setup from the include file:


else
LIST
LIST p = 18F67J50, r = dec, w = -311, w = -230, f = inhx32
INCLUDE "P18F67J50.INC" ; MPASM Header
CONFIG XINST = OFF
CONFIG STVREN = OFF ;added
CONFIG WDTEN = OFF ;added
CONFIG CP0 = OFF ;added
CONFIG IESO = OFF ;added
CONFIG FCMEN = OFF ;added
CONFIG CCP2MX = DEFAULT ;added
CONFIG PLLDIV = 5
CONFIG WDTPS = 32768 ;was 512
CONFIG CPUDIV = OSC1
CONFIG FOSC = HSPLL
CONFIG MSSPMSK = MSK5 ;added
NOLIST
endif


And here is one of my attempts at getting A/D out of it:


DEFINE OSC 48

include "modedefs.bas"
include "LCD_3310.pbp"

TRISD = 0
PORTD.0 = 1 'turn on g sensor
PORTD.1 = 0 'select scale for g sensor
PORTD.2 = 0 'select scale for g sensor


TRISA = %00000111 'set porta.0, 1, and 2 as inputs
TRISB = 0
CM1CON = 7
CM2CON = 7
TRISC = 0
TRISE = 0
ADCON0 = %00000001 'turn on adc
ADCON1 = %00000010 'fosc/32 ??
'am I translating c language ADCON1=0x10 above correctly?

resx var word
x var word
y var word
z var word
adval var word

x=0
y=0
z=0
adval = 0

PORTD.0 = 1 'turn on g sensor (again)
'*************************************************
@bsf WDTCON,ADSHR ;set shared address SFR with WTCON<4> - is this right?
ADCON0 = %11111110 ' channel with a 0 is analog input, all others digital
@bcf WDTCON,ADSHR
ADCON1 = %10111110 'right justified, AD=20AD, A/D clock=fosc/64
ADCON0.0 = 1 'turn on adc

ADCON0.2 = 0 'channel select bit CHS0(should already be a 0)
ADCON0.3 = 0 'Channel select bit CHS1(should already be a 0)


start:
Pause 500 ' Wait .5 second
loop: ADCON0.1 = 1 'Start Conversion
adval = 0 'clear result word
notdone: pause 5
if ADCON0.1 = 1 Then notdone 'wait for low on bit-2 of ADCON0, conversion finished

adval.highbyte = ADRESH 'move HIGH byte of result to adval
adval.lowbyte = ADRESL 'move LOW byte of result to adval

ADCON0 = %00000000 'turn off adc

'Lcdout $fe, 1 'Clear screen
'Lcdout "Value: ", DEC adval 'Display the decimal value
@ PrintStr 0,0, "Z= " ;display on Nokia 3310
@ PrintVar 24,0, _adval ;display result on 3310
Pause 100 'Wait .1 second

'Goto loop 'Do it forever
End


This is an (apparently BAD) attempt at making it look almost just like:


#pragma config XINST = OFF // Extended instruction set
#pragma config STVREN = OFF // Stack overflow reset
#pragma config PLLDIV = 5 // (20 MHz crystal used on this board)
#pragma config WDTEN = OFF // Watch Dog Timer (WDT)
#pragma config CP0 = OFF // Code protect
#pragma config CPUDIV = OSC1 // OSC1 = divide by 1 mode
#pragma config IESO = OFF // Internal External (clock) Switchover
#pragma config FCMEN = OFF // Fail Safe Clock Monitor
#pragma config FOSC = HSPLL // Firmware must also set OSCTUNE<PLLEN> to start PLL!
#pragma config WDTPS = 32768
// #pragma config WAIT = OFF // Commented choices are
// #pragma config BW = 16 // only available on the
// #pragma config MODE = MM // 80 pin devices in the
// #pragma config EASHFT = OFF // family.
#pragma config MSSPMSK = MSK5
// #pragma config PMPMX = DEFAULT
// #pragma config ECCPMX = DEFAULT
#pragma config CCP2MX = DEFAULT

;---------------snip

////////////MMA pins configuration - Sleep mode disabled///////////////////////////////
TRISDbits.TRISD0=0;
PORTDbits.RD0=1;
//GS1 =0
TRISDbits.TRISD1=0;
PORTDbits.RD1=0;
//GS2=0
TRISDbits.TRISD2=0;
PORTDbits.RD2=0;

TRISAbits.TRISA0=1;
TRISAbits.TRISA1=1;
TRISAbits.TRISA2=1;
//ADC module enable
//ADCON1=0x10111110; //right-justified; AD=20AD;A/D clock=fOSC/64
ADCON0=0x01; //Enable ADC module
ADCON1=0x10;
////////////////////////MMA measure/////////////////////
resx=0;
x=0;
y=0;
z=0;
sym=0;
PORTDbits.RD0=1; //MMA SLEEP MODE disable
//************************************************** **************************
ANCON0bits.PCFG0=0; //AN0 - analog input
ADCON1=0b10111110; //right-justified; AD=20AD;A/D clock=fOSC/64
// ADCON1=0x10;
ADCON0bits.ADON=1; //Enable ADC module, AVdref, AVss
//set Z-axis measure
ADCON0bits.CHS0=0;
ADCON0bits.GO=1; //BSF ADCON0,GO ;Start conversion
while(ADCON0bits.GO); // BSC ADCON0,GO ;Is conversion done? ; GOTO $-1 ;No, test again
resz=ADRESL;
z=ADRESH;
z=(z<<8)|resz;
resz=z;
ADCON0=0x00; //stop ADC
//************************************************** **************************


If someone could point out what an idiot I am, that would be great!

Thanks!

Walter

Darrel Taylor
- 6th May 2009, 19:47
I believe it's the ADCON0 = %00000000 'turn off adc

You probably get a reading the first loop through.
But for all loops after that, the A/D module is turned off.
<br>

ScaleRobotics
- 6th May 2009, 20:26
Thanks Darrel,

I commented out my ADCON0 = %00000000 and put the loop back in, and confirmed my loop is looping. My result seems to be stuck at 24543, 40910 or 8142 each time I reset. Basically giving me random numbers as best I can tell. But despite the loop looping, the numbers do not change, until I remove power from the unit, then apply power again.



DEFINE OSC 48

include "modedefs.bas"
include "LCD_3310.pbp"

TRISD = 0
PORTD.0 = 1 'turn on g sensor
PORTD.1 = 0 'select scale for g sensor
PORTD.2 = 0 'select scale for g sensor


TRISA = %00000111 'set porta.0, 1, and 2 as inputs
TRISB = 0
CM1CON = 7
CM2CON = 7
TRISC = 0
TRISE = 0
ADCON0 = %00000001 'turn on adc
ADCON1 = %00000010 'fosc/32 ??
'am I translating c language ADCON1=0x10 above correctly?

resx var word
x var word
y var word
z var word
adval var word

x=0
y=0
z=0
adval = 0

PORTD.0 = 1 'turn on g sensor (again)
'*************************************************
@ bsf WDTCON,ADSHR ;set shared address SFR with WTCON<4> - is this right?
ADCON0 = %11111110 ' channel with a 0 is analog input, all others digital
@ bcf WDTCON,ADSHR
ADCON1 = %10111110 'right justified, AD=20AD, A/D clock=fosc/64
ADCON0.0 = 1 'turn on adc

ADCON0.2 = 0 'channel select bit CHS0(should already be a 0)
ADCON0.3 = 0 'Channel select bit CHS1(should already be a 0)


start:
Pause 500 ' Wait .5 second
loop: ADCON0.1 = 1 'Start Conversion
adval = 0 'clear result word
notdone: pause 5
if ADCON0.1 = 1 Then notdone 'wait for low on bit-2 of ADCON0, conversion finished

adval.highbyte = ADRESH 'move HIGH byte of result to adval
adval.lowbyte = ADRESL 'move LOW byte of result to adval

'ADCON0 = %00000000 'turn off adc

'Lcdout $fe, 1 'Clear screen
'Lcdout "Value: ", DEC adval 'Display the decimal value
x = x +1 'test to see if loop is working
@ PrintStr 0,0, "Z= " ;display on Nokia 3310
@ PrintVar 24,0, _adval ;display result on 3310
@ PrintVar 0,1, _x ;show if loop is looping
Pause 100 'Wait .1 second

Goto loop 'Do it forever
End

ScaleRobotics
- 6th May 2009, 20:53
Whoops,

I noticed that it was going to my include file, then popping up at start: which missed all my settings to the ADCON0 etc.

Sometimes I have to say it out loud (to everyone) to figure it out, with the help of some experts. I won't tell anyone how many days I was trying..........

Thanks,

Walter

mister_e
- 6th May 2009, 21:32
You conversion clock seems a bit high @48MHz operation, and your first example in C used ANCON0, not yours.... yet...

While it's not a problem for now, one day you may need to disable some analog feature on this PIC... however, seems ANCON0 and ANCON1 are not included in PBP 2.50c, so I guess the following would be handy one day or another.


'
' Configure ADC
' =============
ANCON0 VAR BYTE EXT ' not included in PBP2.50c
ANCON1 VAR BYTE EXT ' not included in PBP2.50c

ANCON0 = %10011110
' -xx------ Not Implemented
' 1--1111-- AN7, & AN<4:1> = Digital
' -------0- AN0 = Analog

ANCON1 = %11111111
' 11111111- AN<15:10> = Digital

ADCON0 = %00000001
' 0-------- VCFG1, Vref- 0 = AVss (1=AN2)
' -0------- VCFG2, Vref+ 0 = AVdd (1=AN3)
' --0000--- CHS<3:0>, Channel select -- 0
' ------0-- Go/Done, don't care for now
' -------1- ADON, Enable ADC

ADCON1 = %10000111
' 1-------- ADFM, Right justified result
' -0------- ADCAL, Normal A/D converter operation
' --000---- ACQT<2:0>, A/D Aquisition time = 0 Tad
' -----111- ADCS<2:0>, A/D conversion clock = FRC

'
' Hardware Aliases
' ================
GoDone var ADCON0.1 ' StartConversion = 1, Conversion done = 0

'
' Software Variables
' ==================
@ADVal = ADRESL
ADVal VAR WORD EXT

Start:
pauseus 10 ' Acquisition time
GoDone = 1
While GoDone : Wend
LCDOUT $FE, 1, "Value: ", DEC ADVal
PAUSE 250
GOTO START

EDIT: for some odd reason, ANCON0 & ANCON1 are commented in PIC18EXT.BAS, i'd sent an e-mail to Melabs, obviously they must have a reason for that.

ScaleRobotics
- 6th May 2009, 22:32
Thanks mister_e ! I have flipped to page 299 to 302 so many times but never noticed the "D" to "N" change. Doh!

Do you think it is edited out because it is a shared address, only distinguished by the address share bit ADSHR in the WDTCON register?

Currently I have to:
@ bsf WDTCON,ADSHR 'flag address share bit
ADCON0 = %11111000 ' channels with a 0 is analog input, all others digital
@ bcf WDTCON,ADSHR
(or should I say I think? I have to....)

to set the aNcon0 register

(Despite all my mistakes, I am now getting valid conversion results, as of post 4)

mister_e
- 6th May 2009, 22:47
Holly crap, yeah, that make sense indeed. Yet another stupidity from Microchip :eek:

So my example will need some changes...


'
' Configure ADC
' =============
ANCON0 VAR BYTE EXT ' not included in PBP2.50c
ANCON1 VAR BYTE EXT ' not included in PBP2.50c

WDTCON.4 = 1 ' Switch to Alternate SFR
ANCON0 = %10011110
' -xx------ Not Implemented
' 1--1111-- AN7, & AN<4:1> = Digital
' -------0- AN0 = Analog

ANCON1 = %11111111
' 11111111- AN<15:10> = Digital

WDTCON.4 = 0 ' Back to Default SFR
or

'
' Configure ADC
' =============
WDTCON.4 = 1 ' Switch to Alternate SFR

ADCON1 = %10011110 ' alternate ANCON0
' -xx------ Not Implemented
' 1--1111-- AN7, & AN<4:1> = Digital
' -------0- AN0 = Analog

ADCON0 = %11111111 ' alternate ANCON1
' 11111111- AN<15:10> = Digital

WDTCON.4 = 0 ' Back to Default SFR

By far, i prefer the first, easier to read ;)

However, yours work.. keep it like that. If it's not broken, don't fix it!

mister_e
- 7th May 2009, 04:59
Side note... there's no real need to redefine ANCON1, ANCON0 as i did if you use ANCON1_ALT, ANCON0_ALT within your code. Those two are defined in PIC18EXT.BAS.

Having _ALT written at the right of the register name, may remember you to set/clear WDTCON.4 bit? Maybe ;)

ScaleRobotics
- 7th May 2009, 15:20
Side note... there's no real need to redefine ANCON1, ANCON0 as i did if you use ANCON1_ALT, ANCON0_ALT within your code. Those two are defined in PIC18EXT.BAS.

Having _ALT written at the right of the register name, may remember you to set/clear WDTCON.4 bit? Maybe ;)

Sweet! I did not see that either. May be time for glasses. And a lot cleaner than the way I was doing it, and I like the way you wrote the registry bits in the code. That would have kept me from having to divert my attention to and from tfm a lot!

Thanks for all the help.

Walter

mister_e
- 8th May 2009, 01:48
To me, comments are really important. So, on the long run... coding like that


ADCON0 = %00000001
' 0-------- VCFG1, Vref- 0 = AVss (1=AN2)
' -0------- VCFG2, Vref+ 0 = AVdd (1=AN3)
' --0000--- CHS<3:0>, Channel select -- 0
' ------0-- Go/Done, don't care for now
' -------1- ADON, Enable ADC

May indeed avoid to open the datasheet all the time, one thing is sure, it's easier to modify/understand later.