Here is a snip that uses a lookdown table with linear interpolation between key values. It has had a lot of junk snipped out but it comes from a running program using a PIC16F88.
HTH
Brian
/code
data @0, "Delivery ver Ce 14 Nov 11 " '40 characters
'***** Configuration fuses set via melabs U2 USB Pgmr ***************
' Device = PIC16F88 @ 20 MHz.
' Osc = HS, WDT = Disabled, PwrUpTmr = En, MCLR = Reset, BrnOutRst = En
' LVP = Dis, FlashPgmWrite = En, CCP mux with RB3, Code = Not Prot,
' Data EEPROM = Not Prot, FSCM = En, IntExtSwitch = En
'************************************************* ******************
' OnTime is a BYTE array in this version
'************************* Strategy *****************************
'Delivery.pbp aims to deliver short gas 'burps' at a steady rate
'regardless of tank pressure.
'One litre of gas should be delivered in 200 pulses each of 5 mls @ STP,
'each causing a 20 mBar drop in tank pressure. The start pressure is
'6000 mBar and the end pressure after 200 'burps' is 2000 mB. The
'pressure drop is 6000 - 2000 or 4000 mBar in 200 'burps' = 20 mB/burp.
'The pulse rate is nominally once per second for a delivery time of
'200 seconds or a little over three minutes.
'MaxTank = 6000, MinTank = 2000, Delta P is 4000 mBar, Tank
'volume is 250 mls @ STP.
'Delivery.bpb gets tank pressure messages from the GasMixer on an
'intermittent basis. In between times, it estimates the pressure drop
'from each firing and corrects its estimate whenever a true pressure
'reading comes in.
'The OnTimes are stored as BYTE variables in the two LookDown tables.
'Below are ARBITRARY STARTING VALUES which get overridden during
'Calibration.
''Tank0 Dlvry0 LookDown values
'data @100, 250 'OnTime @ 1500 mB for 20 mB drop
'data @101, 208 '2000 mB
'data @102, 170 '2500
'data @103, 136 '3000
'data @104, 106 '3500
'data @105, 80 '4000
'data @106, 58 '4500
'data @107, 40 '5000
'data @108, 26 '5500
'data @109, 16 '6000
'data @110, 10 '6500
'
'data @115, 0 'SolCal value. 0 = not calibrated, 1 = calibrated
'
''At GasMix startup there is a brief pause during which the operator
''can hit "D" or "d" and start diagnostics. Selecting Solenoid Cal
''will send the DELIVERY 16F88 into the calibration routines.
''At end, SolCal will be set to 1 and the two tables will be updated.
''Tank1 Dlvry1 LookDown values
'data @120, 250 'OnTime @ 1500 mB for 20 mB drop
'data @121, 208 '2000 mB
'data @122, 170 '2500
'data @123, 136 '3000
'data @124, 106 '3500
'data @125, 80 '4000
'data @126, 58 '4500
'data @127, 40 '5000
'data @128, 26 '5500
'data @129, 16 '6000
'data @130, 10 '6500
DEFINE LOADER_USED 1
DEFINE OSC 20
DEFINE SHIFT_PAUSEUS 50
define char_pacing 100
DEFINE DEBUG_REG PORTB 'Debug pin port
DEFINE DEBUG_BIT 5 'Debug output pin bit
DEFINE DEBUG_BAUD 9600 'Debug baud rate
DEFINE DEBUG_MODE 0 'Debug mode: 0 = True, 1 = Inverted
DEFINE DEBUG_PACING 500 'Debug character pacing in us
DEFINE DEBUGIN_REG PORTB 'Debugin pin port
DEFINE DEBUGIN_BIT 2 'Debugin pin bit
DEFINE DEBUGIN_MODE 0 'Debugin mode: 0 = True, 1 = Inverted
'''''''''''''''''''''''Hardware assignment '''''''''''''''''
Dlvry0 var PortA.0 'Solenoid driver Tank0 delivery
Dlvry1 var PortA.1 'Solenoid driver Tank1 delivery
SpareA2 var PortA.2
SpareA3 var PortA.3
SpareA4 var PortA.4
TRISA = %00000000 'all outputs.
PortA = %00000000
ANSEL = %00000000 'all ports digital
CMCON = %00000111 'comparators OFF
'PortB 'MUST have Weak PullUps ACTIVE for comms to/from '4620.
'WPU pulls Alert, Reply and DataIO high. These go low when active.
Reply var PortB.0 'p6 Idle INPUT. LOW to Acknowledge a poll.
DataIO var PortB.1 'p7 Idle INPUT. Bidirectional data exchange.
RxD var PortB.2 'p8 Boot or RS232 data IN. Idles HIGH
LED var PortB.3 'p9 activity LED
Alert var PortB.4 'p10 Idle INPUT. Pulled LOW by calling party.
TxD var PortB.5 'p11 Boot data or RS232 OUT
SpareB6 var PortB.6 'p12 unused - set as OUT
SpareB7 var PortB.7 'p13 unused - set as OUT
TRISB = %00011111
PortB = %00100000 'idle TxD high
OPTION_REG.7 = 0 'Enable WeakPullUps
'*********************** Variables *****************************
A var byte
B var byte
C var byte
D var byte
Delta var byte 'interpolation in LookDown table
ChkSum var byte 'The appemded CheckSum calculated by Mixer
LclChk var byte 'the locally calculated CheckSum
OT0 var byte[11] 'LookDown OnTime array entry for Tank 0
OT1 var byte[11] 'LookDown OnTime array entry for Tank 1
SolCalDone var bit '0 until calibration routine is run.
OnTime var word 'actual solenoid open time.
'Calculated as word then truncated to byte.
Pace var word 'time between each firing in mSecs
SoakFlag var bit '0 when in normal delivery, 1 in Soak
SoakCtr var word '10 mSec increments from 0 to 10 minutes
SoakTime var byte 'in minutes
Tank var byte '0 or 1
TankPress var word 'Measured value supplied by Mixer
EstPress var word 'Estimated pressure in the active tank.
PressDec con 30 'target pressure decrement per pulse = 30 mB
TestP var word '500, 1000,2000,3500 mB etc targets
LastP var word
Ident var byte 'Identifier shows what MsgType is coming in.
TimeOut var word
Burps var word ' the number of times gas has been released
W var word
X var word
Y var word
Z var word
AA var byte
'********************** Subroutines ****************************
goto endsubs
'any subroutines go here
EndSubs: '******************* End Subs **********************
Initialise: '****************** Initialise *********************
TRISA = %00000000 'all outputs.
PortA = %00100000 'MCLR an input
ANSEL = %00000000 'all ports digital
CMCON = %00000111 'comparators OFF
TRISB = %00010111 '
PortB = %00110111 'idle TxD high
OPTION_REG.7 = 0 'Enable WeakPullUps
low dlvry0 : low dlvry1 : input reply : input alert : input dataio
low led : timeout = 0 : ident = 8 : ontime = 0 : burps = 0
testp = 0 : lastp = 0 : estpress = 6250 : soakflaG = 0
'
Main: '********************** MAIN *******************************
TRISA = %00000000 'all outputs.
PortA = %00100000 'MCLR an input
ANSEL = %00000000 'all ports digital
CMCON = %00000111 'comparators OFF
TRISB = %00010111 '
PortB = %00110111 'idle TxD high
OPTION_REG.7 = 0 'Enable WeakPullUps
low dlvry0 : low dlvry1
input reply : input alert : input dataio
pace = 1000 'the time between each burp
'************************** FlowToChamber **************************
FlowToChamber:
'
' The working pressure range is from 1500 mBar to 6500 mBar. This is
' broken into 500 mBar bands and the solenoid OnTime necessary to
' get a 20 mBar pressure drop for each end of these bands is stored.
' Linear interpolation is used within each pressure band. The table
' MUST be monotonic with the time taken to deliver the gas pulse
' increasing as the pressure falls.
if (ident = 2) and (alert = 1) then
high led
if estpress > 6499 then estpress = 6499
if estpress < 1520 then estpress = 1520 'keep index always > 0
'Explanation of the LookDown Table logic
'Returns 'A' between 0 and 10 for TankPress between 1501 and
'6499 mBar.
'A table, starting at EEROM 100 for OT0, has byte entries in mSec.
'OnTimes range from 8 to 255 mS and are unique to the delivery
'valves and tank restrictors. Values below 10 pushed up to 10.
'A is the index to find the solenoid opening time for that
'pressure band. A is zero if T0Pressure < 1500.
' For example A = 6 if T0Pressure >= 4000 but < 4500
'To compute Dlvry0 OnTime we need the times from A and A-1
'Worked example
' suppose T0Pressure = 3345 mBar.
' A will be 4 because T0Pressure is < 3500.
' The OnTime at location 400 + A (i.e. C) is for 3500 mBar,
' say 55.
' The OnTime at location 400 + (A-1) (i.e. B) relates to 3000,
' say 75
'Delta =(OnTime at lower pressure)-(OnTime at higher pressure)
'Delta = 75 - 55 = 20 in this example
'
'Find the lower pressure OnTime.
'Assume W = T0Pressure = 3450 mB
'lookdown2 tankpress, <[1500, 2000, 2500, 3000, 3500, 4000, _
' 4500, 5000, 5500, 6000, 6500], a
if tank = 0 then
lookdown2 estpress, <[1500, 2000, 2500, 3000, 3500, 4000, _
4500, 5000, 5500, 6000, 6500], A
read (100 + A) ,b 'this is the higher pressure = shorter
read (100 + a - 1), c 'lower pressure = longer open time
delta = (c - b)
'OnTime = time at higher pressure plus a proportion
'of the delta.
x = estpress//500 '= 450 if T0Pressure was 3450 0<X<500
ontime = b + ((delta * (500 - x) + 250)/500)
if ontime > 255 then ontime = 255
endif 'Tank = 0 case
if tank = 1 then
lookdown2 estpress, <[1500, 2000, 2500, 3000, 3500, 4000, _
4500, 5000, 5500, 6000, 6500], a
read (120 + A), b 'the ontime at the upper pressure point
read (120 + a - 1), c 'ontime at the lower pressure
delta = (c - b)
x = estpress//500 'eg = 450 if T0Pressure was 3450 0<X<13
ontime = b + (((delta * (500 - x))+250)/500)
if ontime > 255 then ontime = 255 'OnTime here is a WORD
endif 'Tank = 1 case
endif 'Ident = 2 AND Alert = 1 case
DriveValve:
if (ident = 2) and (alert = 1) then
timeout = timeout + 1 : pause 1
if timeout > (pace - ontime) then 'fire solenoid
if tank = 0 then
high dlvry0 : pause ontime : low dlvry0
endif
if tank = 1 then
high dlvry1 : pause ontime : low dlvry1
endif
'Keep a local estimate of the declining TankPress
'correct this when new data from the GasMix module arrives.
estpress = estpress - pressdec
'PressDec is the target Pdrop per pulse = 20 mBar.
if estpress < 1540 then estpress = 1540
'EstPress gets updated whenever new pressure info comes in
debug "Burps ", # burps, ", T ", # tank, ", ActP ",_
# tankpress, ", EstP ", # estpress, ", On ", # ontime, _
", SkFlg ", # soakflag, ", SkTm ", # soaktime, 13, 10
timeout = 0 : burps = burps + 1
endif ' Timeout passed
endif 'Ident = 2 AND Alert = 1 case
low led
goto main
end
/endcode
Bookmarks