Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 09:06 25 Nov 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MM2(+): BME280 temp, pressure, humidity

Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 9110
Posted: 11:06pm 17 Feb 2016
Copy link to clipboard 
Print this post

This device is certainly useful but what a ridiculous programming interface

The registers where you read the conversion data are big-endian. However, the registers where you read the calibration data are little-endian. What plonker thought that one up?

Moreover, the humidity function has two calibration data elements sharing registers in a most bizarre way.

Finally there is a gotcha that may affect any port from C to MMBasic.

In MMBasic the ">>" operator always puts a zero into the 64th bit. In C, if the datatype is signed then ">>" will put a zero or 1 depending on whether the number was originally positive or negative

However, having sorted all that out here is a program for reading the temperature, pressure and humidity from a BME280 (thanks to lew247 for the loan of the module)

Connection to the device is I2C.
Connect I2C Clock on the Micromite to SCK on the module
Connect I2C Data on the Micromite to SDI on the module
Connect power and ground (the device works fine on 3.3V)
Leave CS and SDO on the module unconnected

UPDATE - Removed CFunctions so now Basic only


option explicit
option default none
'
' BME280 routines and test harness
'
const BME280_ADDRESS = &H77
const BME280_REGISTER_T1 = &H88
const BME280_REGISTER_P1 = &H8E
const BME280_REGISTER_H1 = &HA1
const BME280_REGISTER_H2 = &HE1
const BME280_REGISTER_CHIPID = &HD0
const BME280_REGISTER_CONTROLHUMID = &HF2
const BME280_REGISTER_CONTROL = &HF4
const BME280_REGISTER_PRESSUREDATA = &HF7
const BME280_REGISTER_TEMPDATA = &HFA
const BME280_REGISTER_HUMIDDATA = &HFD
'
dim integer s16=&HFFFFFFFFFFFF0000 , s16b=&H8000
dim integer s12=&HFFFFFFFFFFFFF000 , s12b=&H800
dim integer s8= &HFFFFFFFFFFFFFF00 , s8b=&H80
'
DIM INTEGER T1,T2,T3 'uint16_t, int16_t, int16_t
DIM INTEGER P1,P2,P3,P4,P5,P6,P7,P8,P9 'uint16_t, 8 x int16_t
DIM INTEGER H1,H2,H3,H4,H5,H6 'uint8_t, int16_t , uint8_t, int16_t, int16_t, int8_t
'
dim INTEGER t_fine 'used to store accurate temp reading from temp conversion for use in pressure and humidity conversions
'
' Test program
'
bme280_init
do
print bme280_read_temp() 'must be run before pressure or humidity
print bme280_read_pressure()
print bme280_read_humidity()
pause 2000
loop
'
end
'
'***************************************************************************************************
'
function bme280_read_temp() as float
local integer var1,var2,adc_T
local adc%(2)
i2c write BME280_ADDRESS,1,1,BME280_REGISTER_TEMPDATA
i2c read BME280_ADDRESS,0,3,adc%()
adc_T=((adc%(0)<<16) OR (adc%(1)<<8) or adc%(2))>>4
var1 = ((((adc_T>>3) - (T1 <<1))) * T2) \ q(11)
var2 = (((((adc_T>>4) - (T1)) * ((adc_T\ q(4)) - (T1))) \ q(12)) * (T3)) \ q(14)
t_fine = var1 + var2
bme280_read_temp = ((t_fine * 5 + 128) \ q(8))/100.0
end function

function bme280_read_pressure() as float
local integer var1, var2, adc_P, p
local adc%(2)
i2c write BME280_ADDRESS,1,1,BME280_REGISTER_PRESSUREDATA
i2c read BME280_ADDRESS,0,3,adc%()
adc_P=((adc%(0)<<16) OR (adc%(1)<<8) or adc%(2))>>4
var1 = t_fine - 128000
var2 = var1 * var1 * P6
var2 = var2 + ((var1 * P5)<<17)
var2 = var2 + (P4 << 35)
var1 = ((var1 * var1 * P3)\ q(8)) + ((var1 * P2)<<12)
var1 = ((1<<47)+var1)*P1\ q(33)
if var1 = 0 THEN
bme280_read_pressure = 0' avoid exception caused by division by zero
exit function
endif
p = 1048576 - adc_P
p = (((p<<31) - var2)*3125) \ var1
var1 = (P9 * (p\ q(13)) * (p\ q(13))) \ q(25)
var2 = (P8 * p) \ q(19)
p = ((p + var1 + var2) \ q(8)) + (P7<<4)
bme280_read_pressure = p/25600.0
end function
'
function bme280_read_humidity() as float
local integer v_x1,adc_H
local adc%(1)
i2c write BME280_ADDRESS,1,1,BME280_REGISTER_HUMIDDATA
i2c read BME280_ADDRESS,0,2,adc%()
adc_H=(adc%(0)<<8) or adc%(1)
v_x1 = t_fine - 76800
v_x1=(((((adc_H<<14)-((H4)<<20)-(H5*v_x1))+16384)\ q(15))*(((((((v_x1*H6)\ q(10))*(((v_x1*H3)\ q(11))+32768))\ q(10))+2097152)*H2+8192)\ q(14)))
v_x1 = (v_x1 - (((((v_x1 \ q(15)) * (v_x1 \ q(15))) \ q(7)) * (H1)) \ q(4)))
if v_x1< 0 then v_x1 = 0
if v_x1 > 419430400 then v_x1= 419430400
bme280_read_humidity = (v_x1\ q(12)) / 1024.0
end function

sub bme280_init
local i%,cal%(17)
i2c open 400,1000 '400KHz bus speed
i2c write BME280_ADDRESS,1,1,BME280_REGISTER_CHIPID
i2c read BME280_ADDRESS,0,1,i%
if i%<>&H60 then print "Error BME280 not found"
'
i2c write BME280_ADDRESS,1,1,BME280_REGISTER_T1
i2c read BME280_ADDRESS,0,6,cal%()
T1=cal%(0) OR (cal%(1)<< 8)
T2=cal%(2) OR (cal%(3)<< 8): if T2 and s16b then T2=T2 OR s16 'sign extend if required
T3=cal%(4) OR (cal%(5)<< 8): if T3 and s16b then T3=T3 OR s16
'
i2c write BME280_ADDRESS,1,1,BME280_REGISTER_P1
i2c read BME280_ADDRESS,0,18,cal%()
P1=cal%(0) OR (cal%(1)<<8)
P2=cal%(2) OR (cal%(3)<<8): if P2 and s16b then P2=P2 OR s16 'sign extend if required
P3=cal%(4) OR (cal%(5)<<8): if P3 and s16b then P3=P3 OR s16
P4=cal%(6) OR (cal%(7)<<8): if P4 and s16b then P4=P4 OR s16
P5=cal%(8) OR (cal%(9)<<8): if P5 and s16b then P5=P5 OR s16
P6=cal%(10) OR (cal%(11)<<8): if P6 and s16b then P6=P6 OR s16
P7=cal%(12) OR (cal%(13)<<8): if P7 and s16b then P7=P7 OR s16
P8=cal%(14) OR (cal%(15)<<8): if P8 and s16b then P8=P8 OR s16
P9=cal%(16) OR (cal%(17)<<8): if P9 and s16b then P9=P9 OR s16
'
i2c write BME280_ADDRESS,1,1,BME280_REGISTER_H1
i2c read BME280_ADDRESS,0,1,H1
i2c write BME280_ADDRESS,1,1,BME280_REGISTER_H2
i2c read BME280_ADDRESS,0,7,cal%()
H2=cal%(0) OR (cal%(1)<< 8): if H2 and s16b then H2=H2 OR s16 'sign extend if required
H3=cal%(2)
H6=cal%(6): if H6 and s8b then H6=H6 OR s8 'sign extend if required
H4=(cal%(3)<<4) OR (cal%(4) and &H0F): if H4 and s12b then H4=H4 OR s12 'sign extend if required
H5=(cal%(5)<<4) OR (cal%(4)>>4): if H5 and s12b then H5=H5 OR s12
'
i2c write BME280_ADDRESS,0,2,BME280_REGISTER_CONTROLHUMID,&H05 '16x oversampling humidity
i2c write BME280_ADDRESS,0,2,BME280_REGISTER_CONTROL,&HB7 '16x oversampling pressure/temp, normal mode
'
end sub
'
function q(x as integer) as integer 'returns 2 raised to the power
q=(1<<x)
End CFunction
Edited by matherp 2016-02-19
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1702
Posted: 02:04am 18 Feb 2016
Copy link to clipboard 
Print this post

Thank you so much for this
 
viscomjim
Guru

Joined: 08/01/2014
Location: United States
Posts: 925
Posted: 05:50pm 18 Feb 2016
Copy link to clipboard 
Print this post

Matherp... you are a machine! Do you dream in code? Amazing stuff here....
 
centrex

Guru

Joined: 13/11/2011
Location: Australia
Posts: 320
Posted: 10:11pm 18 Feb 2016
Copy link to clipboard 
Print this post

Hi Matherp
Way above my pay scale but how accurate is the device with the readings you have obtained?????


Cliff
Cliff
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 9110
Posted: 01:18am 19 Feb 2016
Copy link to clipboard 
Print this post

  Quote  how accurate is the device with the readings you have obtained?


Difficult to say - it is certainly very stable. The code sets the device for 16x oversampling on all measurements

Humidity measurements were within 2% of DHT22, temperature measurements within 1 degree of DS18B20.
 
lew247

Guru

Joined: 23/12/2015
Location: United Kingdom
Posts: 1702
Posted: 10:23am 22 Feb 2016
Copy link to clipboard 
Print this post

Probably asking too much
but
is there an easy way to display altitude? I can see how it's done on the BME280 on the arduino code but thats like speaking a totally foreign language to me
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 9110
Posted: 11:36am 22 Feb 2016
Copy link to clipboard 
Print this post

  Quote  is there an easy way to display altitude?


See this thread for code and discussion.

You can't properly calculate altitude without knowing sea level pressure at the same time and even then you are basing it on a model of the atmosphere which may not be exact at that particular moment. However the thread contains simple code for converting local pressure to altitude given sea level pressure.

If you don't know sea-level pressure then 1013.25 is considered "standard".

Aircraft above a certain altitude all set 1013.25 as the notional sea-level pressure. This way if they fly 1000ft apart in altitude then they will be at that separation even though the absolute altitude may be different to that displayed on their altimeters
 
v.lenzer
Regular Member

Joined: 04/05/2024
Location: Germany
Posts: 49
Posted: 04:11pm 26 Jun 2024
Copy link to clipboard 
Print this post

I need your help again. I want to build a display for temperature, air pressure and humidity using an RP2040-Zero, a BME/BMP280-I2C module and a TFT ILI9341. I was happy when I found the MMBasic source here. As far as I understand, the program runs on a Micromite MM2.

The I2C device is labeled "BME/BMP280". It has the inputs GND, Vin, SCL and SDA. The device address is hex76/dec118. This address was recognized by an I2C scanner. So it should work.

The RP2040-Zero has the MMBasic version 5.09.00RC5. I have adapted the program, which should initially only output the values ​​on the console:
SETPIN GP0,GP01,I2C
const BME280_ADDRESS = &H76
I have not set any options.

After RUN there is no error message, but no measured values ​​appear either.

I have built text output into the bme280_init function. That is how I know that it is called. The error "Error BME280 not found" is not output - the device has obviously been recognized. The value for i% is dez96.

The program then also enters the do/loop loop, but the functions
bme280_read_temp()
bme280_read_pressure()
bme280_read_humidity()
are not called and the pause of 2 seconds is not processed. The loop is also exited.

Does anyone have any idea why this might be.
Edited 2024-06-27 02:45 by v.lenzer
Best wishes! Joachim
 
v.lenzer
Regular Member

Joined: 04/05/2024
Location: Germany
Posts: 49
Posted: 04:48pm 26 Jun 2024
Copy link to clipboard 
Print this post

I just found the error:
The last line in the above program is wrong!
It should say: "END FUNCTION" and not "END CFUNCTION"
Now I get all the values ​​I want. Thanks for the program!!
Best wishes! Joachim
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 2135
Posted: 04:14am 27 Jun 2024
Copy link to clipboard 
Print this post

  Quote   what a ridiculous programming interface

Indeed! Perhaps it was designed on April 1, or by a disgruntled employee on their last day with the firm.

For comparison the Sub for an AHT10, no pressure sensing  but still...
Sub AHT10
  Local dat(4) as Integer
  I2C read AHaddr,1,5,dat() 'read first 5 data bytes - last one not needed.
  humid = Cint(dat(1) / 2.56)
  temp = Cint((((dat(3) And 15) << 8) + dat(4)) / 2.048 - 500) / 10
  I2C write AHaddr, 0, 3, 172, 51, 0  'trigger measurement for next read
End Sub

Edited 2024-06-27 14:19 by phil99
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024