PDA

View Full Version : Sonic Depth Meter code & Math problems 12F683



johnnylynx
- 29th October 2013, 05:13
I'm a newbie when it comes to programming...with some previous experience, but getting old and remembering less...

I'm creating a depth meter using a MAXSONAR ranger - using the PW output. I've made the code work previously with a Basic Stamp BS2, but want to use the 12F683 with PBP3. The problem seems to be in the math.

My input readings "inputpulse" reads anywhere from 92 to 466 after taking the average of 10 readings and dividing by 10 (just to move back the decimal). 92 (is tank full) and 364 is tank empty. using these values I am changing the tap setting on an AD5220 (digital Potentiometer). the Digipot values range from 0 to 127.

So, I need to convert the 92 and 364 to 1% or 100% respectively and apply to 127 to get a new tap setting.

I get my average readings fine, but somewhere in the math I can't get a multiplier to properly vary the 127 to a new tap setting...it gives me 0's and 1's or 11,21,31,41,51...

I'm stumped and out of scotch!

here's the code.



'@ __config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_OFF & _CP_OFF

oSCCON = %01100111 ' Ocs set to 4 MHz
TRISIO = %00000000 ' Set all ports to outputs, in this example
CMCON0 = 7 ' Analog comparators off
ANSEL = 0 ' Analog select set to digital, pg 69 data
ADCON0 = 0 ' A/D turned OFF, pg 68 of data

INCLUDE "modedefs.bas"
define char_pacing 1000
define osc 4

'Define Variables *************************

inputpulse var word
dist var word
avgdist var word
x var word
counter VAR byte
oldtapsetting VAR word
newtapsetting VAR word


'Pin Assignments **************************

' GPIO.0 = Pin 7 - Serout LCD
' GPIO.1 = Pin 6 - Output clk to AD5220
' GPIO.2 = Pin 5 - Output U/D Select to AD5220
' GPIO.3 = Pin 4 - Switch Input
' GPIO.4 = Pin 3 - Input from sensor
' GPIO.5 = Not Used

'Set Variables ****************************

dist = 0
oldtapsetting = 0
newtapsetting = 0

'initialize outputs **********************
low gpio.0
low gpio.1
low gpio.2
low gpio.3
low gpio.4
low gpio.5




' Initialize AD5220

LOW gpio.2
FOR counter=0 TO 127
PULSOUT 6,5
PAUSE 1
NEXT

'Main Program ****************************

'get avg depth
pause 1000
for x = 1 to 10
pulsin gpio.4,1,inputpulse
dist= dist + inputpulse
pause 100
next x

avgdist=dist/10

select case avgdist

case is < 92
newtapsetting = 1

case is > 364
newtapsetting = 127

case else
avgdist = avgdist - 92
'avgdist = avgdist
newtapsetting = 127 * (avgdist / 272)
newtapsetting = newtapsetting

end select


serout gpio.0,t9600,[12,"avg :", #avgdist,13]
serout gpio.0,t9600,["tap :", #newtapsetting]

pause 500

end





Help!

John

HenrikOlsson
- 29th October 2013, 07:19
Hi,
I'd probably skip dividing the accumulated result by 10 in order to keep the resolution as long as possible.
It's not perfect but perhaps something like this might work:

newtapsetting = (dist ** 3060) - 42
IF newtapsetting > 127 THEN newtapsetting = 127

This will give you a newtapsetting ranging from 0-127 for a dist value ranging from 920-3640. (At least I think it will....)

/Henrik.

Ioannis
- 29th October 2013, 08:51
Also the program runs one time. Is this what you want?

And on the third paragraph of your post, you say that the sensor gives a value of 92-466 and then 92-364. Which of the two is true?

Ioannis

johnnylynx
- 29th October 2013, 17:39
92 is my rank full value, 466 is zero water in tank, 364 is 8" of water in tank which is my safe empty value.

johnnylynx
- 29th October 2013, 17:41
Have I defined my variables correctly?

johnnylynx
- 29th October 2013, 18:05
Sorry, and yes, runs once to establish one depth value based on the average of 10 readings. I have an external system that cycles the power every 5 min ultimately giving me an average reading every 5 min.

Ioannis
- 29th October 2013, 19:01
I 'd use what Henrik has posted and maybe with a smaller multiplier, say 3000. Keep your ten average pile. Then Henrik's lines will give you directly the result for your digital pot.



'Main Program ****************************

'get avg depth
pause 1000
for x = 1 to 10
pulsin gpio.4,1,inputpulse
dist= dist + inputpulse
pause 100
next x

newtapsetting = (dist ** 3060) - 42 'try also a number smaller, 3000
IF newtapsetting > 127 THEN newtapsetting = 127

serout gpio.0,t9600,[12,"avg :", #avgdist,13]
serout gpio.0,t9600,["tap :", #newtapsetting]

pause 500

end

Ioannis

johnnylynx
- 30th October 2013, 05:44
Thanks guys. I'm trying to understand the math here, help me out.

What is the difference between * and **? I can't seem to find something on this forum that explains this. How does the math work.

For example, Henrik's suggestion above, how did you select 3060 to try and result in a range between 1 and 127? I tried random numbers and 2020 gets me close to my 127 value at full, but gives me 25 at empty. If I subtract 24 to give me 1, then I've also reduced my 127 to 103...Ugg.

and while I'm at it...how doe the */ and // work?


I really need the result to provide a linear value between 1 and 127 for this to work properly. So I feel like I need to determine the ratio of the reading (in this case with full reading 92 and emplty reading 364, I would subtract 91 from the values for an adjusted range between 1 and 273) then take the adjusted value and divide by 273 for a multiplier between 0 and 1 and apply that multiplier to 127.

johnnylynx
- 30th October 2013, 06:20
Excuse my last reply...Henrik's number of 3020 gets me a new tap setting of 127 (perfect empty value) but when the tank is full (8" away from the sensor) the new tap reading is 42 (not 0 or 1). If I subtract 42, the full reading gets to 0 or 1, but my empty reading is also reduced...not letting me see the empty value of 127.

:confused:

HenrikOlsson
- 30th October 2013, 08:11
Hi,
I guess I'm a bit confused by your somewhat "conflicting" numbers.
In your original post you said that the input value ranged from 92 from to 466 but that a full scale output (127) should be reached with an input value of 364.

So, I need to convert the 92 and 364 to 1% or 100% respectively and apply to 127 to get a new tap setting

Think of the ** operator as kind of like multiplying by units of 1/65536. With an input value of 920 (given we stick with the times ten accumulated result) the output value would (should) be 920 * (3060/65536) = 42 and with an input value of 3640 the output value will be 3640 * (3060/65536) = 169. Subtract 42 from the two numbers and you'll get 0 and 127 respectively. Note that it's 3060, not 3020.

Is that not what you wanted? Or is that what you wanted but it doesn't actually give you those results - which is possible as I haven't tested it here. Please clarify.

The */ operator is similar to the ** operator but instead of units of 1/65536 it's units of 1/256. The // operator is modolus or remainder. If you do 123//10 you'll get 3 which is the "left over" from 123/10. They have been covered multiple times on the forum and they are covered in the manual.

/Henrik.

Ioannis
- 30th October 2013, 09:23
And if I may add, to prevent negative results, a limit test for the two sides of the range will guarantee the result will be 0-127.

Ioannis

Archangel
- 31st October 2013, 07:06
So, I need to convert the 92 and 364 to 1% or 100% respectively and apply to 127 to get a new tap setting.

John
You can do this with a simple lookdown2 table, but there is 1 gotcha, in order to have more than 85 values you need to use an 18F series pic
here is the table you basically need.


lookdown2 temp,<[9200,9414 ,9628 ,9842 ,10056,10270,10484,10698,10912,11126,11340,11554,1 1768,11982,12196,12410,_
12624,12838,13052,13266,13480,13694,13908,14122,14 336,14550,14764,14978,15192,15406,15620,15834,_
16048,16262,16476,16690,16904,17118,17332,17546,17 760,17974,18188,18402,18616,18830,19044,19258,_
19472,19686,19900,20114,20328,20542,20756,20970,21 184,21398,21612,21826,22040,22254,22468,22682,_
22896,23110,23324,23538,23752,23966,24180,24394,24 608,24822,25036,25250,25464,25678,25892,26106,_
26320,26534,26748,26962,27176,27390,27604,27818,28 032,28246,28460,28674,28888,29102,29316,_
29530,29744,29958,30172,30386,30600,30814,31028,31 242,31456,31670,31884,32098,32312,32526,32740,_
32954,33168,33382,33596,33810,34024,34238,34452,34 666,34880,35094,35308,35522,35736,35950,36164,_
36378,36592],b

Put it in an 18F and it will count to 127 in a 16F it will count to 85
in fact here is my whole code written for a 16F690 demo board and a PICKIT2 using it's uart window to watch it count


@MyConfig = _INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_ON
@MyConfig = MyConfig & _MCLRE_OFF & _BOR_OFF & _FCMEN_OFF & _IESO_OFF
@ __config MyConfig

DEFINE OSC 4
DEFINE DEBUG_MODE 0 ' Debug sending True serial data
DEFINE DEBUG_REG_PORTA ' Debug Port = PortA as required by PICKIT2 USART Monitor
DEFINE DEBUG_BIT 0 ' Debug.bit = PortA.0
DEFINE DEBUG_BAUD 9600 ' Default baud rate = 9600
DEFINE DEBUGIN_REG PORTA' Debug Port = PortA as required by PICKIT2 USART Monitor
DEFINE DEBUGIN_BIT 1 ' Debugin bit PortA.1
DEFINE DEBUGIN_BAUD 9600' Default baud rate = 9600
DEFINE DEBUGIN_MODE 0 ' Debugin receiving data true = 0 inverted = 1
DEFINE NO_CLRWDT 1
;INDF
;TMR0
;PCL
;STATUS
;FSR
;PORTA = %00000000
;PORTB = 0
;PORTC = %00000000
;PCLATH
;INTCON
;PIR1
;PIR2
;TMR1L
;TMR1H
;T1CON
;TMR2
;T2CON
;SSPBUF
;SSPCON
;CCPR1L
;CCPR1H
;CCP1CON = %10001100 ;Dual PWM 10xx11xx P1A/RC5 P1B/RC4 RC3/AN7 RC2/AN6

;RCSTA
;TXREG
;RCREG
;PWM1CON ;PROGRAMMABLE DEAD BAND DELAY
;PSTRCON = %00000011
;ECCPAS
;ADRESH
ADCON0 = 0 ; analog 1 dig 0

;-----Bank1------------------


;OPTION_REG = %00000000 ;RABPU,INTEDG,T0CS,T0SE,PSA,PS,PS,PS
;bit 7 RABPU: PORTA/PORTB Pull-up Enable bit
;1 = PORTA/PORTB pull-ups are disabled
;0 = PORTA/PORTB pull-ups are enabled by individual port latch values
;JoeNote: may lock up cpu if all ports set as outputs and WPU are enabled by experience!
;bit 6 INTEDG: Interrupt Edge Select bit
;1 = Interrupt on rising edge of RA2/AN2/T0CKI/INT/C1OUT pin
;0 = Interrupt on falling edge of RA2/AN2/T0CKI/INT/C1OUT pin
;bit 5 T0CS: TMR0 Clock Source Select bit
;1 = Transition on RA2/AN2/T0CKI/INT/C1OUT pin
;0 = Internal instruction cycle clock (CLKOUT)
;bit 4 T0SE: TMR0 Source Edge Select bit
;1 = Increment on high-to-low transition on RA2/AN2/T0CKI/INT/C1OUT pin
;0 = Increment on low-to-high transition on RA2/AN2/T0CKI/INT/C1OUT pin
;bit 3 PSA: Prescaler Assignment bit
;1 = Prescaler is assigned to the WDT
;0 = Prescaler is assigned to the Timer0 module
;bit 2-0 PS<2:0>: Prescaler Rate Select bits

;bits TMR0 WDT
;2:0 Rate Rate
;000 1 : 2 1 : 1
;001 1 : 4 1 : 2
;010 1 : 8 1 : 4
;011 1 : 16 1 : 8
;100 1 : 32 1 : 16
;101 1 : 64 1 : 32
;110 1 : 128 1 : 64
;111 1 : 256 1 : 128

TRISA = %00000000
TRISB = %00000000
TrisC = %00000000
;PIE1 :peripheral interrupt enable
;PIE2
PCON = 0 ; shut off brownout
; * * * * * * * * * make sure OSC DEFINE Agrees with OSCCON * * * * * * * * *
OSCCON = %01100000
; 000 = 31kHz
; 001 = 125kHz
; 010 = 250kHz
; 011 = 500kHz
; 100 = 1MHz
; 101 = 2MHz
; 110 = 4MHz (default)
; 111 = 8MHz
;* * * * * * * * * OSCTUNE * * * * * * * * * * * * * * * * * * * * * * * * * *

OSCTUNE = 0 ; factory calibration = 0

;bits 7:5 are unimplemented
;bit 4:0 TUN<4:0>: Frequency Tuning bits
;01111 = Maximum frequency
;01110 =
;•
;•
;•
;00001 =
;00000 = Oscillator module is running at the calibrated frequency.
;11111 =
;•
;•
;•
;10000 = Minimum frequency



;PR2
;MSK
;SSPADD
;SSPMSK
;SSPSTAT
;WPUB = 0
;WPUA = 2
;IOC
;IOCA
;WDTCON
;TXSTA
;SPBRG
;SPBRGH
;BAUDCTL
;ADRESL = %00000000
ADCON0 = %00000000
ADCON1 = %00000000

;EEDAT
;EEDATA
;EEADR
;EEDATH
;EEADRH
WPUB = 0 ; WEAK PULLUPS PORT B
;IOCB ;INTERRUPT ON CHANGE PORT B
;VRCON
CM1CON0 = 0
CM2CON0 = 0
CM2CON1 = 0
ANSEL = 0
ANSELH = 0

main:
index var word
b var word
temp var word
;DEBUGIN [temp]
;index = ~~temp
for index = 92 to 364 step 1
temp =(index * 100)
;if temp < 92 then main



lookdown2 temp,<[9200,9414 ,9628 ,9842 ,10056,10270,10484,10698,10912,11126,11340,11554,1 1768,11982,12196,_
12410,12624,12838,13052,13266,13480,13694,13908,14 122,14336,14550,14764,14978,15192,15406,15620,_
15834,16048,16262,16476,16690,16904,17118,17332,17 546,17760,17974,18188,18402,18616,18830,19044,_
19258,19472,19686,19900,20114,20328,20542,20756,20 970,21184,21398,21612,21826,22040,22254,22468,_
22682,22896,23110,23324,23538,23752,23966,24180,24 394,24608,24822,25036,25250,25464,25678,25892,_
26106, 26320,26534,26748,26962,27176,27390,27604,27818,28 032,28246,28460,28674,28888,29102,29316,_
29530,29744,29958,30172,30386,30600,30814,31028,31 242,31456,31670,31884,32098,32312,32526,32740,_
32954,33168,33382,33596,33810,34024,34238,34452,34 666,34880,35094,35308,35522,35736,35950,36164,3637 8,36592],b

;debug dec b, ","
pause 200
next index

b = (b/100)
debug dec b, " ,"



goto main

Ignore any line that is commented out

johnnylynx
- 1st November 2013, 02:28
mnay thanks to all who provided help. I'm having a tough time...but only due to my ignorance. Archangel, I like the UART use of Pickit2...I need to learn how to use that to help debug. Looking into it right now.

Archangel
- 1st November 2013, 06:04
Archangel, I like the UART use of Pickit2...I need to learn how to use that to help debug. Looking into it right now.1 caveat to use that, is take sure to exit the USART routine before you compile changes, or it tends to lock up the PICKIT, works a treat otherwise, because of it I almost never use a breadboard to test code anymore.