PDA

View Full Version : More Pic basic pro maths help.



retepsnikrep
- 8th February 2011, 19:14
Ok i have a bit of code which reads a -100A - 0 - +100A current sensor.

The sensor idles at 2.5v and swings rail to rail as current flows.

I use a 10 bit adc to capture the value. No issues with all of this.

Now I also capture a sensor offset value at program start up which is the 0A value. this doesnt change much perhaps by one number either way around 510 each day.

So my formula looks like the below.



if BatCurrent < Offset then 'If BatCurrent is < Offset means system is Discharging
BatCurrent = ((Offset - BatCurrent) * 2) / 10 'Subtract offset to get a positive number (0-512 = 0-100A+) Max 99
AmpSign = 45 'Set ascii Character 45 (-) to be displayed if Discharging
goto ExitCurrent
endif


The snippet checks which way the current is flowing and then calculates the value in amps. I cheated and just multiplied the value by 2 as i knew -100A would be an adc reading of 0 so in effect 512 became 1024 or -102.4A So it's a bit off, can anyone suggest some better maths. Vice versa applies and an adc reading of 1024 = +100A flowing

timmers
- 8th February 2011, 22:28
So assuming :-

Amps ADC value
-100 0000
0 0511
+100 1023


Equates to 201 amp values against 1024 a2d values gives us 1024/201 =5.094 a2d's per amp. By multiplying up we lose less in the division.
If using LONG variables you can get even more accuracy.

ADC_VALUE VAR WORD
AMPS VAR BYTE
AMPS_SIGN VAR BYTE
AMPS_CHAR VAR BYTE

ADCIN x,ADC_VALUE 'collect a2d
ADC_VALUE = ADC_VALUE *64 'multiply up by 64 (assuming a WORD variable)
AMPS = ADC_VALUE / 326 'divide down by 64 * 5.094
IF AMPS <100 THEN 'negative amps
AMPS_SIGN ="-"
AMPS_CHAR =100 -AMPS
ELSE 'positive amps
AMPS_SIGN ="+"
AMPS_CHAR =AMPS -100
ENDIF
LCDOUT $FE,128,AMPS_SIGN, DEC3 AMPS


Ok.
Timmers.

retepsnikrep
- 9th February 2011, 03:54
Thanks Timmers that's a big improvement.

I'm using a pic 16F886 so can't use long variables sadly.

Anyone else any other ideas?

HenrikOlsson
- 9th February 2011, 06:30
Hi,
Not tested but how about:

ADC_VALUE VAR WORD
AMPS VAR WORD
i VAR BYTE

AMPS = 0
For i = 0 to 3 ' Sample 4 times
ADCIN 0,ADC_VALUE ' Get actual value
AMPS = AMPS + ADC_VALUE ' Accumulate
NEXT

AMPS = AMPS >> 1 ' Divide by 2, AMPS is now 0-2048
AMPS = AMPS ** 64000 ' Multiply by ~0.97656, AMPS is now 0-2000
AMPS = AMPS - 1000 ' AMPS is now +/-1000, change to AMPS=1000-AMPS to invert.

LCDOUT $FE,$1, "Current: ", SDEC AMPS/10, ".", DEC ABS(AMPS // 10)

/Henrik.

retepsnikrep
- 10th February 2011, 04:26
Clever Henrik. I actually do capture ten samples and average them to get a reliable figure. But your maths after that is interesting. Wish i understood all the funny symbols >> etc

Thanks i might try that.

HenrikOlsson
- 10th February 2011, 06:09
Hi,
The >> is the shift right operator, it shifts the word, in this case, one bit to the right which effectively is the same as dividing by 2. It's really not needed as you might as well change 64000 to 32000 to get the same end result (a value ranging from 0-2000)

In your case, with ten accumulating samples you could remove the shift operation and do Amps = Amps ** 12800 to get value ranging from 0-2000.

The ** operator multiplies by the value you specify and then returns the top 16bits of the intermediate 32bit result (you don't need LONGS for this). In effect this is the same as first multiplying by your value and then dividing by 65536. 12800/65536=0.1953 and 10240*0.1953=2000.

Good luck!
/Henrik.