PDA

View Full Version : need help with adc



houa
- 20th September 2005, 05:36
new to using pbp language

using pic18f452
using port A to do conversion
using strain guage sensor
lcd on port b
keypad on port c

question:
need help writing code to do adc for strain guage sensor
to output weight on the lcd

strain guage conditioned to 0-5v
weight desired 0-300 or 0-400lbs

any help would be greatly appreciated
sorry i don't really know the processes for writing threads yet since i am new
thanks for any help

CocaColaKid
- 20th September 2005, 12:56
DEFINE OSC 4 ' Set Xtal Frequency
DEFINE ADC_BITS 10 ' Set resolution of conversion
DEFINE ADC_CLOCK 8 ' Set clock source (x/FOSC or FRC)
DEFINE ADC_SAMPLEUS 50 ' Set sampling time (in uS)

ADFM var ADCON1.7 ' ADC result format select bit
PCFG3 var ADCON1.3 ' ADC port configuration bit
PCFG2 var ADCON1.2 ' ADC port configuration bit
PCFG1 var ADCON1.1 ' ADC port configuration bit
PCFG0 var ADCON1.0 ' ADC port configuration bit

PCFG0 = 0 ' Configure AN0 as analogue input, others digital
PCFG1 = 1
PCFG2 = 1
PCFG3 = 1
ADFM = 1 ' Right justified result in ADRESL and ADRESH

adcin 0,adc_in ' Place the conversion of channel0 into adc_in



For 0-300 lbs output = adc_in * 100 / 341
For 0-400 lbs output = adc_in * 100 / 256

This will give you an output within 1 lb.

houa
- 21st September 2005, 05:49
thanks a lot

Ingvar
- 21st September 2005, 09:06
Theese calculations will overflow when adc_in is greater than 655.

For 0-300 lbs output = adc_in * 100 / 341
For 0-400 lbs output = adc_in * 100 / 256

It would be better to use the "*/" operator for these calculations.

For 0-300 lbs output = adc_in */ 75
For 0-400 lbs output = adc_in */ 100

If you want proper rounding of the result you can use.....

For 0-300 lbs output = ((adc_in */ 750)+5)/10
For 0-400 lbs output = ((adc_in */ 1000)+5)/10

CocaColaKid
- 21st September 2005, 13:25
Oops, missed that one. I personally would use this:

d = 100
dummy = adc_in * d
adc_value = DIV32 256

Substitute 341 for the 256 is using the 0-300 lbs scale. The adc_value variable will contain the lbs.

houa
- 22nd September 2005, 01:22
thanks a lot guys
but more probelms occured...
after testing the program and testing the voltage received using a multimeter
the actually voltage range is approx 0.44 volts +/- .009 volts and the max load we were able to obtain is approx 4.99 volts +/- .009 volts.

can you please explain to me how the equations so i can understand the analog to digital conversion + plus can if possible, derive a new equation to fix this problem.

here's the source code:

Define LOADER_USED 1
Define LCD_DREG PORTB
Define LCD_DBIT 4
Define LCD_RSREG PORTB
Define LCD_RSBIT 0
Define LCD_EREG PORTB
Define LCD_EBIT 1
DEFINE OSC 4 ' Set Xtal Frequency
DEFINE ADC_BITS 10 ' Set resolution of conversion
DEFINE ADC_CLOCK 8 ' Set clock source (x/FOSC or FRC)
DEFINE ADC_SAMPLEUS 50 ' Set sampling time (in uS)
'---------------------------------------------------------------
' INTCON.7 = 0 ' Enable PORTB pullups
' ADCON1 = 7 ' Make PORTA and PORTE digital
Low PORTB.2 ' LCD R/W low (write)
TRISA = %11111111 ' Set PORTA to all input
ADCON1 = %10000010 ' Set PORTA analog and right justify result
'---------------------------------------------------------------
d VAR word
dummy var word
adc_in var word
W VAR WORD
adc_value var word

ADFM var ADCON1.7 ' ADC result format select bit
PCFG3 var ADCON1.3 ' ADC port configuration bit
PCFG2 var ADCON1.2 ' ADC port configuration bit
PCFG1 var ADCON1.1 ' ADC port configuration bit
PCFG0 var ADCON1.0 ' ADC port configuration bit

PCFG0 = 0 ' Configure AN0 as analogue input, others digital
PCFG1 = 1
PCFG2 = 1
PCFG3 = 1
ADFM = 1 ' Right justified result in ADRESL and ADRESH

loop:
adcin 0,adc_in ' Place the conversion of channel0 into adc_in
d = 100
dummy = adc_in * d
adc_value = DIV32 256
W = adc_value
pause 500
Lcdout $FE, 1
Lcdout $FE, $80, #W," lbs"
pause 500
goto loop

anymore help would be appreciated

thanks a lot

Ingvar
- 22nd September 2005, 10:18
Ok, here's one way to do it.

The general formula would be ....

result = (adc_in - CalLO)*Range/(CalHI-CalLO)

.... where

adc_in = input from ADconverter
Range = Maximum load
CalLO = adc_in when load is zero
CalHI = adc_in when load is "Range"

You could calculate and "hardcode" the last two, but the best solution would be to make a small calibrationroutine that gathers the readings. I'll use 0.44v as zero load and 4.99v at maximum load(300lbs).



Range CON 300
adc_in VAR WORD
CalLO VAR WORD
CalHI VAR WORD
div_val VAR WORD
result VAR WORD
dummy VAR WORD

CalLO = 90 ' calculated calibrationvalue (0.44/5*1024)
CalHI = 1022 ' calculated calibrationvalue (4.99/5*1024)

div_val = CalHI - CalLO
dummy = (adc_in - CalLO) * Range
result = DIV32 div_val


If you want rounding you could do .....


Range CON 3000
adc_in VAR WORD
CalLO VAR WORD
CalHI VAR WORD
div_val VAR WORD
result VAR WORD
dummy VAR WORD

CalLO = 90 ' calculated calibrationvalue (0.44/5*1024)
CalHI = 1022 ' calculated calibrationvalue (4.99/5*1024)

div_val = CalHI - CalLO
dummy = (adc_in - CalLO) * Range
result = DIV32 div_val
result = (result + 5) / 10 'rounded result


/Ingvar

houa
- 22nd September 2005, 18:17
Thanks a lot Ingvar
You are the best
I'll try that code out

Leonardo
- 22nd September 2005, 18:37
You can put the scheme?

houa
- 27th September 2005, 02:51
scale isn't accurate...

the code is logical and it makes sense, but the scale itself doesn't weight correctly

can it be that i have a faulty sensor?

is there a way to correct this?