Attached to this article is a .zip file with PBP code that is able to do these calculations. It is setup to use SPI and for simplicity it uses the good old SHIFTOUT/SHIFTIN commands but for those inclined it should be easy enough to change to hardware SPI or I2C.
In order to use it you must have LONGs enabled and therefor you must use an 18F device. The code weighs in at around 6.5kB and uses 107 bytes of RAM. Running the compensation routines for all three values takes aproximately 2.2ms at 64MHz which equates to 35200 instruction cycles.
This is sort of a bare bones example of how to use it:
Code:
'********************************************************************
'* Name : BME280-Demo.pbp *
'* Author : Henrik Olsson *
'* Notice : Copyright (c) 2020 Henrik Olsson *
'* : All Rights Reserved *
'* Date : 2020-10-13 *
'* Version : 1.0 *
'* Notes : This program shows how to use the BME280.pbp include *
'* : file to read (via SPI) and display values from the *
'* : BME280 sensor. *
'********************************************************************
' [1] As always you need to configure and setup your particular device.
' I'm doing that in a separate file for my particular development board.
INCLUDE "HWConfig.pbp"
' [2] The BME280.pbp file expects aliases for the following:
BME280_CS VAR LATH.2 ' Chip select (output)
BME280_CLK VAR PORTC.3 ' Clock pin (output)
BME280_MISO VAR PORTC.4 ' PIC Data In (input)
BME280_MOSI VAR PORTC.5 ' PIC Data Out (output)
' [3] Then we're ready to include the BME280.pbp file.
INCLUDE "BME280.pbp"
' [4] Configure the BME280 sensor.
' See section 5.4.3 in the datasheet.
BME280_Reg = $F2 ' Control humidity register
BME280_Data = %00000011 ' 4x oversampling for humidity
GOSUB BME280_Write
' See section 5.4.5 in the datasheet
BME280_Reg = $F4 ' Control register
BME280_Data = %01101111 ' 4x oversampling for temp and pressure, normal mode
GOSUB BME280_Write
' See section 5.4.6 in the datasheet
BME280_Reg = $F5 ' Config register
BME280_Data = %11101000 ' 20ms standby time, IIR coefficient 4, 4 wire SPI
GOSUB BME280_Write
' Read in all the compensation/calibration coefficients from the sensor.
GOSUB BME280_GetTrimValues
'---------------------------------------------------------------------------------
Main:
GOSUB BME280_GetRawValues
GOSUB BME280_CompensateValues
' At this point variables Temperature, Pressure and Humidity contains the properly compensated
' values and can, for example, be displayed as follows.
HSEROUT2[SDEC Temperature/100,".", DEC Temperature//100, "°C ", DEC Pressure/100, ".",_
DEC Pressure//100, "hPa ", DEC Humidity/1000, ".", DEC Humidity //1000, "%RH",13]
PAUSE 1000
Goto Main
Running the above code produces output like this:
The results of the PBP code has been compared to that of floating point code running on PC hardware and were found to be pretty accurate, here are a couple of datapoints:
Code:
' adc_T = 530386, adc_P = 345501, adc_h = 28680 ' Results of Pyhton code Results of PBP code ' t_Fine: 122508.9573 122505 ' Temperature: 23.9275 23.93 ' Pressure: 1011.1778 1011.20 ' Humidity: 46.3329 47.44 ' ' adc_t = 410521, adc_p = 290230, adc_h = 22123 ' Results of Pyhton code Results of PBP code ' t_Fine: -72370.21 -72372 ' Temperature: -14.13 -14.13 ' Pressure: 1038.4243 1041.76 ' Humidity: 11.819 12.10 ' ' adc_t = 380734 : adc_p = 414855 : adc_h = 32123 ' Results of Pyhton code Results of PBP code ' t_Fine: -120785.60 -120795 ' Temperature: -23.59 -23.58 ' Pressure: 828.2755 832.29 ' Humidity: 62.244 63.73
There's a forum thread where some details pertaining to this development was discussed. I suggest any questions, comments, suggestions, bug reports and so on is kept in that thread.
If you don't want to download a .zip file or if you're just curious, here's the code in the BME280.pbp file:
Code:
'****************************************************************************
'* Name : BME280.pbp *
'* Author : Henrik Olsson *
'* Notice : Copyright (c) 2020 Henrik Olsson *
'* : All Rights Reserved *
'* Date : 2020-10-13 *
'* Version : 1.0 *
'* Notes : This is an include file containing routines to read (via SPI) *
'* temperature, pressure and humidity from the BME280 Digital *
'* humidity, pressure and temperature sensor from BOSCH. *
'* *
'* : Uses 107 bytes of RAM and roughly 6.5kB of FLASH. *
'* *
'* History: v1.0 - 2020-10-13 *
'* Initial version *
'****************************************************************************
' Code expects some aliases to be defined BEFORE including this file, namely:
' BME280_CS VAR LATH.2
' BME280_CLK VAR PORTC.3
' BME280_MISO VAR PORTC.4
' BME280_MOSI VAR PORTC.5
'
' Then you can include this file:
' INCLUDE "BME280.pbp"
adc_T VAR LONG ' Raw temperature value as read from sensor.
adc_P VAR LONG ' Raw pressure value as read from sensor.
adc_H VAR WORD ' Raw humidity value as read from sensor.
Temperature VAR LONG ' Final temperature value in units of 0.01 degrees C.
Pressure VAR LONG ' Final pressure value in units of 1Pa.
Humidity VAR LONG ' Final humidity value in units of 0.001%.
' Compensation / trimming parameters to be read from the BME280.
' Datatypes listed as comments are how they are defined in the datasheet.
dig_T1 VAR WORD ' Unsigned short
dig_T2 VAR LONG ' Signed short, we cast to LONG when read.
dig_T3 VAR LONG ' Signed short, we cast to LONG when read.
dig_P1 VAR WORD ' Unsigned short.
dig_P2 VAR LONG ' Signed short, we cast to LONG when read.
dig_P3 VAR LONG ' Signed short, we cast to LONG when read.
dig_P4 VAR LONG ' Signed short, we cast to LONG when read.
dig_P5 VAR LONG ' Signed short, we cast to LONG when read.
dig_P6 VAR LONG ' Signed short, we cast to LONG when read.
dig_P7 VAR LONG ' Signed short, we cast to LONG when read.
dig_P8 VAR LONG ' Signed short, we cast to LONG when read.
dig_P9 VAR LONG ' Signed short, we cast to LONG when read.
dig_H1 VAR BYTE ' Unsigned char.
dig_H2 VAR LONG ' Signed short, we cast to LONG when read.
dig_H3 VAR BYTE ' Unsigned char.
dig_H4 VAR WORD ' Signed short, we cast to LONG when read.
dig_H5 VAR WORD ' Signed short, we cast to LONG when read.
dig_H6 VAR LONG ' Signed char, we cast to LONG when read.
' These variables are used in all three compensation routines and needs to be included all the time.
var1 VAR LONG
var2 VAR LONG
' These are not needed if humidity is not going to be used.
var3 VAR LONG
var4 VAR LONG
var5 VAR LONG
' This is used in all three compensation routines
t_fine VAR LONG
BME280_Reg VAR BYTE
BME280_Data VAR BYTE
tmp_B VAR BYTE ' Temporary variable.
' Actual code below this point, jump over as to not execute unless specifically called.
GOTO OverBME280
'----------------------------------------------------------------------------------------------------------------------
BME280_Read:
' Basic read function.
' Set BME280_Reg to whatever address you want to read.
' Data at that address will be returned in BME280_Data
BME280_Reg.7 = 0
BME280_CS = 0
SHIFTOUT BME280_MOSI, BME280_CLK, 5, [128 + BME280_Reg]
SHIFTIN BME280_MISO, BME280_CLK, 6, [BME280_Data]
BME280_CS = 1
RETURN
'----------------------------------------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------------------------------------
BME280_Write:
' Basic write function.
' Set BME280_Reg to whatever address you want to write and
' BME280_Data to whatever value you want to write to that address.
BME280_REg.7 = 0
BME280_CS = 0
SHIFTOUT BME280_MOSI, BME280_CLK, 5, [BME280_Reg, BME280_Data]
BME280_CS = 1
RETURN
'----------------------------------------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------------------------------------
BME280_Reset:
' This will perform a reset of the device, same as power on (according to datasheet).
BME280_Reg = $E0
BME280_Data = $B6
GOSUB BME280_Write
RETURN
'----------------------------------------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------------------------------------
BME280_CompensateValues:
' The execution time for compensating all three values are measured
' to around 2190us with the PIC running at 64MHz
'------------------------------------------------------------------
' Optimized Temperature conversion, verified to work with negative temperatures
' Execution time at 64MHz is around 300us
'------------------------------------------------------------------
var1 = (((adc_T >> 3) - (dig_T1 << 1)) * dig_T2) / 2048
var2 = (((( (adc_T >> 4) - dig_T1) * ((adc_T >> 4) - dig_T1)) / 4096) * dig_T3) / 16384
t_fine = var1 + var2
Temperature = (t_fine * 5 + 128) / 256
'------------------------------------------------------------------
'------------ Pressure compensation, working version --------------
'------------------------------------------------------------------
' Execution time at 64MHz is around 1230us
var1 = (t_fine / 2) - 64000
var2 = (((var1 / 4) * (var1 / 4)) / 2048) * dig_P6
var2 = var2 + (var1 * dig_P5 * 2)
var2 = (var2 / 4) + (dig_P4 * 65536)
var1 =((dig_P3 * ((var1 / 4) * var1 / 4) / 8192) / 8) + ((dig_P2 * var1) / 2)
var1 = var1 / 262144
var1 = ((32768 + var1) * dig_P1) / 32768
IF var1 = 0 THEN
Pressure = 0
RETURN
ENDIF
Pressure = ABS((1048576 - adc_P) - (var2 / 4096)) * 3125
IF Pressure < $80000000 THEN
Pressure = (Pressure / 2) / (ABS(var1))
ELSE
Pressure = (Pressure / ABS(var1)) * 2
ENDIF
var1 = (dig_P9 * ( (Pressure >> 3) * (Pressure >> 3) / 8192)) / 4096
var2 = ((Pressure >> 2) * dig_P8) / 8192
Pressure = Pressure + ((var1 + var2 + dig_P7) / 16)
'------------------------------------------------------------------
'----------- Humidity compensation, working version ---------------
'------------------------------------------------------------------
' Execution time at 64MHz is around 660us
var1 = t_fine - 76800
var2 = adc_H << 14 ' adc_H is unsigned so we can use left shift instead of dived here
var3 = dig_H4 * 1048576
var4 = dig_H5 * var1
var5 = (((var2 - var3) - var4) + 16384) / 32768
var2 = (var1 * dig_H6) / 1024
var3 = (var1 * dig_H3) / 2048
var4 = ((var2 * (var3 + 32768)) / 1024) + 2097152
var2 = ((var4 * dig_H2) + 8192) / 16384
var3 = var5 * var2
var4 = ((var3 / 32768) * (var3 / 32768)) / 128
var5 = var3 - ((var4 * dig_H1) / 16)
IF Var5 < 0 THEN
var5 = 0
ENDIF
IF var5 > 419430400 THEN
var5 = 419430400
ENDIF
Humidity = var5 >> 12
IF Humidity > 102400 THEN
Humidity = 102400
ENDIF
RETURN
'----------------------------------------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------------------------------------
BME280_GetRawValues:
' Make sure we don't have any "residue" in the highest significant byte of the variables
' since we're only shifting in 24 bits. adc_H is 16bits and we're shifting in 16bits so
' no need for any special attention there.
adc_P.BYTE3 = 0
adc_T.BYTE3 = 0
BME280_Reg = $F7
BME280_Reg.7 = 0
BME280_CS = 0
SHIFTOUT BME280_MOSI, BME280_CLK, 5, [128 + BME280_Reg]
SHIFTIN BME280_MISO, BME280_CLK, 6, [adc_P.BYTE2, adc_P.BYTE1, adc_P.BYTE0, adc_T.BYTE2, adc_T.BYTE1, adc_T.BYTE0, adc_H.BYTE1, adc_H.BYTE0]
BME280_CS = 1
' Temperature and pressure are left justified, needs to be shifted right four places.
adc_P = adc_P >> 4
adc_T = adc_T >> 4
RETURN
'----------------------------------------------------------------------------------------------------------------------
'----------------------------------------------------------------------------------------------------------------------
BME280_GetTrimValues:
' This routines reads the trim/compensation constants from the sensor.
' For some reason there's a gap in the memory map, first group of data are between 0x88 and 0xA1 (with 0xA0 skipped).
' and second group is from 0xE1 and 0xE7 with digits H4 and H5 spanning three bytes
' Since these values never change for the specific sensor it would be possible to
' read these once and hardcode them into their respective variables, or even better in
' that case, change the variables to constants.
' Most values (but not all) are 16bit signed as they are read from the sensor.
' But PBP does not do signed arithmetic on 16bit variables so we're storing them in LONGs.
' But for that to work properly we need "move" the sign bit (if the value) is negative.
dig_T1 = 0 : dig_T2 = 0 : dig_T3 = 0
dig_P1 = 0 : dig_P2 = 0 : dig_P3 = 0
dig_P4 = 0 : dig_P5 = 0 : dig_P6 = 0
dig_P7 = 0 : dig_P8 = 0 : dig_P9 = 0
dig_H1 = 0 : dig_H2 = 0 : dig_H3 = 0
dig_H4 = 0 : dig_H5 = 0 : dig_H6 = 0
' Read 0x88 thru 0xA1. 0xA0 is not in use so dump that in tmp_B
BME280_Reg = $88
BME280_Reg.7 = 0
BME280_CS = 0
SHIFTOUT BME280_MOSI, BME280_CLK, 5, [128 + BME280_Reg]
SHIFTIN BME280_MISO, BME280_CLK, 6, [dig_T1.BYTE0, dig_T1.BYTE1, dig_T2.BYTE0, dig_T2.BYTE1, dig_T3.BYTE0, dig_T3.BYTE1,_
dig_P1.BYTE0, dig_P1.BYTE1, dig_P2.BYTE0, dig_P2.BYTE1, dig_P3.BYTE0, dig_P3.BYTE1,_
dig_P4.BYTE0, dig_P4.BYTE1, dig_P5.BYTE0, dig_P5.BYTE1, dig_P6.BYTE0, dig_P6.BYTE1,_
dig_P7.BYTE0, dig_P7.BYTE1, dig_P8.BYTE0, dig_P8.BYTE1, dig_P9.BYTE0, dig_P9.BYTE1,_
tmp_B, dig_H1]
IF dig_T2.15 = 1 THEN
dig_T2 = -ABS(dig_T2.LOWWORD)
ENDIF
IF dig_T3.15 = 1 THEN
dig_T3 = -ABS(dig_T3.LOWWORD)
ENDIF
IF dig_P2.15 = 1 THEN
dig_P2 = -ABS(dig_P2.LOWWORD)
ENDIF
IF dig_P3.15 = 1 THEN
dig_P3 = -ABS(dig_P3.LOWWORD)
ENDIF
IF dig_P4.15 = 1 THEN
dig_P4 = -ABS(dig_P4.LOWWORD)
ENDIF
IF dig_P5.15 = 1 THEN
dig_P5 = -ABS(dig_P5.LOWWORD)
ENDIF
IF dig_P6.15 = 1 THEN
dig_P6 = -ABS(dig_P6.LOWWORD)
ENDIF
IF dig_P7.15 = 1 THEN
dig_P7 = -ABS(dig_P7.LOWWORD)
ENDIF
IF dig_P8.15 = 1 THEN
dig_P8 = -ABS(dig_P8.LOWWORD)
ENDIF
IF dig_P9.15 = 1 THEN
dig_P9 = -ABS(dig_P9.LOWWORD)
ENDIF
BME280_CS = 1
BME280_Reg = $E1
BME280_Reg.7 = 0
BME280_CS = 0
SHIFTOUT BME280_MOSI, BME280_CLK, 5, [128 + BME280_Reg]
SHIFTIN BME280_MISO, BME280_CLK, 6, [dig_H2.BYTE0, dig_H2.BYTE1, dig_H3, dig_H4.BYTE0, tmp_B, dig_H5.BYTE0, dig_H6]
IF dig_H2.15 = 1 THEN
dig_H2 = -ABS(dig_H2.LOWWORD)
ENDIF
dig_H4 = dig_H4 << 4
dig_H5 = dig_H5 << 4 ' Make room for lower 4 bits
dig_H4 = dig_H4 + (tmp_B & %00001111) ' Extract lower 4 bits of dig_H4
tmp_B = tmp_B >> 4 ' Extract lower 4 bits of dig_H5
dig_H5 = dig_H5 + (tmp_B & %00001111)
BME280_CS = 1
RETURN
'***********************************************************************************************************************
'********* Optional debug code below this point. Will get included with #DEFINE BME280_DEBUG
'***********************************************************************************************************************
#IFDEF BME280_DEBUG
Testcase:
adc_T = 530386 : adc_P = 345501 : adc_h = 28680
GOSUB BME280_CompensateValues : GOSUB PrintValues
adc_T = 486770 : adc_P = 330198 : adc_h = 35867
GOSUB BME280_CompensateValues : GOSUB PrintValues
adc_t = 468750 : adc_p = 324532 : adc_h = 27951
GOSUB BME280_CompensateValues : GOSUB PrintValues
adc_t = 455100 : adc_p = 320161 : adc_h = 29389
GOSUB BME280_CompensateValues : GOSUB PrintValues
adc_t = 438939 : adc_p = 314970 : adc_h = 31164
GOSUB BME280_CompensateValues : GOSUB PrintValues
adc_t = 427235 : adc_p = 311954 : adc_h = 38152
GOSUB BME280_CompensateValues : GOSUB PrintValues
adc_t = 410521 : adc_p = 290230 : adc_h = 22123
GOSUB BME280_CompensateValues : GOSUB PrintValues
adc_t = 380734 : adc_p = 414855 : adc_h = 32123
GOSUB BME280_CompensateValues : GOSUB PrintValues
RETURN
PrintValues:
HSEROUT2[DEC i, ": ", "Temp: ", SDEC Temperature, " P: ", SDEC Pressure, " RH: " , DEC Humidity, " t_fine: ", SDEC t_fine, 13]
RETURN
PrintTrimValues:
HSEROUT2["dig_T1: ", DEC dig_T1, 13]
HSEROUT2["dig_T2: ", SDEC dig_T2, 13]
HSEROUT2["dig_T3: ", SDEC dig_T3, 13]
HSEROUT2["dig_P1: ", DEC dig_P1, 13]
HSEROUT2["dig_P2: ", SDEC dig_P2, 13]
HSEROUT2["dig_P3: ", SDEC dig_P3, 13]
HSEROUT2["dig_P4: ", SDEC dig_P4, 13]
HSEROUT2["dig_P5: ", SDEC dig_P5, 13]
HSEROUT2["dig_P6: ", SDEC dig_P6, 13]
HSEROUT2["dig_P7: ", SDEC dig_P7, 13]
HSEROUT2["dig_P8: ", SDEC dig_P8, 13]
HSEROUT2["dig_P9: ", SDEC dig_P9, 13]
HSEROUT2["dig_H1: ", DEC dig_H1, 13]
HSEROUT2["dig_H2: ", SDEC dig_H2, 13]
HSEROUT2["dig_H3: ", DEC dig_H3, 13]
HSEROUT2["dig_H4: ", SDEC dig_H4, 13]
HSEROUT2["dig_H5: ", SDEC dig_H5, 13]
HSEROUT2["dig_H6: ", SDEC dig_H6, 13]
RETURN
#ENDIF
OverBME280:


Menu

Re: serial LCD 1602 Backpack using PIC16F690 for Hitach HD44780
one last update:
jackberg1 Yesterday, 17:11added an PGM Sw on RA3
to edit the baud rate:
turn off the LCD display, press & hold the PGM sw, turn on the LCD
line 1 will show "Press to Select" , line 2 : "Baud Rate:"...