From 3397950723f5bd572624ba4d72f75cf1af6875c7 Mon Sep 17 00:00:00 2001 From: tobid7 Date: Wed, 11 Jun 2025 18:42:20 +0200 Subject: [PATCH] Initial Commit --- .gitignore | 1 + CMakeLists.txt | 14 ++++ README.md | 23 ++++++ include/bme280.h | 66 ++++++++++++++++++ source/bme280.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 282 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 README.md create mode 100755 include/bme280.h create mode 100755 source/bme280.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d163863 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +build/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d5aa373 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.22) + +######################################################## +### Tested for add_subdirectory Raspi Pico projects! ### +### NOT OPTIMIZED TO BE USED WITHOUT PICOSDK!!! ### +######################################################## +project(bme280 LANGUAGES C) + +add_library(bme280 source/bme280.c) +target_include_directories(bme280 PUBLIC include) +target_link_libraries(bme280 PUBLIC + pico_stdlib + hardware_i2c +) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7e47d8e --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# BME 280 Library + +Library Created for BME280 Temperature Sensor + +## Example + +```c +#include + +int main() { + stdio_init_all(); + bme280_ctx* ctx = bme280_init(i2c0, 4, 5); + while(true) { + ctx->update(ctx); + printf("Temp: %.1f°C Hum: %.2f%%", + ctx->read_temp(ctx), + ctx->read_humidity(ctx)); + sleep_ms(1000); + } + // Probably never reached + bme280_deinit(ctx); +} +``` diff --git a/include/bme280.h b/include/bme280.h new file mode 100755 index 0000000..774ed27 --- /dev/null +++ b/include/bme280.h @@ -0,0 +1,66 @@ +#ifndef __BME280_H__ +#define __BME280_H__ + +// Einfach mal wieder was in C schreinben oder so + +// Use extern C from C++ +#ifdef __cplusplus +extern "C" { +#endif + +#include "hardware/i2c.h" + +#ifndef BME280_ADDR +#define BME280_ADDR 0x76 +#endif + +// Strcut zum speichern aller kallibrierungsdaten +typedef struct __bme280_callib { + // Temp + uint16_t dig_T1; + int16_t dig_T2; + int16_t dig_T3; + // Luftdruck ?? + uint16_t dig_P1; + int16_t dig_P2; + int16_t dig_P3; + int16_t dig_P4; + int16_t dig_P5; + int16_t dig_P6; + int16_t dig_P7; + int16_t dig_P8; + int16_t dig_P9; + // Luftfeuchtigkeit + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4; + int16_t dig_H5; + int8_t dig_H6; +} bme280_callib; + +// Usally the way how devkitpro members declare +// structs in C +typedef struct bme280_ctx_s { + // Functions + void (*update)(struct bme280_ctx_s* self); + float (*read_temp)(struct bme280_ctx_s* self); + float (*read_humidity)(struct bme280_ctx_s* self); + float (*read_pressure)(struct bme280_ctx_s* self); + /// Nur für bme280.c lesbar + bme280_callib callib; + int32_t raw_temperature; + int32_t raw_humidity; + int32_t raw_pressure; + int32_t t_fine; + i2c_inst_t* i2c; +} bme280_ctx; + +// Base functions +bme280_ctx* bme280_init(i2c_inst_t* i2c, uint sda, uint scl); +void bme280_deinit(bme280_ctx* ctx); + +#ifdef __cplusplus +} +#endif +#endif \ No newline at end of file diff --git a/source/bme280.c b/source/bme280.c new file mode 100755 index 0000000..ca77a5d --- /dev/null +++ b/source/bme280.c @@ -0,0 +1,178 @@ +#include +#include +#include +#include + +/** + * Funktionen für Die umrechnung mithilfe der Kallibrierungstaten wurden mit + * ChatGPT erstellt + * + * Die gesamte bme280.c musste ich selber schreiben, da für meinen sensor keine + * Library existiert hat, mit der nan arbeiten konnte (außer in python) + */ + +// Internsal declerations +void __bme280_16cmd(i2c_inst_t* i2c, uint16_t cmd); +void __bme280_reset(i2c_inst_t* i2c); +bme280_callib __bme280_read_callib(i2c_inst_t* i2c); +void __bme280_read_buf(i2c_inst_t* i2c, uint8_t what, uint8_t* buf, + size_t size); + +// Struct functions + +void update(struct bme280_ctx_s* self) { + uint8_t data[8]; + __bme280_read_buf(self->i2c, 0xf7, data, 8); + self->raw_temperature = + (int32_t)((data[3] << 12) | (data[4] << 4) | (data[5] >> 4)); + self->raw_pressure = + (int32_t)((data[0] << 12) | (data[1] << 4) | (data[2] >> 4)); + self->raw_humidity = (int32_t)((data[6] << 8) | data[7]); +} + +// Berechnen der Temperatur anhand der Kallibrierungsdatan +float read_temp(struct bme280_ctx_s* self) { + int32_t var1 = + ((((self->raw_temperature >> 3) - ((int32_t)self->callib.dig_T1 << 1))) * + ((int32_t)self->callib.dig_T2)) >> + 11; + int32_t var2 = + (((((self->raw_temperature >> 4) - ((int32_t)self->callib.dig_T1)) * + ((self->raw_temperature >> 4) - ((int32_t)self->callib.dig_T1))) >> + 12) * + ((int32_t)self->callib.dig_T3)) >> + 14; + self->t_fine = var1 + var2; + float T = (self->t_fine * 5 + 128) >> 8; + return T / 100.0f; +} + +// Berechnen der Luftfeuchtigkeit anhand der Kallibrierungsdatan +float read_humidity(struct bme280_ctx_s* self) { + int32_t v_x1_u32r = self->t_fine - 76800; + v_x1_u32r = + (((((self->raw_humidity << 14) - (((int32_t)self->callib.dig_H4) << 20) - + (((int32_t)self->callib.dig_H5) * v_x1_u32r)) + + 16384) >> + 15) * + (((((((v_x1_u32r * ((int32_t)self->callib.dig_H6)) >> 10) * + (((v_x1_u32r * ((int32_t)self->callib.dig_H3)) >> 11) + 32768)) >> + 10) + + 2097152) * + ((int32_t)self->callib.dig_H2) + + 8192) >> + 14)); + v_x1_u32r = v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * + ((int32_t)self->callib.dig_H1)) >> + 4); + v_x1_u32r = (v_x1_u32r < 0) ? 0 : v_x1_u32r; + v_x1_u32r = (v_x1_u32r > 419430400) ? 419430400 : v_x1_u32r; + return (float)(v_x1_u32r >> 12) / 1024.0f; +} + +// Berechnen des Luftdrucks? anhand der Kallibrierungsdatan +float read_pressure(struct bme280_ctx_s* self) { + int64_t var1 = ((int64_t)self->t_fine) - 128000; + int64_t var2 = var1 * var1 * (int64_t)self->callib.dig_P6; + var2 = var2 + ((var1 * (int64_t)self->callib.dig_P5) << 17); + var2 = var2 + (((int64_t)self->callib.dig_P4) << 35); + var1 = ((var1 * var1 * (int64_t)self->callib.dig_P3) >> 8) + + ((var1 * (int64_t)self->callib.dig_P2) << 12); + var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)self->callib.dig_P1) >> 33; + + if (var1 == 0) { + return 0; // Vermeidung Division durch Null + } + int64_t p = 1048576 - self->raw_pressure; + p = (((p << 31) - var2) * 3125) / var1; + var1 = (((int64_t)self->callib.dig_P9) * (p >> 13) * (p >> 13)) >> 25; + var2 = (((int64_t)self->callib.dig_P8) * p) >> 19; + p = ((p + var1 + var2) >> 8) + (((int64_t)self->callib.dig_P7) << 4); + return (float)p / 25600.0f; +} + +// public functions +bme280_ctx* bme280_init(i2c_inst_t* i2c, uint sda, uint scl) { + if (!i2c) return NULL; + bme280_ctx* ret = (bme280_ctx*)malloc(sizeof(bme280_ctx)); + if (!ret) return NULL; + // Init I2C and GPIO Pins + i2c_init(i2c, 100 * 1000); + gpio_set_function(sda, GPIO_FUNC_I2C); + gpio_set_function(scl, GPIO_FUNC_I2C); + gpio_pull_up(sda); + gpio_pull_up(scl); + // Setup the Sensor + __bme280_reset(i2c); + ret->callib = __bme280_read_callib(i2c); + __bme280_16cmd(i2c, 0xf201); + __bme280_16cmd(i2c, 0xf427); + __bme280_16cmd(i2c, 0xf5a0); + + ret->update = update; + ret->read_humidity = read_humidity; + ret->read_temp = read_temp; + ret->read_pressure = read_pressure; + + ret->i2c = i2c; + return ret; +} + +void bme280_deinit(bme280_ctx* ctx) { free(ctx); } + +// Internal Functions + +void __bme280_reset(i2c_inst_t* i2c) { + // Reset Command + uint8_t cmd[2] = {0xE0, 0xB6}; + i2c_write_blocking(i2c, BME280_ADDR, cmd, 2, false); + sleep_ms(100); // Wait +} + +bme280_callib __bme280_read_callib(i2c_inst_t* i2c) { + bme280_callib ret; + // Read from sensor + uint8_t buf[0x1a]; // Size 26 + __bme280_read_buf(i2c, 0x88, buf, 0x18); + __bme280_read_buf(i2c, 0xa1, &ret.dig_H1, 1); + uint8_t buf_h[0x7]; + __bme280_read_buf(i2c, 0xe1, buf_h, 7); + + // Get Temp Callib out of Data + ret.dig_T1 = (uint16_t)(buf[1] << 8 | buf[0]); + ret.dig_T2 = (int16_t)(buf[3] << 8 | buf[2]); + ret.dig_T3 = (int16_t)(buf[5] << 8 | buf[4]); + + // Get pressure Data + ret.dig_P1 = (uint16_t)(buf[7] << 8 | buf[6]); + ret.dig_P2 = (int16_t)(buf[9] << 8 | buf[8]); + ret.dig_P3 = (int16_t)(buf[11] << 8 | buf[10]); + ret.dig_P4 = (int16_t)(buf[13] << 8 | buf[12]); + ret.dig_P5 = (int16_t)(buf[15] << 8 | buf[14]); + ret.dig_P6 = (int16_t)(buf[17] << 8 | buf[16]); + ret.dig_P7 = (int16_t)(buf[19] << 8 | buf[18]); + ret.dig_P8 = (int16_t)(buf[21] << 8 | buf[20]); + ret.dig_P9 = (int16_t)(buf[23] << 8 | buf[22]); + + // Get humidity callib data + ret.dig_H2 = (int16_t)(buf_h[1] << 8 | buf_h[0]); + ret.dig_H3 = buf_h[2]; + ret.dig_H4 = (int16_t)((buf_h[3] << 4) | (buf_h[4] & 0x0F)); + ret.dig_H5 = (int16_t)((buf_h[5] << 4) | (buf_h[4] >> 4)); + ret.dig_H6 = (int8_t)buf_h[6]; + return ret; +} + +void __bme280_16cmd(i2c_inst_t* i2c, uint16_t cmd) { + // Could do this as well + // i2c_write_blocking(i2c, BME280_ADDR, (uint8_t*)&cmd, 2, false); + // Simply extracting into a 2byte buffer + uint8_t _cmd[2] = {(cmd >> 8) & 0xFF, cmd & 0xff}; + i2c_write_blocking(i2c, BME280_ADDR, _cmd, 2, false); +} + +void __bme280_read_buf(i2c_inst_t* i2c, uint8_t what, uint8_t* buf, + size_t size) { + i2c_write_blocking(i2c, BME280_ADDR, &what, 1, true); + i2c_read_blocking(i2c, BME280_ADDR, buf, size, false); +} \ No newline at end of file