PDA

View Full Version : Strange ADC behaviour



ruijc
- 6th December 2007, 21:57
Hi guys,

i've made a simple circuit to measure the ad value from 2 channel of my 16F88 pic out to a LCD.

The strange thing is that porta.1 's values are conditioned by the results in porta.0 !

For example... this is what i get on my LCD...


Porta.1 = 5.00v lcd = 5.0
porta.0 = 5.00v lcd = 5.0

Porta.1 = 0.17v lcd = 0.17
Porta.0 = 5.00v lcd = 4.17

porta.1 = 2.54v lcd = 2.54
porta.0 = 5.00v lcd = 4.54

porta.1 = 5.00v lcd = 5.00
porta.0 = 4.58v lcd = 5.00

Here's the code:

output portb.7
low portb.7

Define osc 4

' Define LCD pins
Define LCD_DREG PORTB
Define LCD_DBIT 0
Define LCD_RSREG PORTB
Define LCD_RSBIT 4
Define LCD_EREG PORTB
Define LCD_EBIT 5
Define LCD_BITS 4

'variables
va1 var word
va2 var word
temp var word
volt var word

pause 200 'init LCD
lcdout $fe,1 'clear LCD

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

input porta.0
input porta.1

ADCON1 = %10000011 ' set porta analog and right justify result

loop:

ADCIN 0, va1
ADCIN 1, va2

temp = (va1 */ 500 ) >> 2
volt = (va2 */500) >>2

high portb.7

lcdout $fe,2,"VOLTAGE..",dec (volt/100),",",dec2 volt,"V"
lcdout $fe,$c0,"TEMP.....",dec (temp/100),",",dec2 volt,"V"

pause 250

Goto loop

End

Thanks

mister_e
- 6th December 2007, 23:10
In theory the comparator should already be off at POR, but for safety sake, add this line at the top of your code

CMCON=7

This kind of weirdness is usually caused by a too high external analog impedance, AND/OR a too short sampling time, or combination of. Make sure your external source is bellow the maximum recommended (<10K if my memory serves me well for this device).

You could still add some PAUSE/PAUSEUS between each ADCIN to see if it's better or worst.

I'll suggest to properly set the ANSEL register and set to digital all unused i/o as well.

BUT the main problem is in red


lcdout $fe,2,"VOLTAGE..",dec (volt/100),",",dec2 volt,"V"
lcdout $fe,$c0,"TEMP.....",dec (temp/100),",",dec2 volt,"V"

have a look at DIG modifier as well.

ruijc
- 7th December 2007, 19:37
Thanks mister_e

I guess i need glasses on this one...

lcdout $fe,2,"VOLTAGE..",dec (volt/100),",",dec2 volt,"V"
lcdout $fe,$c0,"TEMP.....",dec (temp/100),",",dec2 volt,"V"

Corrected that but still some strange behaviour...

With
porta.1 = 0.16v lcd 0.16 and porta.0=5v lcd 5

but

with porta.1 = 0.16v AND porta.0 = 0.16v lcd 0.00v on both

I'm guessing some comparator issue here...

mister_e
- 7th December 2007, 19:49
ah come on ;) let's see what happen if i put some explanation 'round.


lcdout $fe,2,"VOLTAGE..",dec (volt/100),",",dec2 volt,"V"
GOOD! you want to display voltage, that's what you do in both DEC and DEC2 modifier.

NOW


lcdout $fe,$c0,"TEMP.....",dec (temp/100),",",dec2 volt,"V"
'
'
'

Why are you mixing temp AND VOLT......?

ruijc
- 7th December 2007, 19:54
Let me correct my last statement:

Having 2 LM35 on my breadboard

Porta.1 working fine either each one

Porta.0 showing 0.00 when conected to any one of them

Tryed a pot to get a lower voltage ( 0.16v ) like the LM35 but with the pot is working !!!
Also getting good readings from other like pulldown resistor or 5v supply !

Same code for both though

added :

pauseus 500 between each adc reading,

also

CMCON=7 on top of code

Any ideas ?

ruijc
- 7th December 2007, 19:56
sorry Mister-e...

You did not undestand my post ;)

i was just quoting your statement...i did corrected that :)

this is how it is:

lcdout $fe,2,"VOLTAGE..",dec (volt/100),",",dec2 volt,"V"
lcdout $fe,$c0,"TEMP.....",dec (temp/100),",",dec2 temp,"C"



.

mister_e
- 7th December 2007, 19:58
EDIT: let me see...

ruijc
- 7th December 2007, 20:01
i get

voltage = 2.49
temp = 1.25

.

mister_e
- 7th December 2007, 20:21
mmm, must be too drunk and blind now..
what if you add

ansel=3
trisa=3

at the top of your code?

what if you forget the decimal point but use


lcdout $fe,2,"VOLTAGE..",dec volt," V"
lcdout $fe,$c0,"TEMP.....",dec temp," C"

instead?

skimask
- 7th December 2007, 20:28
lcdout $fe,2,"VOLTAGE..",dec volt," V"
lcdout $fe,$c0,"TEMP.....",dec temp," C"
[/QUOTE]

Shouldn't that be dec (volt/100) and dec (volt // 100) above?

ruijc
- 7th December 2007, 20:34
Thanks for the help

The code is correct like Mister-e posted because the reading values are 0.xx and with the /100 i would have just 0 !

Changed everything but i still get

porta.1 = 17
and
porta.0 = 0

changing each other i still get the same on lcd

.

mister_e
- 7th December 2007, 20:45
out of curiosity, which version of PBP are you using? i've never ever used ADCIN in my program since over 5-6 years.

I may bet on some averaging... but i hate to bet on friday ;)

ruijc
- 7th December 2007, 21:29
My version is 2.47

But i will try a 2nd pic now and see...

.

ruijc
- 7th December 2007, 21:32
Tryed a 2nd pic but same result...

it's not a pic failure

.

mister_e
- 7th December 2007, 22:05
How better/worst it is if you dump the appended .HEX file in your PIC... don't change anything in the config fuses.. use it AS-IS

ruijc
- 7th December 2007, 22:17
I just changed the MCLR off to on ( i was affraid i could get my pic locked ).

But it worked and both ports are 0.15V ... meaning...are reading both LM35

EDIT:
The first line of the LCD is not steady...i mean...i get VOLTAGE..0.15V and dLTAGE..0.15V ( blinking some times )
.

tenaja
- 8th December 2007, 17:22
After the Line2 command, I found that I often had to add a space ahead the text, or the first character would get dropped. Some LCD's are too slow to change lines and display immediately. Apparently you need a delay, since it's effecting more than one character.

ruijc
- 9th December 2007, 12:04
I still get behaviour no matter what i change...


except with Mister-e's code that works OK

Is it just a pbp version issue or is it something else ?

If it's a version problem...is there a way to get arround it ?

.

Acetronics2
- 9th December 2007, 16:58
Hi, Ruijc

I just re-wrote your code ... works fine ( I'm only talking of the PIC point of view - do not talk about precision ...)

Try to write carefully ( and readably) ALL your config sequence ( I know ... ~ 50 lines ! )... and it will work !!!

Just a tip:

instead of :

" temp = (va1*/500)>> 2 "

try :

" temp = val*125
temp = temp.highbyte "

Alain

mister_e
- 9th December 2007, 17:26
Mine did some averaging, not much. Read the sensor couple of time (10-16 times) then calculate the average of it, go to next channel, do the same, show the results.

I did it the 'bad' way


for loopw = 0 to 15
ADCIN 0, TEMPW
VA1=VA1 + (TEMPW>>4)
NEXT

pause 500

FOR LOOPW=0 TO 15
ADCIN 1, TEMPW
VA2=VA2 + (TEMPW>>4)
NEXT

lost of precision and so on, now for something better, have a look at Darrel's routine.

Averaging 16 bit values without using 32 bit math?
http://www.pbpgroup.com/modules/wfsection/article.php?articleid=7

Acetronics2
- 9th December 2007, 19:45
lost of precision and so on, now for something better, have a look at Darrel's routine.



Hi, Steve

for precision ... measuring 150 or 200 mV on a 5 v full scale is a nonsense ...
we already had this discussion here with ruijc ...

Alain

mister_e
- 9th December 2007, 20:01
Yup i agree, an external Vref or op-amp should be used.

ruijc
- 10th December 2007, 17:14
Hi guys

thanks for all the help.

Mister-e...you mentioned an external Vref.

I have a 12v power down to 5v for this circuit.

Can i use 12v as reference ? How can i do this ?

I'm a bit confused...can i plug it directly to my 16F88 ?

.

mister_e
- 10th December 2007, 17:46
NO NO NO DON'T DO IT :D

Vref have to be lower than Vdd. Let's see you have a sensor who produce you a max of 1 volt. Then you select a Vref of ~1 Volt, then your ADC give you the full 10 bit conversion scale between 0-Vref. This is the use of it.

But yeah.. check out for the minimum Vref requirement...:D

Acetronics2
- 10th December 2007, 17:54
NO NO NO DON'T DO IT :D

Vref have to be lower than Vdd. Let's see you have a sensor who produce you a max of 1 volt. Then you select a Vref of ~1 Volt, then your ADC give you the full 10 bit conversion scale between 0-Vref. This is the use of it.

Hi, Steve

a LM 385 or 385-1.2 will make a nice ( and cheap ! ...) 1.235 v reference here ...

BUT, do not forget the higher the signal ... the smaller the noise ! ( and last digit flickering ! ) ...
so, here, the sensor choice is " not so good" ... If I understood (?) , our friend wants to read ambiant temp ... 150-250 mv levels !


( note an OPA will amplify noise + signal ... "not so good" solution too ...)

Alain

ruijc
- 10th December 2007, 18:35
Hello Alain,

the purpose of this circuit is first to learn ;)
Then it will be for reading temperatures between 20 and 130ºC.

The forum mentioned the LM335 as the best choice but this one does not reach above 100ºC.

I had the LM35 and the LM135 ( which does accept temps higher than 100ºC ) on my list.

The problem is than my local store does not have the LM135 :( so i'm kinda stuck with this one !

I will retry to write the code with your tip :

" temp = val*125
temp = temp.highbyte "


.

b1arrk5
- 11th December 2007, 00:03
You might also try a little pause between reading adc channels, to make certain that the internal capacitor has fully discharged between readings. Someone else just had a similar problem last week, it's posted on this forum.

Jerry.

ruijc
- 12th December 2007, 18:30
Hi guys,

some changes made but still Porta.0 is running the show :(

If i change the input on porta.0 it changes my "fixed" reading on porta.1

What i did :

Turned on the Vref+ and with a voltage drop through resistors i managed to get 1.6V vref in porta.3 and added this in my code:
ADCON1 = %10100011

Also added a pauseus between readings
pauseus 1000

placed on LCD the original adc reading followed by the math result
lcdout $fe,2, dec tes1, " PA1 ", dec volt, " "
lcdout $fe,$c0,dec te0," PA0 ", dec temp, " "

Acetronics,

you said that you re-wrote my code and it worked...

One question:

Have you made any changes ?

I dont know where to turn now :(

.

Acetronics2
- 12th December 2007, 20:03
Acetronics,

you said that you re-wrote my code and it worked...

One question:

Have you made any changes ?

.

Hi, Ruijc

I did not make any noticeable change to your " functionnal " program ( = the part that runs )

BUT ... as I told you, The config section took me ~ 50 lines.

Here is your headache : The processor config lines !!!




'************************************************* ****************************
'************************************************* ****************************
'09/12/2007
'
'Lecture de 2 temp avec LM35 ( ambiant temp ... LOL ! )
'
'PIC 16F88 @ 4Mhz

'************************************************* ****************************
'Config

@ __CONFIG _CONFIG1, _CP_OFF & _CCP1_RB3 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_ON & _INTRC_IO

@ __CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF

OSCCON = %01101110 'Internal RC w/ I/Os

INTCON = 0
PIE1 = 0
PIE2 = 0
CMCON = 7
CVRCON = 0


'************************************************* ****************************
'DEFINEs
'************************************************* ****************************

'OSC

DEFINE osc 4

'************************************************* ****************************
'
'ADC

DEFINE ADC_BITS 10 ' Set number of bits in result ( 8 or 10 bits )

'DEFINE ADC_CLOCK 3 ' Set clock source (3=rc)

DEFINE ADC_SAMPLEUS 50 ' Set sampling time in uS

'************************************************* ****************************
'
'LCD

DEFINE LCD_DREG PORTB
DEFINE LCD_DBIT 0
DEFINE LCD_RSREG PORTB
DEFINE LCD_RSBIT 4
DEFINE LCD_EREG PORTB
DEFINE LCD_EBIT 5
DEFINE LCD_BITS 4

DEFINE LCD_COMMANDUS 2000

'************************************************* ****************************
'ADC parameters

ADCON0 = %11000000 ' clock source
ADCON1 = %10000011 ' set porta.0 and .1 analog and right justify result
ANSEL = %00000011 ' Porta.0 and .1 used by ADC

'************************************************* ****************************
' variables

va1 var word
va2 var word
temp var word
volt var word

LM351 con 0
LM352 con 1

CLEAR

'************************************************* ****************************
'I/O's

PORTA = %00000000
PORTB = %00000000

TRISA = %00000011
TRISB = %00000000

'************************************************* ****************************
'PINS

LM35_1 var PORTA.0
LM35_2 var PORTA.1
a2 var PORTA.2
a3 var PORTA.3
a4 var PORTA.4
MCLR var PORTA.5
a6 var PORTA.6
a7 var PORTA.7

DATA1 var PORTB.0
DATA2 var PORTB.1
DATA3 var PORTB.2
DATA4 var PORTB.3

R_S var PORTB.4
E var PORTB.5
b6 var PORTB.6
LED var PORTB.7


'************************************************* ****************************
'************************************************* ****************************
'
'************************************************* ****************************
'Init LCD

pause 500 'init LCD
lcdout $fe,1 'clear LCD


loop:

ADCIN LM351, va1 ' 15 °C ... 150 /5000*1024 = 30.72 ... 30 = NOT GOOD !!!
ADCIN LM352, va2

'temp = (va1 */ 500 ) >> 2
temp = (va1*125)
temp = temp.Highbyte

'volt = (va2 */500) >> 2
volt = (va2*125)
volt = volt.Highbyte

high portb.7

lcdout $fe,2,"VOLTAGE..",dec (volt/100),".",dec2 volt,"V"
lcdout $fe,$c0,"TEMP.....",dec (temp/100),".",dec2 volt,"V"

pause 250

Goto loop

End



as you can see it ....no great change to what you did ...


IT IS FORBIDDEN TO YOU TO PASTE THAT CODE ... before having understood YOU MUST CONFIGURE the registers and ports by YOURSELF !!!

PbP cares for some ... yes, but only some "general use" ones.

Also try to show a "readable" listing where you ( mostly ! ) and others can find if you've programmed the "good" registers or not ...

And for the end ... remember to separate the "config zone" and the "working zone" ... setting registers in the "working zone" must be kept ONLY if changes have to be made while running ...


Here we are ... PbP doesn't do everything for you ...that's it

Especially read those F...manual and Datasheet !!!


Keep on ... thinking you're good at pics ... you'll become really good one day !!!

Alain