PDA

View Full Version : ADC Help Please



elevenscorpions
- 14th June 2007, 03:12
I'm having some trouble with the analog inputs on a 16F886. Code is shown below. Most of it is commented out right now, so it's just an initial LED flash, analog in, heartbeat routine. I want to use AN0(RA0), AN1(RA1) and AN4(RA5) as analog inputs. If I comment out all of the ADCIN instructions, the LED flashes away as it should. If I uncomment any of the ADCINs, the heartbeat LED just stays on. It seems I'm doing something wrong with either the ADC configuration or the actual ADCIN command, but what? I had something very similar to this working fine on a 16f690, but changing over to the 16F886 has caused me some problems. This is new for me, so any comments/suggestions on programming style, etc. would be welcome. Thanks.



BrianB

define OSC 4
Define ADC_BITS 8 ' Set number of bits in result
Define ADC_CLOCK 3 ' Set clock source (3=rc)
Define ADC_SAMPLEUS 50 ' Set sampling time in uS

'CM1CON0 = 0 ' Comparators off (Do I need these?)
'CM2CON0 = 0 ' Comparators off
ANSEL = %00010011' Set analog pins
ANSELH = %00000000
TRISA = %00100011' Set port A
TRISB = %11000000 ' Set port B
TRISC = %00000000 ' Set port C

ANIN0 var WORD 'Cylinder 1 Feedback Pot
ANIN1 var WORD 'Cylinder 2 Feedback Pot
SW1EXT var bit 'Extend Switch
SW2RET var Bit 'Retract Switch
EXT1FLAG VAR Bit
RET1FLAG VAR Bit
EXT2FLAG var bit
RET2FLAG var bit
J var WORD

'Initialize Variables and Ports
PORTA=0
PORTB=0
PORTC=0
EXt1flag=0
ext2flag=0
ret1flag=0
ret2flag=0

for j=1 to 25 'Startup indicator
toggle PortA.2
pause 50
next j

MAIN:
FOR j=1 TO 500
Adcin 4, ANIN0
'Poll Switches
'If PortB.7=0 then
' pause 20
' if PORTB.7=0 then
' SW1EXT=1
' endif
'Else
' SW1EXT=0
'ENDIF
'If PortB.6=0 then
' pause 20
' if PORTB.6=0 then
' SW2RET=1
' endif
'else
' SW2RET=0
'endif
'adcin 0, ANIN0 'Cylinder 1 Pot
'IF ANIN0<245 then
' EXT1FLAG=0 'OK to Extend
'Else
' EXT1FLAG=1
'endif
'IF ANIN0>10 then
' RET1FLAG=0 'OK to Retract
'else
' RET1FLAG=1
'ENdif
'ADCIN 1, ANIN1 'Cylinder 2 Pot
'IF ANIN1<245 then
' EXT2FLAG=0 'OK to Extend
'Else
' EXT2FLAG=1
'endif
'IF ANIN1>10 then
' RET2FLAG=0 'OK to Retract
'else
' RET2FLAG=1
'ENdif

'IF (SW1EXT=1) and (EXT1FLAG=0) then 'Extend Cylinder 1
' PORTB.3=1
' PORTB.4=0
' PORTB.5=1
'endif
'IF (SW1EXT=1) and (EXT1FLAG=1) then 'Stop Cylinder 1
' PORTB.3=0
' PORTB.4=0
' PORTB.5=0
'ENDIF
'IF (SW2RET=1) and (RET1FLAG=0) then 'Retract Cylinder 1
' PORTB.3=0
' PORTB.4=1
' PORTB.5=1
'endif
'IF (SW2RET=1) AND (RET1FLAG=1) then 'Stop Cylinder 1
' PORTB.3=0
' PORTB.4=0
' PORTB.5=0
'endif
'IF (SW1EXT=1) and (EXT2FLAG=0) then 'Extend Cylinder 2
' PORTB.0=1
' PORTB.1=0
' PORTB.2=1
'endif
'IF (SW1EXT=1) and (EXT2FLAG=1) then 'Stop Cylinder 2
' PORTB.0=0
' PORTB.1=0
' PORTB.2=0
'ENDIF
'IF (SW2RET=1) and (RET2FLAG=0) then 'Retract Cylinder 2
' PORTB.0=0
' PORTB.1=1
' PORTB.2=1
'endif
'IF (SW2RET=1) AND (RET2FLAG=1) then 'Stop Cylinder 2
' PORTB.0=0
' PORTB.1=0
' PORTB.2=0
'endif
'if (SW1EXT=0) and (SW2RET=0) then 'Stop Cylinders
' PORTB.3=0
' PORTB.4=0
' PORTB.5=0
' PORTB.0=0
' PORTB.1=0
' PORTB.2=0
'endif
'if SW1EXT=1 and SW2RET=1 then 'Stop Cylinders
' PORTB.3=0
' PORTB.4=0
' PORTB.5=0
' PORTB.0=0
' PORTB.1=0
' PORTB.2=0
'endif
'if (ANIN0>ANIN1) AND (SW1EXT=0) AND (SW2RET=0) THEN
' GOSUB SLAVE1
'ENDIF
'IF (ANIN1>ANIN0) AND (SW1EXT=0) AND (SW2RET=0) THEN
' GOSUB SLAVE2
'ENDIF

NExt J
toggle PORTA.2 'Heartbeat LED
pause 500
goto main

'SLAVE1:
'IF (ANin0-ANin1)>=5 THEN
' PORTB.0=1
' PORTB.1=0
' PORTB.2=1
'ENDIF
'if (ANin0-ANin1)<5 THEN
'PORTB.0=0
'PORTB.1=0
'PORTB.2=0
'ENDIF
'RETURN

'SLAVE2:
'IF (ANin1-ANin0)>=5 THEN
' PORTB.0=0
' PORTB.1=1
' PORTB.2=1
'ENDIF
'IF (ANin1-ANin0)<5 THEN
'PORTB.0=0
'PORTB.1=0
'PORTB.2=0
'ENDIF
'RETURN

mister_e
- 14th June 2007, 03:32
I'll try it here, but i think it has something to do with the WORD variable inside a ADCIN setuped for 8 bit results... not sure yet. I have to find those 886 here first... What a messy bench i have in front of me http://www.mister-e.org/Pics/ROFL

mister_e
- 14th June 2007, 04:35
OK it's true, ADCIN do something bad on this chip, now i have to find why. In meantime use something like

<font color="#000000"> <font color="#000080">DEFINE </font>OSC 4

ADCON0=%11000001
ADCON1=%00000000
GoDone <font color="#000080">VAR </font>ADCON0.1
<font color="#008000">'76543210
</font>CHSELECT <font color="#000080">VAR BYTE

</font>CM1CON0 = 0 <font color="#008000">' Comparators off (Do I need these?)
</font>CM2CON0 = 0 <font color="#008000">' Comparators off
</font>ANSEL = %00010011<font color="#008000">' Set analog pins
</font>ANSELH = %00000000
TRISA = %00100011<font color="#008000">' Set port A
</font>TRISB = %11000000 <font color="#008000">' Set port B
</font>TRISC = %00000000 <font color="#008000">' Set port C

</font>ANIN0 <font color="#000080">VAR BYTE </font><font color="#008000">'Cylinder 1 Feedback Pot
</font>ANIN1 <font color="#000080">VAR BYTE </font><font color="#008000">'Cylinder 2 Feedback Pot
</font>SW1EXT <font color="#000080">VAR BIT </font><font color="#008000">'Extend Switch
</font>SW2RET <font color="#000080">VAR BIT </font><font color="#008000">'Retract Switch
</font>EXT1FLAG <font color="#000080">VAR BIT
</font>RET1FLAG <font color="#000080">VAR BIT
</font>EXT2FLAG <font color="#000080">VAR BIT
</font>RET2FLAG <font color="#000080">VAR BIT
</font>J <font color="#000080">VAR WORD

</font><font color="#008000">'Initialize Variables and Ports
</font>PORTA=0
PORTB=0
PORTC=0
EXT1FLAG=0
EXT2FLAG=0
RET1FLAG=0
RET2FLAG=0

<font color="#000080">GOTO </font>START

<font color="#000080">ASM
ADC_IN MACRO CHANNEL, VARIABLE
MOVE?CB CHANNEL, _CHSELECT
L?CALL _DO_AD_CONVERSION
MOVE?BB ADRESH,VARIABLE
ENDM
ENDASM

</font>DO_AD_CONVERSION:
ADCON0=(CHSELECT&lt;&lt;2) |%11000001
<font color="#000080">PAUSEUS </font>50
GoDone=1
<font color="#000080">WHILE </font>GoDone : <font color="#000080">WEND
RETURN
</font>START:
<font color="#000080">FOR </font>J=1 <font color="#000080">TO </font>25 <font color="#008000">'Startup indicator
</font><font color="#000080">TOGGLE </font>PortA.2
<font color="#000080">PAUSE </font>50
<font color="#000080">NEXT </font>J

MAIN:
<font color="#000080">FOR </font>J=1 <font color="#000080">TO </font>500
@ ADC_IN 4,_ANIN0
<font color="#008000">'Poll Switches
</font><font color="#000080">IF </font>PortB.7=0 <font color="#000080">THEN
PAUSE </font>20
<font color="#000080">IF </font>PORTB.7=0 <font color="#000080">THEN
</font>SW1EXT=1
<font color="#000080">ENDIF
ELSE
</font>SW1EXT=0
<font color="#000080">ENDIF

IF </font>PortB.6=0 <font color="#000080">THEN
PAUSE </font>20
<font color="#000080">IF </font>PORTB.6=0 <font color="#000080">THEN
</font>SW2RET=1
<font color="#000080">ENDIF
ELSE
</font>SW2RET=0
<font color="#000080">ENDIF

</font>@ ADC_IN 0,_ANIN0

<font color="#000080">IF </font>ANIN0&lt;245 <font color="#000080">THEN
</font>EXT1FLAG=0 <font color="#008000">'OK to Extend
</font><font color="#000080">ELSE
</font>EXT1FLAG=1
<font color="#000080">ENDIF

IF </font>ANIN0&gt;10 <font color="#000080">THEN
</font>RET1FLAG=0 <font color="#008000">'OK to Retract
</font><font color="#000080">ELSE
</font>RET1FLAG=1
<font color="#000080">ENDIF

</font>@ ADC_IN 1,_ANIN1

<font color="#000080">IF </font>ANIN1&lt;245 <font color="#000080">THEN
</font>EXT2FLAG=0 <font color="#008000">'OK to Extend
</font><font color="#000080">ELSE
</font>EXT2FLAG=1
<font color="#000080">ENDIF

IF </font>ANIN1&gt;10 <font color="#000080">THEN
</font>RET2FLAG=0 <font color="#008000">'OK to Retract
</font><font color="#000080">ELSE
</font>RET2FLAG=1
<font color="#000080">ENDIF

IF </font>(SW1EXT=1) <font color="#000080">AND </font>(EXT1FLAG=0) <font color="#000080">THEN </font><font color="#008000">'Extend Cylinder 1
</font>PORTB.3=1
PORTB.4=0
PORTB.5=1
<font color="#000080">ENDIF

IF </font>(SW1EXT=1) <font color="#000080">AND </font>(EXT1FLAG=1) <font color="#000080">THEN </font><font color="#008000">'Stop Cylinder 1
</font>PORTB.3=0
PORTB.4=0
PORTB.5=0
<font color="#000080">ENDIF

IF </font>(SW2RET=1) <font color="#000080">AND </font>(RET1FLAG=0) <font color="#000080">THEN </font><font color="#008000">'Retract Cylinder 1
</font>PORTB.3=0
PORTB.4=1
PORTB.5=1
<font color="#000080">ENDIF

IF </font>(SW2RET=1) <font color="#000080">AND </font>(RET1FLAG=1) <font color="#000080">THEN </font><font color="#008000">'Stop Cylinder 1
</font>PORTB.3=0
PORTB.4=0
PORTB.5=0
<font color="#000080">ENDIF

IF </font>(SW1EXT=1) <font color="#000080">AND </font>(EXT2FLAG=0) <font color="#000080">THEN </font><font color="#008000">'Extend Cylinder 2
</font>PORTB.0=1
PORTB.1=0
PORTB.2=1
<font color="#000080">ENDIF

IF </font>(SW1EXT=1) <font color="#000080">AND </font>(EXT2FLAG=1) <font color="#000080">THEN </font><font color="#008000">'Stop Cylinder 2
</font>PORTB.0=0
PORTB.1=0
PORTB.2=0
<font color="#000080">ENDIF

IF </font>(SW2RET=1) <font color="#000080">AND </font>(RET2FLAG=0) <font color="#000080">THEN </font><font color="#008000">'Retract Cylinder 2
</font>PORTB.0=0
PORTB.1=1
PORTB.2=1
<font color="#000080">ENDIF

IF </font>(SW2RET=1) <font color="#000080">AND </font>(RET2FLAG=1) <font color="#000080">THEN </font><font color="#008000">'Stop Cylinder 2
</font>PORTB.0=0
PORTB.1=0
PORTB.2=0
<font color="#000080">ENDIF

IF </font>(SW1EXT=0) <font color="#000080">AND </font>(SW2RET=0) <font color="#000080">THEN </font><font color="#008000">'Stop Cylinders
</font>PORTB.3=0
PORTB.4=0
PORTB.5=0
PORTB.0=0
PORTB.1=0
PORTB.2=0
<font color="#000080">ENDIF

IF </font>SW1EXT=1 <font color="#000080">AND </font>SW2RET=1 <font color="#000080">THEN </font><font color="#008000">'Stop Cylinders
</font>PORTB.3=0
PORTB.4=0
PORTB.5=0
PORTB.0=0
PORTB.1=0
PORTB.2=0
<font color="#000080">ENDIF

IF </font>(ANIN0&gt;ANIN1) <font color="#000080">AND </font>(SW1EXT=0) <font color="#000080">AND </font>(SW2RET=0) <font color="#000080">THEN
GOSUB </font>SLAVE1
<font color="#000080">ENDIF

IF </font>(ANIN1&gt;ANIN0) <font color="#000080">AND </font>(SW1EXT=0) <font color="#000080">AND </font>(SW2RET=0) <font color="#000080">THEN
GOSUB </font>SLAVE2
<font color="#000080">ENDIF

NEXT </font>J

<font color="#000080">TOGGLE </font>PORTA.2 <font color="#008000">'Heartbeat LED
</font><font color="#000080">PAUSE </font>500
<font color="#000080">GOTO </font>MAIN

SLAVE1:
<font color="#000080">IF </font>(ANIN0-ANIN1)&gt;=5 <font color="#000080">THEN
</font>PORTB.0=1
PORTB.1=0
PORTB.2=1
<font color="#000080">ENDIF

IF </font>(ANIN0-ANIN1)&lt;5 <font color="#000080">THEN
</font>PORTB.0=0
PORTB.1=0
PORTB.2=0
<font color="#000080">ENDIF

RETURN

</font>SLAVE2:
<font color="#000080">IF </font>(ANIN1-ANIN0)&gt;=5 <font color="#000080">THEN
</font>PORTB.0=0
PORTB.1=1
PORTB.2=1
<font color="#000080">ENDIF

IF </font>(ANIN1-ANIN0)&lt;5 <font color="#000080">THEN
</font>PORTB.0=0
PORTB.1=0
PORTB.2=0
<font color="#000080">ENDIF

RETURN
</font>

mister_e
- 14th June 2007, 04:49
something is bad with ADCIN with this chip, so before breaking something i will ask Charles at Melabs.

In meantime the above solution or manually set/read register method still work.

Bruce
- 14th June 2007, 17:48
Compare ADCON0 & ADCON1 in the 16F690 & 16F886 data sheets. ADCON0
and ADCON1 are different. Microchip shifted things around again, so ADCIN
library will need some tweaking to work with this one.

I would just configure A/D regs manually, and forget about ADCIN.

mister_e
- 14th June 2007, 19:12
Yup, i had an answer from Charles that confirm a issue of those 16F88x serie. He suggest this work around


DEFINE ADC_BITS 8 ' ADCIN resolution (Bits)
DEFINE ADC_CLOCK 0 ' Work around that sets Vref bits in ADCON1
DEFINE ADC_SAMPLEUS 50 ' ADC sampling time (uSec)
ADCON0=ADCON0 | %11000000 ' Work around that sets ADCS in ADCON0

i've tested it here, and it's working. So now, you have 2-3 different way to make it work.

elevenscorpions
- 16th June 2007, 18:49
Works great now. Thanks.

BrianB

aberco
- 9th February 2009, 20:15
Hi everyone,
I am following up on that ADC config issue, as I have troubles to make my project (based on a 16F884) to work.

Here is the hardware part:

The project is a nixie clock with other fancy stuffs (thermometer, hygrometer...). That is, I use the analog module to read various sensors. Additionally, due to the lack of I/O, I use an "analog" keypad consisting of 3 pushbuttons that each produce a different voltage (with resistor combinations).

So far, I can only get erratic values out of the ADC no matter which A/D pin I'm reading... It is varying as if the pin was connected to an antenna and reading noise (with completely random variations from min to max!). I also tried to ground one of the analog I/O to read it, and the results are actually pulled towards 0, but can still get as high as 300.

I don't thing the hardware is wrong on that one, I have a steady 5V powersupply, checked with a scope, also sensor output were checked and don't fluctuate more than a few mV. I also included capacitors between inputs and ground... and everything is mounted on a nice dual side PCB.

The only source of noise would be my buck-boost switch, that I use to get the 180V for the tubes, but I don't see much noise when I look on the analog lines with my scope.

This is why i'm suspecting a software or config problem, but can't work it out. And since there's issue with this family I'd like to make sure i'm not doing anything wrong.
Here is parts of my program, I added the workaround posted above in the config:

DEFINE OSC 20
DEFINE LOADER_USED 1

'set up the ADC with special workaround for the 16F88x family
DEFINE ADC_BITS 10 ' ADCIN resolution (Bits)
DEFINE ADC_CLOCK 0 ' Work around that sets Vref bits in ADCON1
DEFINE ADC_SAMPLEUS 50 ' ADC sampling time (uSec)
ADCON0=ADCON0 | %11000000 ' Work around that sets ADCS in ADCON0

'Set oscillator configuration to run on external oscillator
OSCCON = %00000000

'Set comparators off
CM1CON0 = %00000000
CM2CON0 = %00000000

'Set analog input AN0, AN1, AN2, AN3, AN4 and AN5
ANSEL = %00011111
ANSELH = %00000000
ADCON1 = %00000000
'ADCON0 = %01000001

'Set PortA as input or output
PORTA = %00000000
TRISA = %00101111
'Set entire PortB as digital input
PORTB = %00000000
TRISB = %00000000
'Set entire PortC as digital input
PORTC = %00000000
TRISC = %00000000
'Set entire PortD as digital input
PORTD = %00000000
TRISD = %00000000
'Set PortE0 as input or output
PORTE = %00000000
TRISE = %00000001

---------------------------

'************************************************* ******
'Read the keypad
'************************************************* ******
ReadPushButtons:
'Mode/UP 0.47V
'Date/DOWN 2.6V
'SET 5.0V

ADCIN 5, ButtonValue

Return

---------------------------

All other (non analog) functions are working great otherwise...!
Any help apreciated :)

mackrackit
- 9th February 2009, 20:23
1 = Input
0 = Output

aberco
- 9th February 2009, 21:48
Hmm good catch! I forgot AN5 which was purposedly the one I'm trying to read...!

Here is ANSEL now:
'Set analog input AN0, AN1, AN2, AN3, AN4 and AN5
ANSEL = %00111111

However that hasn't changed anything, for AN5 or the other sensors (AN4 to AN0).

Going through the 16F884 datasheet again to check these registers.

I remember doing this lately on a 16F877A whithout much troubles!

mister_e
- 9th February 2009, 22:42
Compiler version?

aberco
- 10th February 2009, 07:25
It is PBP 2.50

mackrackit
- 10th February 2009, 12:18
Take the advise from Bruce in post 5.
Here is an example for a different chip, but you will get the idea. Works much nicer.
http://rentron.com/PICX2.htm

And it may not be causing you trouble now but it could ...Maybe you got my hint...


'Set entire PortB as digital input
PORTB = %00000000
TRISB = %00000000
'Set entire PortC as digital input
PORTC = %00000000
TRISC = %00000000
'Set entire PortD as digital input
PORTD = %00000000
TRISD = %00000000
1 = Input
0 = Output

aberco
- 10th February 2009, 17:48
I will try to read the ADC manually then,

And I missed your hint, because the code is working for those I/O's (however the comments are wrong!).


'Set entire PortB as digital output
PORTB = %00000000
TRISB = %00000000
'Set entire PortC as digital output
PORTC = %00000000
TRISC = %00000000
'Set entire PortD as digital output
PORTD = %00000000
TRISD = %00000000

Looks better now :D

aberco
- 12th February 2009, 15:16
Ok, I just tried to recompile my code for a 16F877A and if does work much better. Values are still fluctuating a bit so I will have to find a way to stabilize this (using software and or hardware).

here is the new init code

'************************************************* ******
'Init for PIC16F877A
'************************************************* ******

'Set ADC pins to digital operation
ADCON1 = %10001001 'AN0 to AN5 are analog input
CMCON = %00000111 'disabling the comparator module

'Define pin function
TRISA = %00101111 'Set PortA as input or output
TRISB = %00000000 'Set entire PortB as digital output
TRISC = %00000000 'Set entire PortC as digital output
TRISD = %00000000 'Set entire PortD as digital output
TRISE = %00000001 'Set PortE0 as input and rest as output

' Define ADCIN parameters
Define ADC_BITS 10 ' Set number of bits in result
Define ADC_CLOCK 3 ' Set clock source (3=rc)
Define ADC_SAMPLEUS 50 ' Set sampling time in uS

I thought I would use a 16F88x since the 877A is being phased out. Also I have a couple 884 on hand... but with all the extra trouble I think I will stick to the 877A to write the code and then transfer it to the 884 afterward.

Will update the status of the project here ;)


PS: as far as my noise problem comming from the HV generation circuit, I now switch off the PWM module that drive the switching mosfet slightly before doing my analog readings and they are now rock solid :)