Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

BME280 sensor
Goto page 1, 2  Next
 
Post new topic   Reply to topic    www.mcselec.com Forum Index -> Share your working BASCOM-AVR code here
View previous topic :: View next topic  
Author Message
Mrshilov

Bascom LCD Guru



Joined: 24 Jan 2009
Posts: 314
Location: Russia

russia.gif
PostPosted: Tue Dec 15, 2015 1:41 pm    Post subject: BME280 sensor Reply with quote

BME280 is a combined digital humidity, pressure and temperature sensor. Attached library for I2C mode, but it can be easy adapted for SPI.
Back to top
View user's profile
aphawk

Bascom Member



Joined: 23 Jan 2010
Posts: 168
Location: Brazil

brazil.gif
PostPosted: Wed Dec 16, 2015 1:29 am    Post subject: Reply with quote

Mrshilov,

Thanks for the Lib. Is very nice have all this sensors in one unique module.

Paulo
Back to top
View user's profile
albertsm

Administrator



Joined: 09 Apr 2004
Posts: 5922
Location: Holland

blank.gif
PostPosted: Thu Dec 17, 2015 10:22 am    Post subject: Reply with quote

Hello Mrshilov,

thanks for sharing this project. I always like the fact that you include a PDF and a sample.
This looks like a super sensor. The LCD looks sharp and clear too.

_________________
Mark
Back to top
View user's profile Visit poster's website
O-Family

Bascom Expert



Joined: 23 May 2010
Posts: 320
Location: Japan

japan.gif
PostPosted: Thu Mar 16, 2017 11:15 am    Post subject: Reply with quote

Hi Mrshilov,

The procedure for converting formulas from your C language is wonderful!

please tell me.
Conversion of humidity coefficient is not wrong?
Register 0xE5 is 0xE5 [3: 0] and 0xE5 [7: 4].
Therefore, I think that there is no Temp [8].

Best regards
Code:
Temp(1) = &HA1                                              ' Read Humidity calibration
I2creceive Slave , Temp(1) , 1 , 1
H1 = Temp(1)
Temp(1) = &HE1
I2creceive Slave , Temp(1) , 1 , 8
H2 = Makeint(temp(1) , Temp(2))
H3 = Temp(3) : H4 = Temp(4) : Shift H4 , Left , 4
Temp(5) = Temp(5) And &H0F : H4 = H4 + Temp(5)
H5 = Temp(6) : Shift H5 , Left , 4
Temp(7) = Temp(7) And &H0F : H5 = H5 + Temp(7)
H6 = Temp(8)
Return
Back to top
View user's profile Visit poster's website
Mrshilov

Bascom LCD Guru



Joined: 24 Jan 2009
Posts: 314
Location: Russia

russia.gif
PostPosted: Thu Mar 16, 2017 1:40 pm    Post subject: Reply with quote

Yes, you are right - it's wrong. Also I find another error in hum procedure. In attachment corrected version & proteus model.
Back to top
View user's profile
O-Family

Bascom Expert



Joined: 23 May 2010
Posts: 320
Location: Japan

japan.gif
PostPosted: Fri Mar 17, 2017 11:35 am    Post subject: Reply with quote

Thanks for the fix!

There was a difference of 0.2% humidity with my routine, but it was consistent after the correction.
Because your routine is concise, I will adopt it as well.
Thank you for your effort!
Back to top
View user's profile Visit poster's website
Per Svensson

Bascom Member



Joined: 03 Oct 2004
Posts: 235
Location: Gothenburg, Sweden

sweden.gif
PostPosted: Thu May 14, 2020 11:12 am    Post subject: Reply with quote

Hi Mrshilov,

Thank you for this contribution.
Inspired by it, and also having a need for this sensor, I decided to make a floating point version of it and compare the results.
Attached you will find a test program and an include lib for Integer as well as Single
In my case, the interesting part is a very accurate air pressure resolution, as I will use it for measuring rock topografy variations.
Ideally it should , with aggressive filtering, be possible to discriminate down to 10cm or better.
As 1pascal is ~equivalent to 8cm at sea level I need fractions of 1 Pascal. Absolute accuracy is however not important so stability is key here.

To make a long story shorter. I took the datasheet formulas from Bosch and rewrote it to Bascom math.
I also wrote a short test program that is calling both float and integer compensation routines with the same data and calibration parameters to compare the outcomes.
So, Integer results basically comes from your code and FP-results from mine.
The data and calibration was extracted from the BME280 sensor I had handy.

Running the test:
RAWDATA: ADCp=310604.00 ADChum=30411.00 ADCt=535756.00

32bit FLOAT MATH --> P=104591.05 Pa, Hum=32.60 %, T=25.57'C
CPU Load: 14715 cycles = 919.69 us at 16 MHz


16bit INTEGER MATH --> P=100315 Pa, Hum=3259 %, T=2557'C
CPU Load: 8933 cycles = 558.31 us at 16 MHz

It can be seen that Humidity and Temperature agrees, but Pressure differ 1.5 Pascal.
Now, the question is. Is there an implementation mistake in on of the routines or is it just due to the higher accuracy in FP-math?
I really cannot tell, as there is no on line calculator from Bosch.
Perhaps there is someone in this forum who have another FP-implementation to run for comparison?
You can easily use my rawdata and calibration constants.
An excel sheet for the same thing would also be a good candidate...

/Per
Back to top
View user's profile Visit poster's website
Per Svensson

Bascom Member



Joined: 03 Oct 2004
Posts: 235
Location: Gothenburg, Sweden

sweden.gif
PostPosted: Thu May 14, 2020 12:32 pm    Post subject: Reply with quote

Sorry for the typing mistake.
Pressure discrepancy should read 43hPa. Not 1.5Pa
(104591.05 - 100315 ~43276 Pa)

/Per
Back to top
View user's profile Visit poster's website
Per Svensson

Bascom Member



Joined: 03 Oct 2004
Posts: 235
Location: Gothenburg, Sweden

sweden.gif
PostPosted: Thu May 14, 2020 2:06 pm    Post subject: Reply with quote

Ok, so I made this Excel calculations as well, and here are the results:
(Attached the excel sheet)

RAWDATA: ADCp=310604.00 ADChum=30411.00 ADCt=535756.00 (as before)


EXCEL MATH --> P=100309.36 Pa, Hum=32.60 %, T=25.57'C

32bit FLOAT BASCOM MATH --> P=104591.05 Pa, Hum=32.60 %, T=25.57'C

16bit INTEGER BASCOM MATH --> P=100315 Pa, Hum=3259 %, T=2557'C

The conclusion is that the integer math is correct (although rougher that Excel)
My bascom version has a bug somewhere. I have to find it.
Stay tuned...

/Per
Back to top
View user's profile Visit poster's website
O-Family

Bascom Expert



Joined: 23 May 2010
Posts: 320
Location: Japan

japan.gif
PostPosted: Fri May 15, 2020 3:53 am    Post subject: Reply with quote

The BME280 program created by Mrshilov and the measurement results of different pressure sensors [LPS331AP], [LPS25H], [MPL115A2], [MPL115A1] were also within the difference of 2hPa-10hPa.

The BME280 is a compound sensor, so I think it's not very accurate.

In addition, moving averages are important because minute air pressure values change with wind and the degree to which doors are opened and closed.
Although it does not provide sufficient accuracy, it can capture changes in height difference of about 10cm.
https://www.youtube.com/watch?v=LBJcptDYFUk&feature=youtu.be

http://translate.google.com/translate?hl=ja&sl=ja&tl=en&u=http%3A%2F%2Fwww.ne.jp%2Fasahi%2Fshared%2Fo-family%2FElecRoom%2FAVRMCOM%2FBME280%2FBME280_SK2.html&sandbox=1
http://www.ne.jp/asahi/shared/o-family/ElecRoom/AVRMCOM/BME280/BME280_SK2.html
Back to top
View user's profile Visit poster's website
Per Svensson

Bascom Member



Joined: 03 Oct 2004
Posts: 235
Location: Gothenburg, Sweden

sweden.gif
PostPosted: Sun May 17, 2020 11:33 am    Post subject: Reply with quote

I rewrote the floating point for 64 bit double instead of 32 bit single.
The 32 bot code was not performing better that the integer code, even after finding the bug.

The results with double precision math is nearly as accurate as of Excel as you can see here below, but of course much
slower than using integer math. About three times.

RAWDATA: ADCp=310604.00 ADChum=30411.00 ADCt=535756.00 (as before)


EXCEL MATH --> P=100314,1123 Pa, Hum=32.60 %, T=25.57'C

BASCOM: 64bit FLOAT MATH --> P=100314.11 Pa, Hum=32.60 %, T=25.57'C
CPU Load: 28820 cycles = 1801.25 us at 16 MHz

BASCOM: 16bit INTEGER MATH --> P=100315 Pa, Hum=3259 %, T=2557'C
CPU Load: 8933 cycles = 558.31 us at 16 MHz

Now, the next step is to do a lot of sampling over an extended time in controlled atmosphere (Pressure and/or Temp),
and run statistics on it to see if the high floating point accuracy is worth the price. It might be that Bosch's calibration parameters are
less useful after soldering and aging. Heavy averaging of data is meaningless if the linearization of the raw data does not work
and proves to be in excess of random sensor noise.

Stay tuned...
Back to top
View user's profile Visit poster's website
Per Svensson

Bascom Member



Joined: 03 Oct 2004
Posts: 235
Location: Gothenburg, Sweden

sweden.gif
PostPosted: Thu May 21, 2020 11:07 pm    Post subject: Reply with quote

Here is an update of the Bascom code for correction of data from BME280 and the companion Excel sheet.

I also made a series of data sampling for 5 hours at 1Hz.
There are five reports from this run (Pdf's)
- Raw Pressure data from the BME280 adc.
- Compensated pressure data using 32bit integer math
- Compensated pressure data using FP64 double math
- Compensated Temperature using FP32 (single) math
- Compensated Humidity data using FP32 single math

Each file contains statistics like plots of values versus time and spectrum density.
Most interesting is the Allan Variance plot of the 64 bit floating point data.
It shows 0.2-0.6 Pascal short time stability (Standard deviation) (for variance taken in the interval up to ten seconds.
then for longer times stability seem rather poor…. Or is it?
It is not easy to distinguish real atmospheric pressure variations from inherent sensor drift (Random walk)...

To further get a clue if the temperature correction really works as intended I made a test (data not included here) where sensor temperatur was ramped up from 25 degrees to 36, and then back again. I used 4 hours sampling at 1 Hz. The result clearly shows that the raw pressure data closely follows the temperature curve, whilst the
compensated curve shows no obvious correlation to temperature. This indicates that the compensation math does a pretty good job.
Furthermore, the pressure curve follows rather well the pressure curves from the Swedish Metereological Institute for the time at hand.

My conclusion is that the BME280 sensor can be used for resolving atmospheric pressure variations around 0.5-1 Pascal which correspond to 4-8cm of altitude change.
The real challenge, using the device for altitude measurements, is not the resolution or accuracy of the sensor as such . The challenge is to reject the natural air pressure variations, also for rather short time periods. The pressure can sometimes vary 100 pascals over one hour. which is 8m error (!)
The only remedy is to set up a reference sensor at a known altitude and take the difference between this and the "rover", to noll out the weather factor.
Alternatively, to keep contact with another reference station over radio or internet and use that for "weather compensation".

Observe though, that heavy lowpass filtering by averaging (running-average) is mandatory to get good noise performance for this particular task, where speed is of no interest.
In my real application I have set up the sensor for maximum filtering, and also used som additional running average to supress noise. But this is not shown in the test file in the zip.

Another conclusion is that unless you need lowest possible noise, the 32bit integer compensation math, originally coded by Mrshilov will serve most needs very well.
And speed is superior, as stated earlier. Three timed the speed of 64 bit floating point math.

Enough of this for now.
Comment are as usual welcome. and don't forget to be out in the sun. Coding is fun but tan is better… Smile

/Per
Back to top
View user's profile Visit poster's website
matjazs

Bascom Member



Joined: 08 Nov 2016
Posts: 86

PostPosted: Tue Jan 11, 2022 6:16 pm    Post subject: Reply with quote

I am testing this software without a graphic LCD. Instead of an LCD, I send data to the serial port.
Temperature and pressure work OK, humidity does not. The result of humidity is always zero (0.00).

Quote:
--------------------------
742.30 mm
24.32 C
0.00 %
--------------------------


Where is a problem?
I use this sensor: https://www.aliexpress.com/item/4000053138063.html?spm=a2g0o.productlist.0.0.1c5930761YGI80&algo_pvid=1d37c9fd-4056-4837-98a4-7fcdf52f118e&algo_exp_id=1d37c9fd-4056-4837-98a4-7fcdf52f118e-1&pdp_ext_f=%7B%22sku_id%22%3A%2210000000118240878%22%7D&pdp_pi=-1%3B0.9%3B-1%3B-1%40salePrice%3BUSD%3Bsearch-mainSearch
... with six (6) pins.

I'm checking the last Mrshilov example, which I'm changing to an Arduino UNO ATMEGA328P. The SDA and SCL ports are set to PORTC.4 and PORTC.5.

I need to remove this code because otherwise it always tells me "Sensor not found"

Code:
If Temp(1) = &H60 Then
     Print "Sensor found"                                   ' ID register must return $60
    ' Lcd_text "Sensor found" , 88 , 120 , Darkgreen , White
Else
    Print "Sensor not found"
    ' Lcd_text "Sensor not found" , 64 , 120 , Red , White
   Goto Not_exist
End If


In attach is my code. (Bascom AVR 2.0.8.5)

Code:
'BME Weather station BME280
'
'
'
'2022-01-11

$regfile = "m328pdef.dat"
$crystal = 16000000
'$crystal = 16e6
$baud = 9600
$hwstack = 30
$swstack = 30
$framesize = 30
'Config Clockdiv = 1
'Mcucr.7 = 1                                                 'Turn OFF JTAG
'Mcucr.7 = 1

'--------------------------- Display Configuration -----------------------------


'=============================== TWI (I2C) config ==============================
$lib "i2c_twi.lbx"
Config Sda = Portc.4                                        ' I2C Data
Config Scl = Portc.5                                        ' I2C Clock
Config Twi = 400000
Const Slave = &HEC                                          ' I2C Address (5pin=0)
I2cinit

Dim Temp(24) As Byte , Text As String * 16
Dim Temperature As Single , Humidity As Single , Pressure As Single
'================================ Test Program =================================
Print "Weather station BME280"
wait 2
'--------------- Test BME280 exist
Temp(1) = &HD0                                              ' ID register address
I2creceive Slave , Temp(1) , 1 , 1
'(
If Temp(1) = &H60 Then
     Print "Sensor found"                                   ' ID register must return $60
    ' Lcd_text "Sensor found" , 88 , 120 , Darkgreen , White
Else
    Print "Sensor not found"
    ' Lcd_text "Sensor not found" , 64 , 120 , Red , White
   Goto Not_exist
End If
')
Gosub Bme280_init                                           ' BME280 Initialization

Do
   Gosub Bme280_read
   Text = Fusing(pressure , "#.##") + " mm"
   Print text
   'Lcd_text "   Pressure = " + Text , 1 , 170 , Black , White
   Text = Fusing(temperature , "#.##") + " C"
   Print text
   'Lcd_text "Temperature = " + Text , 1 , 190 , Black , White
   Text = Fusing(humidity , "#.##") + " %"
   Print text
   'Lcd_text "   Humidity = " + Text , 1 , 210 , Black , White
   print "--------------------------"

   Wait 1
Loop
Not_exist:
Print "End of program"
End                                                         'end program
'-------------------------------------------------------------------------------

'============================= BME280 subroutines ==============================

'------------------------------ Initialization ---------------------------------
Bme280_init:
Dim T1 As Word , T2 As Integer , T3 As Integer
Dim P1 As Word , P2 As Integer , P3 As Integer
Dim P4 As Integer , P5 As Integer , P6 As Integer
Dim P7 As Integer , P8 As Integer , P9 As Integer
Dim H1 As Word , H2 As Integer , H3 As Word
Dim H4 As Integer , H5 As Integer , H6 As Integer
Dim Dtemp As Dword , Dpress As Dword , Dhum As Dword
Dim Temp1 As Long , Temp2 As Long , Temp3 As Long
Dim Press As Dword , T_mem As Long

Temp(1) = &HF2 : Temp(2) = &H05                             ' Humidity oversampling x16
I2csend Slave , Temp(1) , 2
Temp(1) = &HF4 : Temp(2) = &HB7                             ' Temperature oversampling x16, Pressure oversampling x16, Normal mode
I2csend Slave , Temp(1) , 2
Temp(1) = &HF5 : Temp(2) = &H70                             ' Standby 250ms, Filter x16
I2csend Slave , Temp(1) , 2
Temp(1) = &H88                                              ' Read Temperature and Pressure calibration
I2creceive Slave , Temp(1) , 1 , 24
T1 = Makeint(temp(1) , Temp(2))
T2 = Makeint(temp(3) , Temp(4))
T3 = Makeint(temp(5) , Temp(6))
P1 = Makeint(temp(7) , Temp(8))
P2 = Makeint(temp(9) , Temp(10))
P3 = Makeint(temp(11) , Temp(12))
P4 = Makeint(temp(13) , Temp(14))
P5 = Makeint(temp(15) , Temp(16))
P6 = Makeint(temp(17) , Temp(18))
P7 = Makeint(temp(19) , Temp(20))
P8 = Makeint(temp(21) , Temp(22))
P9 = Makeint(temp(23) , Temp(24))


Temp(1) = &HA1                                              ' Read Humidity calibration  Mrshilow
I2creceive Slave , Temp(1) , 1 , 1
H1 = Temp(1)
Temp(1) = &HE1
I2creceive Slave , Temp(1) , 1 , 8
H2 = Makeint(temp(1) , Temp(2))
H3 = Temp(3)
H4 = Temp(4) : Shift H4 , Left , 4
H5 = Temp(5) And &H0F : H4 = H4 + H5
H5 = Temp(5) And &HF0 : Shift H5 , Right , 4
H6 = Temp(6) : Shift H6 , Left , 4 : H5 = H5 + H6
H6 = Temp(7)


'Temp(1) = &HA1                                              ' Read Humidity calibration O-Family
'I2creceive Slave , Temp(1) , 1 , 1
'H1 = Temp(1)
'Temp(1) = &HE1
'I2creceive Slave , Temp(1) , 1 , 8
'H2 = Makeint(temp(1) , Temp(2))
'H3 = Temp(3)
'H4 = Temp(4) : Shift H4 , Left , 4
'Temp(5) = Temp(5) And &H0F : H4 = H4 + Temp(5)
'H5 = Temp(6) : Shift H5 , Left , 4
'Temp(7) = Temp(7) And &H0F : H5 = H5 + Temp(7)
'H6 = Temp(8)

Return


'---------------------- Read data and calculate results ------------------------
Bme280_read:
Temp(1) = &HF7                                              ' Data registers address
I2creceive Slave , Temp(1) , 1 , 8
Dpress = Temp(1) : Shift Dpress , Left , 8
Dpress = Dpress + Temp(2) : Shift Dpress , Left , 8
Dpress = Dpress + Temp(3) : Shift Dpress , Right , 4
Dtemp = Temp(4) : Shift Dtemp , Left , 8
Dtemp = Dtemp + Temp(5) : Shift Dtemp , Left , 8
Dtemp = Dtemp + Temp(6) : Shift Dtemp , Right , 4
Dhum = Temp(7) : Shift Dhum , Left , 8
Dhum = Dhum + Temp(8)

'-------------------------- Temperature
Shift Dtemp , Right , 3 : Temp1 = Dtemp - T1 : Temp1 = Temp1 - T1
Temp1 = Temp1 * T2 : Shift Temp1 , Right , 11 , Signed
Shift Dtemp , Right , 1 : Temp2 = Dtemp - T1
Temp2 = Temp2 * Temp2 : Shift Temp2 , Right , 12 , Signed
Temp2 = Temp2 * T3 : Shift Temp2 , Right , 14 , Signed
T_mem = Temp1 + Temp2 : Temp2 = T_mem * 5
Temp2 = Temp2 + 128 : Shift Temp2 , Right , 8 , Signed
Temperature = Temp2 / 100

'-------------------------- Pressure
Temp1 = T_mem : Shift Temp1 , Right , 1 , Signed
Temp1 = Temp1 - 64000
Temp2 = Temp1 : Shift Temp2 , Right , 2 , Signed
Temp2 = Temp2 * Temp2 : Shift Temp2 , Right , 11 , Signed
Temp2 = Temp2 * P6
Temp3 = Temp1 * P5 : Shift Temp3 , Left , 1
Temp2 = Temp2 + Temp3
Temp3 = P4 : Shift Temp3 , Left , 16
Shift Temp2 , Right , 2 , Signed
Temp2 = Temp2 + Temp3
Temp3 = Temp1 * P2 : Shift Temp3 , Right , 1 , Signed
Shift Temp1 , Right , 2 , Signed
Temp1 = Temp1 * Temp1 : Shift Temp1 , Right , 13
Temp1 = Temp1 * P3 : Shift Temp1 , Right , 3 , Signed
Temp1 = Temp1 + Temp3 : Shift Temp1 , Right , 18 , Signed
Temp1 = Temp1 + 32768
Temp1 = Temp1 * P1 : Shift Temp1 , Right , 15 , Signed
If Temp1 = 0 Then Goto Press_out                            'To avoid zero division
Press = 1048576 - Dpress : Shift Temp2 , Right , 12 , Signed
Press = Press - Temp2 : Press = Press * 3125
Press = Press / Temp1 : Press = Press + Press
Temp1 = Press : Shift Temp1 , Right , 3
Temp1 = Temp1 * Temp1 : Shift Temp1 , Right , 13
Temp1 = Temp1 * P9 : Shift Temp1 , Right , 12 , Signed
Temp2 = Press : Shift Temp2 , Right , 2
Temp2 = P8 * Temp2 : Shift Temp2 , Right , 13 , Signed
Temp1 = Temp1 + Temp2 : Temp1 = Temp1 + P7
Shift Temp1 , Right , 4 , Signed
Press = Press + Temp1
Press_out:
Pressure = Press * 0.0075006

'-------------------------- Humidity
Temp1 = T_mem - 76800
Temp2 = Dhum : Shift Temp2 , Left , 14
Temp3 = H4 : Shift Temp3 , Left , 20
Temp2 = Temp2 - Temp3 : Temp3 = Temp1 * H5
Temp2 = Temp2 - Temp3 : Temp2 = Temp2 + &H4000
Shift Temp2 , Right , 15 , Signed
Temp3 = Temp1 * H6 : Shift Temp3 , Right , 10 , Signed
T_mem = Temp1 * H3 : Shift T_mem , Right , 11 , Signed
T_mem = T_mem + &H8000 : Temp3 = Temp3 * T_mem
Shift Temp3 , Right , 10 , Signed
Temp3 = Temp3 + &H200000
Temp3 = Temp3 * H2 : Temp3 = Temp3 + &H2000
Shift Temp3 , Right , 14 , Signed
Temp1 = Temp2 * Temp3
Temp3 = Temp1 : Shift Temp3 , Right , 15 , Signed
Temp3 = Temp3 * Temp3 : Shift Temp3 , Right , 7 , Signed
Temp3 = Temp3 * H1 : Shift Temp3 , Right , 4 , Signed
Temp1 = Temp1 - Temp3
If Temp1 < 0 Then Temp1 = 0
If Temp1 > &H19000000 Then Temp1 = &H19000000
Shift Temp1 , Right , 15 , Signed
Humidity = Temp1 / 128
Return
Back to top
View user's profile
Per Svensson

Bascom Member



Joined: 03 Oct 2004
Posts: 235
Location: Gothenburg, Sweden

sweden.gif
PostPosted: Tue Jan 11, 2022 9:31 pm    Post subject: Reply with quote

You can try this code if you like
Perhaps Humidity comes out better then.
/Per



Code:


   ' --------------------------------------------------------------------------
   ' -------  BOSCH BME280 BAROMETRIC PRESSURE and TEMPERATURE SENSOR   -------
   ' --------------------------------------------------------------------------

   Function Bme280_getint(byval Lowaddr As Byte , Cs_port As Byte , Byval Cs_pin As Byte , Byval Bspi_port As Byte) As Integer

   ' Read two bytes from BME280 and combine them into a 16bit signed Integer

   ' Lowaddr is the register containing the LSB. MSB is assumed to be found at Lowaddr+1
   ' CS_port is the HW port where we have the CS_pin  (E.g PORTB)
   ' CS_pin is the pin number on CS_port we use for chip select. (0-7)
   ' Bspi_port is the physical spi port nr we are using  (0-3)
   ' Error code is not returned. We assume that the device is functional
   ' This routine consumes max xxus at Xtal=yyMHz

      Local Msb As Byte
      Local Lsb As Byte

      Reset Cs_port.cs_pin                                  ' Chip select
      Print #bspi_port , Lowaddr                            'address of Lsb
      Input #bspi_port , Lsb                                'get Lsb
      Input #bspi_port , Msb                                'get Msb
      Bme280_getint = Makeint(lsb , Msb)
      Set Cs_port.cs_pin                                    ' Chip deselect

   End Function
'---------------------------------------------------------------------------------------

   Function Bme280_getdata(pressure As Dword , Humidity As Word , Temp As Dword , _
      Cs_port As Byte , Byval Cs_pin As Byte , Byval Bspi_port As Byte) As Byte

   ' Read Pressure and temperature BME280 + STATUS
   ' Data is returned as a DWORD where bit 19..0 are significant (20bit resolution)
   ' If device is not ready then we simply exit and data will not be updated.
   ' CS_port is the HW port where we have the CS_pin  (E.g PORTB)
   ' CS_pin is the pin number on CS_port we use for chip select. (0-7)
   ' Bspi_port is the physical spi port nr we are using  (0-3)
   ' Error code returners the status register byte
   ' This routine consumes max xxus at Xtal=yyMHz

      Local Reg As Byte

'    We are using the already existing Temporary DWORD and WORD made up by four overlaied bytes
'    This is how it will be stored in SRAM:

'    <-------------- Dword_overlay ------------->
'    <--- WORD0_OVERLAY ---X--- WORD1_OVERLAY -->
'    +-----------+---------+----------+---------+
'    |   BYTE0   |  BYTE1  |   BYTE2  |  BYTE3  |
'    +-----------+---------+----------+---------+
'    |   Addr    |  Addr+1 |   Addr+2 |  Addr+3 |
'    +-----------+---------+----------+---------+
'    Dim Dword_overlay As Dword
'    Dim Single_overlay As Single At Dword_overlay Overlay
'    Dim Word0_overlay As Word At Dword_overlay + 0 Overlay
'    Dim Word1_overlay As Word At Dword_overlay + 2 Overlay
'    Dim Byte0_overlay As Byte At Dword_overlay + 0 Overlay                          ' LSB (Lowest RAM addr.)
'    Dim Byte1_overlay As Byte At Dword_overlay + 1 Overlay                          '  .
'    Dim Byte2_overlay As Byte At Dword_overlay + 2 Overlay                          '  .
'    Dim Byte3_overlay As Byte At Dword_overlay + 3 Overlay                          ' MSB
'    Dim Bytarr_ovl(4) As Byte At Dword_overlay Overlay                              'Same data but now as a byte array

      Bme280_getdata = 0                                    ' Assume Success


 ' Initiate multiple READ transfer starting at &HF7. Address is autoincrementing  F7,F8...

      Reset Cs_port.cs_pin                                  'Chip select
      Reg = Bme280_status                                   'Status register address
      Print #bspi_port , Reg                                'Use it as start address

 '    Get STATUS BYTE
      Input #bspi_port , Dword_overlay                      'skip to first pressure data (STATUS + Three dummy bytes)
      Bme280_getdata = Byte3_overlay                        'Return The Status Byte
      If Byte3_overlay <> 0 Then Goto Skip_bme280

 '    GET PRESSURE DATA  (20 bits)
      Input #bspi_port , Byte3_overlay                      'F7 msb
      Input #bspi_port , Byte2_overlay                      'F8 lsb
      Input #bspi_port , Byte1_overlay                      'F9 xlsb
      Shift Dword_overlay , Right , 12                      'Right adjust
      Pressure = Dword_overlay

'     GET TEMPERATURE DATA (20 bits)
      Input #bspi_port , Byte3_overlay                      'FA msb
      Input #bspi_port , Byte2_overlay                      'FB lsb
      Input #bspi_port , Byte1_overlay                      'FC xlsb
      Shift Dword_overlay , Right , 12                      'Right adjust
      Temp = Dword_overlay

'     GET HUMIDITY DATA (16 bits)
      Input #bspi_port , Byte1_overlay                      'FD msb
      Input #bspi_port , Byte0_overlay                      'FE lsb
      Humidity = Dword_overlay                              'Use only the two lowest bytes

      Skip_bme280:                                          'Skip data readout if no data ready
         Set Cs_port.cs_pin                                 ' Chip deselect

   End Function
'-------------------------------------------------------------------------------


   Sub Bme280_correct_float(pressure As Single , Humidity As Single , Temperature As Single)
  ' Correct Temperature, Pressure and Humidity, using correction factors loded from the Bme280 chip.
  ' Calibration constants are loaded by the Bme280_config function and must be run before first call to this sub.
  ' All correction constants are passed as global variables.
  ' Corrected values for Pressure, Humidity and Temperature will replace the raw sensor values upon exit.


  ' This routine does the same job as Bme280_correct_int, but is more accurate at the price of half the speed
  ' CPU use is approx 14700 cycles (= 920us at 16 MHz)

  ' See also blog: https://www.instructables.com/id/Library-for-BMP280/

      Local S1 As Single
      Local S2 As Single
      Local S3 As Single
      Local S4 As Single
      Local S5 As Single
      Local Tfine As Single
      Local D1 As Double
      Local D2 As Double
      Local D3 As Double
      Local D4 As Double
      Local Dpress As Double
      Local L1 As Long


  'TEMPERATURE CORR
  '----------------
  '  Tfine is only for use in Pressure and Humidity calculations.
  '  Output value of "51.23" equals 51.23 DegC.

  'Formula from the datasheet:
  '   S1 =(ADC/16384 - Ct1/1024) * Ct2
  '   S2 =((ADC/131072 - Ct1/8192) * (ADC/131072 - Ct1/8192)) * Ct3
  '   Tfine =S1 + S2
  '   Temperature =(S1 + S2) / 5120

  'BASCOM:
      S3 = Temperature : Shift S3 , Right , 14 , Signed     ' ADC/16384
      S4 = Ct1 : Shift S4 , Right , 10 , Signed             ' Ct1/1024
      S1 = S3 - S4
      S1 = S1 * Ct2

 '     Shift S3 , Right , 3 , Signed                         'ADC/131072
'      Shift S4 , Right , 3 , Signed                         'Ct1/8192
      S2 = S3 - S4
      Shift S2 , Right , 3 , Signed
      S2 = S2 * S2                                          '[ADC/131072-Ct1/8192]^2
      S2 = S2 * Ct3

      Tfine = S1 + S2
      Temperature = Tfine / 5120                            'Return Temperature as a long integer multiplied by 100


   'PRESSURE CORR
   '----------------
   ' Read uncompensated pressure and return pressure in Pa
   ' Output value of "96386.2" equals 96386.2 Pa = 963.862 hPa.

   'Formula from the datasheet:
   '  ADC : value of uncompensated data. Tfine comes from the temperature corrction routine
   '  S1 = Tfine/2 - 64000
   '  D2 = D1 * D1 * Cp6 / 32768
   '  D2 = D2 + D1 * Cp5 * 2
   '  D2 = D2/4 + Cp4*65536
   '  D1 = (Cp3*D1*D1/524288 + Cp2*D1) / 524288
   '  D1 =(1 + D1/32768) * Cp1

   '  Avoid exception caused by division by zero.
   '  If D1 = 0 Then
   '     Dpress = 0
   '  Else
   '     Dpress = 1048576 - ADC
   '     Dpress =(Dpress - D2/4096) * 6250/D1
   '     D1 = Cp9 * Dpress * Dpress / 2147483648
   '     D2 = Dpress * Cp8 / 32768
   '     Dpress = Dpress + (D1 + D2 + Cp7) / 16
   '  End If

      Const Inv_16 = 1 / 16
      Const Inv_256 = 1 / 256
      Const Inv_1k = 1 / 1024
      Const Inv_4k = 1 / 2 ^ 12
      Const Inv_32k = 1 / 2 ^ 15
      Const Inv_64k = 1 / 2 ^ 16
      Const Inv_512k = 1 / 2 ^ 19

'BASCOM:

'  S1 = Tfine/2 - 64000
      S1 = Tfine - 128000
      S1 = S1 * 0.5
      D1 = S1                                               ' Tfine/2 - 64000

'  D2 = D1 * D1 * Cp6 / 32768
      D2 = Cp6
      D2 = D2 * Inv_32k
      D2 = D2 * D1
      D2 = D2 * D1

'  D2 = D2 + D1 * Cp5 * 2

      L1 = Cp5 * 2
      D3 = L1
      D3 = D3 * D1
      D2 = D2 + D3

'  D2 = D2/4 + Cp4*65536
      L1 = Cp4 : Shift L1 , Left , 16
      D3 = L1
      D4 = D2 * 0.25
      D2 = D3 + D4

'  D1 = (Cp3*D1*D1/524288 + Cp2*D1) / 524288
      D4 = Cp3
      D3 = D1 * Inv_1k
      D3 = D3 * D3
      D3 = D3 * 2
      D3 = D3 * D4
      D4 = Cp2
      D4 = D4 * D1
      D1 = D3 + D4
      D1 = D1 * Inv_512k

'  D1 =(1 + D1/32768) * Cp1
      D1 = D1 * Inv_32k
      Incr D1
      D3 = Cp1
      D1 = D1 * D3

      If D1 = 0 Then                                        'Avoid div by zero
         Dpress = 0
      Else
'  Replace raw ADC by new estimate
         Dpress = Pressure
         Dpress = 1048576 - Dpress

'  Dpress =(Dpress - D2/4096) * 6250/D1
         D3 = D2 * Inv_4k
         Dpress = Dpress - D3
         Dpress = Dpress * 6250
         Dpress = Dpress / D1                               ' [Dpress - D2/4096] * 6250/d1

'  D1 = Cp9 * Dpress * Dpress / 2147483648  = 2*(Dpress/65536)^2
         D3 = Cp9
         D1 = Dpress * Inv_64k
         D1 = D1 * D1
         D1 = D1 + D1                                       'D1 * 2
         D1 = D1 * D3

'  D2 = Dpress * Cp8 / 32768
         D3 = Cp8
         D2 = Dpress * D3
         D2 = D2 * Inv_32k

'  Dpress = Dpress + (D1 + D2 + Cp7) / 16
         D3 = Cp7
         D3 = D3 + D2
         D3 = D3 + D1
         D3 = D3 * Inv_16
         Dpress = Dpress + D3
         Pressure = Dpress
      End If


 'HUMIDITY CORR
'----------------
'  Read actual humidity from uncompensated humidity and return the value in relative humidity (%rH)
'  Output value of "42.12" equals 42.12 %rH

'  Formula from the datasheet:
'  ADC : value of uncompensated data. Tfine comes from the temperature corrction routine
'  Humidity = Tfine - 76800
'  Humidity=[ADC-(ch4*64 + Ch5/16384*Humidity)] * [Ch2/65536*(1+Ch6/67108864*Humidity*{1+Ch3/67108864*Humidity})]
'  Humidity = Humidity *(1 - Ch1 * Humidity / 524288)

'  If Humidity > 100 Then
'    Humidity = 100
'  Elseif Humidity < 0 Then
'    Humidity = 0
'  End If

'BASCOM:
      S1 = Tfine - 76800
      S2 = Ch4 * 64
      S3 = Ch5 * S1 : Shift S3 , Right , 14 , Signed        ' Ch5/16384*Humidity
      S3 = S2 + S3                                          ' Ch4*64 + Ch5/16384*Humidity
      S3 = Humidity - S3                                    ' ADC-(ch4*64 + Ch5/16384*Humidity)
      S4 = Ch6 : Shift S4 , Right , 26 , Signed
      S4 = S4 * S1                                          ' Ch6/67108864*Humidity
      S5 = Ch3 : Shift S5 , Right , 26 , Signed
      S5 = S5 * S1
      Incr S5                                               ' 1+Ch3/67108864*Humidity
      S2 = S4 * S5
      Incr S2                                               ' 1+Ch6/67108864*Humidity*{1+Ch3/67108864*Humidity}
      S2 = S2 * Ch2 : Shift S2 , Right , 16 , Signed        ' Ch2/65536*(1+Ch6/67108864*Humidity*{1+Ch3/67108864*Humidity})
      S2 = S2 * S3                                          ' [ADC-(ch4*64 + Ch5/16384*Humidity)] * [Ch2/65536*(1+Ch6/67108864*Humidity*{1+Ch3/67108864*Humidity})]
      S3 = S2 * Ch1 : Shift S3 , Right , 19 , Signed
      S3 = 1 - S3                                           ' 1 - Ch1 * Humidity / 524288
      Humidity = S2 * S3

      If Humidity > 100 Then
         Humidity = 100
      Elseif Humidity < 0 Then
         Humidity = 0
      End If

   End Sub
'-------------------------------------------------------------------------------
[/code]
Back to top
View user's profile Visit poster's website
matjazs

Bascom Member



Joined: 08 Nov 2016
Posts: 86

PostPosted: Wed Jan 12, 2022 8:30 am    Post subject: Reply with quote

Your code is probably written for SPI communication. Would you send schema, how is BME280 connected to microcontroller.

I am using I2C communication with the BME280 module.
In my modified case, there is probably something wrong with the addresses and values in the registers, because temperature and pressure work OK.

If I understand correctly, your code is more accurate.
Back to top
View user's profile
Display posts from previous:   
Post new topic   Reply to topic    www.mcselec.com Forum Index -> Share your working BASCOM-AVR code here All times are GMT + 1 Hour
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum