nodemcu-firmware/lua_modules/bme280/bme280.lua

174 lines
5.7 KiB
Lua

--[[
BME280 Lua module
Requires i2c and bme280_math module
Written by Lukas Voborsky, @voborsky
]]
local bme280 = {}
-- bme280.setup()
-- bme280:setup()
-- bme280:read()
-- bme280:altitude()
-- bme280:dewpoint()
-- bme280:qfe2qnh()
-- bme280:startreadout()
local type, assert = type, assert
local table_concat, math_floor = table.concat, math.floor
local i2c_start, i2c_stop, i2c_address, i2c_read, i2c_write, i2c_TRANSMITTER, i2c_RECEIVER =
i2c.start, i2c.stop, i2c.address, i2c.read, i2c.write, i2c.TRANSMITTER, i2c.RECEIVER
local bme280_math_setup, bme280_math_read, bme280_math_qfe2qnh, bme280_math_altitude, bme280_math_dewpoint =
bme280_math.setup, bme280_math.read, bme280_math.qfe2qnh, bme280_math.altitude, bme280_math.dewpoint
local tmr_create, tmr_ALARM_SINGLE = tmr.create, tmr.ALARM_SINGLE
local BME280_I2C_ADDRESS1 = 0x76
local BME280_I2C_ADDRESS2 = 0x77
local BME280_REGISTER_CONTROL = 0xF4
local BME280_REGISTER_CONTROL_HUM = 0xF2
local BME280_REGISTER_CONFIG= 0xF5
local BME280_REGISTER_CHIPID = 0xD0
local BME280_REGISTER_DIG_T = 0x88 -- 0x88-0x8D ( 6)
local BME280_REGISTER_DIG_P = 0x8E -- 0x8E-0x9F (18)
local BME280_REGISTER_DIG_H1 = 0xA1 -- 0xA1 ( 1)
local BME280_REGISTER_DIG_H2 = 0xE1 -- 0xE1-0xE7 ( 7)
local BME280_REGISTER_PRESS = 0xF7 -- 0xF7-0xF9
-- local BME280_FORCED_MODE = 0x01
-- maximum measurement time in ms for maximum oversampling for all measures
-- 113 > 1.25 + 2.3*16 + 2.3*16 + 0.575 + 2.3*16 + 0.575 ms
local BME280_SAMPLING_DELAY =113
-- Local functions
local read_reg
local write_reg
local bme280_setup
local bme280_read
local bme280_startreadout
-- -- Note that the space between debug and the arglist is there for a reason
-- -- so that a simple global edit " debug(" -> "-- debug(" or v.v. to
-- -- toggle debug compiled into the module.
-- local print, node_heap = print, node.heap
-- local function debug (fmt, ...) -- upval: cnt (, print, node_heap)
-- if not bme280.debug then return end
-- if (...) then fmt = fmt:format(...) end
-- print("[bme280]", node_heap(), fmt)
-- end
--------------------------- Set up the bme280 object ----------------------------
-- bme280 has method setup to create the sensor object and setup the sensor
-- object created by bme280.setup() has methods: read, qfe2qnh, altitude, dewpoint
---------------------------------------------------------------------------------
function bme280.setup(id, addr, temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter, full_init)
return bme280_setup(nil, id,
addr, temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter, full_init)
end
------------------------------------------------------------------------------
function bme280_setup(self, id, addr,
temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter, full_init)
addr = (addr==2) and BME280_I2C_ADDRESS2 or BME280_I2C_ADDRESS1
full_init = full_init or true
-- debug("%d %x %d", id, addr, BME280_REGISTER_CHIPID)
local chipid = read_reg(id, addr, BME280_REGISTER_CHIPID, 1)
if not chipid then
return nil
end
-- debug("chip_id: %x", chipid:byte(1))
local isbme = (chipid:byte(1) == 0x60)
local buf = {}
buf[1] = read_reg(id, addr, BME280_REGISTER_DIG_T, 6)
buf[2] = read_reg(id, addr, BME280_REGISTER_DIG_P, 18)
if (isbme) then
buf[3] = read_reg(id, addr, BME280_REGISTER_DIG_H1, 1)
buf[4] = read_reg(id, addr, BME280_REGISTER_DIG_H2, 7)
end
local sensor, config = bme280_math_setup(table_concat(buf),
temp_oss, press_oss, humi_oss, power_mode, inactive_duration, IIR_filter)
self = self or {
setup = bme280_setup,
read = bme280_read,
startreadout = bme280_startreadout,
qfe2qnh = bme280_math_qfe2qnh,
altitude = bme280_math_altitude,
dewpoint = bme280_math_dewpoint
}
self.id, self.addr = id, addr
self._sensor, self._config, self._isbme = sensor, config, isbme
if (full_init) then
write_reg(id, addr, BME280_REGISTER_CONFIG, config[1])
if (isbme) then write_reg(id, addr, BME280_REGISTER_CONTROL_HUM, config[2]) end
write_reg(id, addr, BME280_REGISTER_CONTROL, config[3])
end
return self
end
function bme280_read(self, alt)
local buf = read_reg(self.id, self.addr, BME280_REGISTER_PRESS, 8) -- registers are P[3], T[3], H[2]
if buf then
return bme280_math_read(self._sensor, buf, alt)
else
return nil
end
end
function bme280_startreadout(self, callback, delay, alt)
assert(type(callback) == "function", "invalid callback parameter")
delay = delay or BME280_SAMPLING_DELAY
if self._isbme then write_reg(self.id, self.addr, BME280_REGISTER_CONTROL_HUM, self._config[2]) end
write_reg(self.id, self.addr, BME280_REGISTER_CONTROL, math_floor(self._config[3]:byte(1)/4)+ 1)
-- math_floor(self._config[3]:byte(1)/4)+ 1
-- an awful way to avoid bit operations but calculate (config[3] & 0xFC) | BME280_FORCED_MODE
-- Lua 5.3 integer division // would be more suitable
tmr_create():alarm(delay, tmr_ALARM_SINGLE,
function()
callback(bme280_read(self, alt))
end
)
end
function write_reg(id, dev_addr, reg_addr, data)
i2c_start(id)
if not i2c_address(id, dev_addr, i2c_TRANSMITTER) then
-- debug("No ACK on address: %x", dev_addr)
return nil
end
i2c_write(id, reg_addr)
local c = i2c_write(id, data)
i2c_stop(id)
return c
end
function read_reg(id, dev_addr, reg_addr, n)
i2c_start(id)
if not i2c_address(id, dev_addr, i2c_TRANSMITTER) then
-- debug("No ACK on address: %x", dev_addr)
return nil
end
i2c_write(id, reg_addr)
i2c_stop(id)
i2c_start(id)
i2c_address(id, dev_addr, i2c_RECEIVER)
local c = i2c_read(id, n)
i2c_stop(id)
return c
end
------------------------------------------------ -----------------------------
return bme280