Code:
'******************************************************************************
'MR.SNEEZY - test code for FrSky using Bosch BMP085 baro sensor.
'This version is for PIC 18F4620
'
'PIC 18F4620 port/pin alocations
'-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
'PortA.0/Pin 2 = Serial TX
'PortA.1/Pin 3 = LED
'PortB.0/Pin 33 = I2C SCL clock
'PortB.1/Pin 34 = I2C SDA data
'Config Directive settings for MPASM (fuses) for 18F4620
@ __CONFIG _CONFIG1H, _IESO_OFF_1H & _FCMEN_OFF_1H & _OSC_INTIO7_1H
@ __CONFIG _CONFIG2L, _PWRT_ON_2L & _BOREN_OFF_2L
@ __CONFIG _CONFIG2H, _WDT_OFF_2H & _WDTPS_512_2H
@ __CONFIG _CONFIG3H, _MCLRE_OFF_3H & _PBADEN_OFF_3H
@ __CONFIG _CONFIG4L, _DEBUG_OFF_4L & _LVP_OFF_4L & _STVREN_OFF_4L & _XINST_OFF_4L
@ __CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L
@ __CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H
@ __CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L
@ __CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H
@ __CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L
@ __CONFIG _CONFIG7H, _EBTRB_OFF_7H
'Registers
ADCON1 = 001111 'Turn off all AD's
OSCCON = 110111 'set INTRC to 8 MHZ
DEFINE OSC 8 '8Mhz clock used.
' SO_pinftware Defines (variables and pins)
Cal_table VAR WORD[11] '11 word array to store calibration data
lUpres VAR LONG 'Uncompensated Pressure
lPres VAR LONG 'Compensated Pressure
DataA VAR LONG 'or WORD - as needed
ArraySize CON 16
RawData VAR LONG[ArraySize] 'or WORD - as needed
X1 VAR LONG
X01 VAR LONG
X2 VAR LONG
X3 VAR LONG
B3 VAR LONG
B4 VAR LONG
B5 VAR LONG
B6 VAR LONG
B7 VAR LONG
lAC1 VAR LONG 'cal values actually negative in my sensor
lAC2 VAR LONG 'These are 'cast' from the Word vars into Long vars in code below
lAC3 VAR LONG
lAC4 VAR LONG
lMB VAR LONG
lMC VAR LONG
bTemp_Var1 VAR BYTE 'temp variable
wTemp_Var1 VAR WORD 'temp variable
wTemp_Var2 VAR WORD 'temp variable
lUTemp VAR LONG 'Uncompensated temperature reading from sensor
lCTemp VAR LONG 'Compensated (real) temperature x10 (1/10th of C) from sensor
lTemp_Var1 VAR LONG
lTemp_Var2 VAR LONG
lTemp_Var3 VAR LONG
Tempo1 VAR LONG
Tempo2 VAR LONG
Tempo3 VAR LONG
I2C_Reg VAR BYTE 'target i2c register address
Counter VAR WORD 'loop counter to show on display
Counter = 0
S_Bd_Rate VAR WORD
S_Bd_Rate = 84 '9600DTN
LF CON 10 'Line Feed (for use with Serial Terminal like Hyperterminal)
CR CON 13 'Carriage Return (for use with Serial Terminal like Hyperterminal)
OSS_Res CON $3 'Over Sampling Setting for the BMP085
OSS_Time CON 30 'in ms for OSS_Res 0 = 10ms, ..., 3 = 25ms (see BMP085 datasheet)
I2C_SCL VAR PortB.0 'I2C clock pin
I2C_SDA VAR PortB.1 'I2C data pin
S_TX VAR PortA.0 'Serial Tx) out pin
LED VAR PortA.1 'Indicator LED, via 500ohm to +3.3V
'Aliases for calibration data in the senS_TXr to match the Bosch parameter list names
AC1 VAR Cal_table[0] '
AC2 VAR Cal_table[1] 'BMP085 has 11 16bit values stored in EEPROM
AC3 VAR Cal_table[2] 'First byte is at $AA last at $BF, two bytes per cal value
AC4 VAR Cal_table[3] 'Lowbyte is MSB (e.g $AA), Highbyte is LSB (e.g. $AB)
AC5 VAR Cal_table[4] '
AC6 VAR Cal_table[5]
B1 VAR Cal_table[6] 'Warning - AC4, AC5, AC6 are UNSIGNED values, the rest are SIGNED
B2 VAR Cal_table[7]
MB VAR Cal_table[8]
MC VAR Cal_table[9]
MD VAR Cal_table[10]
I2C_Reg =$AA 'Start address of the BMP085 calibration data
I2CREAD I2C_SDA,I2C_SCL,$EF,I2C_Reg,[STR Cal_table\11],Cal_error 'Read 11 reversed words out of sensor
AC1 = (AC1.LOWBYTE<<8) + AC1.HIGHBYTE 'swap MSB and LSB of each to use in PBP (un-reverse then)
AC2 = (AC2.LOWBYTE<<8) + AC2.HIGHBYTE 'device stores the MSB in the Low byte, LSB in the High byte
AC3 = (AC3.LOWBYTE<<8) + AC3.HIGHBYTE
AC4 = (AC4.LOWBYTE<<8) + AC4.HIGHBYTE
AC5 = (AC5.LOWBYTE<<8) + AC5.HIGHBYTE
AC6 = (AC6.LOWBYTE<<8) + AC6.HIGHBYTE
B1 = (B1.LOWBYTE<<8) + B1.HIGHBYTE
B2 = (B2.LOWBYTE<<8) + B2.HIGHBYTE
MB = (MB.LOWBYTE<<8) + MB.HIGHBYTE
MC = (MC.LOWBYTE<<8) + MC.HIGHBYTE
MD = (MD.LOWBYTE<<8) + MD.HIGHBYTE
'Cast (convert) signed PBP Word vars to signed PBP Long vars where needed by math routines below
lAC1 = AC1 'copy word to long
IF AC1.15 THEN lAC1.HIGHWORD = $FFFF 'Check for negative, set top 16bits to all 1's if true
lAC2 = AC2 'copy word to long
IF AC2.15 THEN lAC2.HIGHWORD = $FFFF 'Check for negative, set top 16bits to all 1's if true
lAC3 = AC3 'copy word to long
IF AC3.15 THEN lAC3.HIGHWORD = $FFFF 'Check for negative, set top 16bits to all 1's if true
lMB = MB 'copy word to long
IF MB.15 THEN lMB.HIGHWORD = $FFFF 'Check for negative, set top 16bits to all 1's if true
lMC = MC 'copy word to long
IF MC.15 THEN lMC.HIGHWORD = $FFFF 'Check for negative, set top 16bits to all 1's if true
'Cast (convert) UN-signed PBP Word var to UN-signed PBP Long var for math routines below
lAC4 = AC4 'copy word to long, both unsigned
'Main loop
'-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
MAIN:
'Get Temp via I2C
I2C_Reg = $F4 '$F4 is the control register address
I2CWRITE I2C_SDA,I2C_SCL,$EE,I2C_Reg,[$2E] 'Write $2E to set temperature conversion
PAUSE 10 'Delay 10ms after each write
I2C_Reg = $F6 '$F6 is the result register MSB
I2CREAD I2C_SDA,I2C_SCL,$EF,I2C_Reg,[wTemp_Var1],I2C_error'Read temperature MSB, LSB.
lUTemp = wTemp_Var1 'copy word to long. Note BMP085 UT is NOT a signed value
'Calculate temperature in 1/10ths of Deg °C from lUTemp ' Note 2^15 = 32768 Dec or $8000
X1 = ((lUTemp - AC6) * AC5) / $8000 'Find X1.
X2 = (lMC * $800) / (X1 + MD) 'Find X2. Note:- math rounding results in X2 being in error by 1 ?
B5 = X1 + X2 'Find B5 from X1 and X2.
lCTemp = (B5 + 8) / 16 'Hey presto, lCTemp appears...
'Assign true temperature in °C in "x.x" format
X1 = lCTemp / 10 'find value above decimal point
X01 = lCTemp // 10 'Find decimal value
'Take 16 measures from the BMP085
lTemp_Var1 = 0 'Clear the last pressure reading
FOR bTemp_Var1 = 0 TO 15 'Start of 16x averaging routine
I2C_Reg = $F4 '$F4 is the control register address
I2CWRITE I2C_SDA,I2C_SCL,$EE,I2C_Reg,[$F4] 'Write $34+(oss << 6) to set pressure conversion
PAUSE OSS_Time 'Delay 10ms after each write (30mS for HiRes results (oss=3))
I2C_Reg = $F6 '$F6 is the result register MSB
I2CREAD I2C_SDA,I2C_SCL,$EF,I2C_Reg,[lUpres],I2C_error 'Read pressure MSB, LSB, XLSB, $F9 ($F9 not actually wanted).
lUpres = lUpres >> (16 - OSS_Res) 'remove $F9 from result (>>8), and left shift result back to 16 to 19 Bits (OSS value dependant)
lTemp_Var1 = lTemp_Var1 + lUpres
RawData(bTemp_Var1) = lUpres 'fill-up array for sorting & averaging
NEXT bTemp_Var1
lUpres = lTemp_Var1 / 16 'finish of the 10x Averaging routine
'Melanie's "sorting number" algorythm - ordonate data
bTemp_Var1 = 0
SortLoop:
IF RawData(bTemp_Var1 + 1) < RawData(bTemp_Var1) THEN
DataA = RawData(bTemp_Var1)
RawData(bTemp_Var1) = RawData(bTemp_Var1 + 1)
RawData(bTemp_Var1 + 1) = DataA
IF bTemp_Var1 > 0 THEN bTemp_Var1 = bTemp_Var1-2
ENDIF
bTemp_Var1 = bTemp_Var1 + 1
IF bTemp_Var1 < (ArraySize -1) THEN GOTO SortLoop
'display data array
'for bTemp_Var1 = 0 to (ArraySize -1)
' Serout2 S_TX,S_Bd_Rate,[dec2 bTemp_Var1, " ", dec rawdata(bTemp_Var1),LF]
'next
'**** Additional SAMPLING METHODS ****
'keep the eight middle values and average them
lTemp_Var2 = 0
FOR bTemp_Var1 = 4 TO 11
lTemp_Var2 = lTemp_Var2 + RawData(bTemp_Var1)
NEXT bTemp_Var1
lTemp_Var2 = lTemp_Var2 / 8
'keep Bottom 4 (B4) and top 4 (T4) and average them
lTemp_Var3 = 0
FOR bTemp_Var1 = 0 TO 3
lTemp_Var3 = lTemp_Var3 + RawData(bTemp_Var1)
NEXT bTemp_Var1
FOR bTemp_Var1 = 12 TO 15
lTemp_Var3 = lTemp_Var3 + RawData(bTemp_Var1)
NEXT bTemp_Var1
lTemp_Var3 = lTemp_Var3 / 8
'find the differences with the previous values
IF lUpres > Tempo1 THEN
Tempo1 = lUpres - Tempo1
ELSE
Tempo1 = Tempo1 - lUpres
ENDIF
IF lTemp_Var2 > Tempo2 THEN
Tempo2 = lTemp_Var2 - Tempo2
ELSE
Tempo2 = Tempo2 - lTemp_Var2
ENDIF
IF lTemp_Var3 > Tempo3 THEN
Tempo3 = lTemp_Var3 - Tempo3
ELSE
Tempo3 = Tempo3 - lTemp_Var3
ENDIF
'Display all data
SEROUT2 S_TX,S_Bd_Rate,["16/16 = ",DEC lUpres," Diff = ",DEC Tempo1, LF]
SEROUT2 S_TX,S_Bd_Rate,["Mid8/16 = ",DEC lTemp_Var2," Diff = ",DEC Tempo2, LF]
SEROUT2 S_TX,S_Bd_Rate,["B4+T4/16 = ",DEC lTemp_Var3," Diff = ",DEC Tempo3, LF]
SEROUT2 S_TX,S_Bd_Rate,["Temp = ",DEC X1,".",DEC X01,"°C",LF]
SEROUT2 S_TX,S_Bd_Rate,["Counter = ",DEC Counter,LF,CR]
PAUSE 1000
Tempo1 = lUpres
Tempo2 = lTemp_Var2
Tempo3 = lTemp_Var3
Counter = Counter + 1
TOGGLE LED 'flash the 'im alive' LED
GOTO MAIN
'Trap and display I2C problems
I2C_error:
SEROUT2 S_TX,S_Bd_Rate,["i2c bus read error",LF,CR]
PAUSE 2000
TOGGLE LED
GOTO MAIN:
Cal_error:
SEROUT2 S_TX,S_Bd_Rate,["i2c cal read error ",LF,CR]
PAUSE 2000
TOGGLE LED
GOTO MAIN:
END
Bookmarks