diff --git a/Sensors.c b/Sensors.c index 80f7243..d35e319 100644 --- a/Sensors.c +++ b/Sensors.c @@ -72,7 +72,7 @@ const Interface ONE_WIRE = { //static const Interface* interfaces[] = {&SINGLE_WIRE, &I2C, &ONE_WIRE}; //Перечень датчиков static const SensorType* sensorTypes[] = - {&DHT11, &DHT12_SW, &DHT21, &DHT22, &AM2320_SW, &AM2320_I2C, &LM75, &BMP280, &Dallas}; + {&DHT11, &DHT12_SW, &DHT21, &DHT22, &AM2320_SW, &AM2320_I2C, &LM75, &BMP280, &BME280, &Dallas}; const SensorType* unitemp_sensors_getTypeFromInt(uint8_t index) { if(index > SENSOR_TYPES_COUNT) return NULL; diff --git a/Sensors.h b/Sensors.h index 52545ec..52e6165 100644 --- a/Sensors.h +++ b/Sensors.h @@ -318,6 +318,7 @@ const GPIO* //DS18x2x #include "./interfaces/OneWireSensor.h" #include "./sensors/LM75.h" -#include "./sensors/BMP280.h" +//BMP280, BME280 +#include "./sensors/BMx280.h" #include "./sensors/AM2320.h" #endif diff --git a/sensors/BMP280.c b/sensors/BMP280.c deleted file mode 100644 index 1be79fc..0000000 --- a/sensors/BMP280.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - Unitemp - Universal temperature reader - Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -#include "BMP280.h" - -const SensorType BMP280 = { - .typename = "BMP280", - .interface = &I2C, - .datatype = UT_DATA_TYPE_TEMP_PRESS, - .pollingInterval = 500, - .allocator = unitemp_BMP280_alloc, - .mem_releaser = unitemp_BMP280_free, - .initializer = unitemp_BMP280_init, - .deinitializer = unitemp_BMP280_deinit, - .updater = unitemp_BMP280_update}; - -//Интервал обновления калибровочных значений -#define BMP280_CAL_UPDATE_INTERVAL 60000 - -#define TEMP_CAL_START_ADDR 0x88 -#define PRESS_CAL_START_ADDR 0x8E -#define BMP280_ID 0x58 - -#define BMP280_REG_STATUS 0xF3 -#define BMP280_REG_CTRL_MEAS 0xF4 -#define BMP280_REG_CONFIG 0xF5 -//Преддескретизация температуры -#define BMP280_TEMP_OVERSAMPLING_SKIP 0b00000000 -#define BMP280_TEMP_OVERSAMPLING_1 0b00100000 -#define BMP280_TEMP_OVERSAMPLING_2 0b01000000 -#define BMP280_TEMP_OVERSAMPLING_4 0b01100000 -#define BMP280_TEMP_OVERSAMPLING_8 0b10000000 -#define BMP280_TEMP_OVERSAMPLING_16 0b10100000 -//Преддескретизация давления -#define BMP280_PRESS_OVERSAMPLING_SKIP 0b00000000 -#define BMP280_PRESS_OVERSAMPLING_1 0b00000100 -#define BMP280_PRESS_OVERSAMPLING_2 0b00001000 -#define BMP280_PRESS_OVERSAMPLING_4 0b00001100 -#define BMP280_PRESS_OVERSAMPLING_8 0b00010000 -#define BMP280_PRESS_OVERSAMPLING_16 0b00010100 -//Режимы работы датчика -#define BMP280_MODE_SLEEP 0b00000000 //Спит и мало кушает -#define BMP280_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон -#define BMP280_MODE_NORMAL 0b00000011 //Регулярно обновляет значения -//Период обновления в нормальном режиме -#define BMP280_STANDBY_TIME_0_5 0b00000000 -#define BMP280_STANDBY_TIME_62_5 0b00100000 -#define BMP280_STANDBY_TIME_125 0b01000000 -#define BMP280_STANDBY_TIME_250 0b01100000 -#define BMP280_STANDBY_TIME_500 0b10000000 -#define BMP280_STANDBY_TIME_1000 0b10100000 -#define BMP280_STANDBY_TIME_2000 0b11000000 -#define BMP280_STANDBY_TIME_4000 0b11100000 -//Коэффициент фильтрации значений -#define BMP280_FILTER_COEFF_1 0b00000000 -#define BMP280_FILTER_COEFF_2 0b00000100 -#define BMP280_FILTER_COEFF_4 0b00001000 -#define BMP280_FILTER_COEFF_8 0b00001100 -#define BMP280_FILTER_COEFF_16 0b00010000 -//Разрешить работу по SPI -#define BMP280_SPI_3W_ENABLE 0b00000001 -#define BMP280_SPI_3W_DISABLE 0b00000000 - -static float bmp280_compensate_T_float(I2CSensor* i2c_sensor, int32_t adc_T) { - BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance; - int32_t var1, var2; - var1 = ((((adc_T >> 3) - ((int32_t)bmp280_instance->temp_cal.dig_T1 << 1))) * - ((int32_t)bmp280_instance->temp_cal.dig_T2)) >> - 11; - var2 = (((((adc_T >> 4) - ((int32_t)bmp280_instance->temp_cal.dig_T1)) * - ((adc_T >> 4) - ((int32_t)bmp280_instance->temp_cal.dig_T1))) >> - 12) * - ((int32_t)bmp280_instance->temp_cal.dig_T3)) >> - 14; - bmp280_instance->t_fine = var1 + var2; - return ((bmp280_instance->t_fine * 5 + 128) >> 8) / 100.0f; -} - -static float bmp280_compensate_P_float(I2CSensor* i2c_sensor, int32_t adc_P) { - BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance; - - int32_t var1, var2; - uint32_t p; - var1 = (((int32_t)bmp280_instance->t_fine) >> 1) - (int32_t)64000; - var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t)bmp280_instance->press_cal.dig_P6); - var2 = var2 + ((var1 * ((int32_t)bmp280_instance->press_cal.dig_P5)) << 1); - var2 = (var2 >> 2) + (((int32_t)bmp280_instance->press_cal.dig_P4) << 16); - var1 = (((bmp280_instance->press_cal.dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + - ((((int32_t)bmp280_instance->press_cal.dig_P2) * var1) >> 1)) >> - 18; - var1 = ((((32768 + var1)) * ((int32_t)bmp280_instance->press_cal.dig_P1)) >> 15); - if(var1 == 0) { - return 0; // avoid exception caused by division by zero - } - p = (((uint32_t)(((int32_t)1048576) - adc_P) - (var2 >> 12))) * 3125; - if(p < 0x80000000) { - p = (p << 1) / ((uint32_t)var1); - } else { - p = (p / (uint32_t)var1) * 2; - } - var1 = (((int32_t)bmp280_instance->press_cal.dig_P9) * - ((int32_t)(((p >> 3) * (p >> 3)) >> 13))) >> - 12; - var2 = (((int32_t)(p >> 2)) * ((int32_t)bmp280_instance->press_cal.dig_P8)) >> 13; - p = (uint32_t)((int32_t)p + ((var1 + var2 + bmp280_instance->press_cal.dig_P7) >> 4)); - return p; -} - -static bool bmp280_readCalValues(I2CSensor* i2c_sensor) { - BMP280_instance* bmp280_instance = (BMP280_instance*)i2c_sensor->sensorInstance; - if(!unitemp_i2c_readRegArray( - i2c_sensor, TEMP_CAL_START_ADDR, 6, (uint8_t*)&bmp280_instance->temp_cal)) - return false; -#ifdef UNITEMP_DEBUG - FURI_LOG_D( - APP_NAME, - "Sensor BMP280 (0x%02X) calibration values: T1: %d, T2: %d, T3: %d", - i2c_sensor->currentI2CAdr, - bmp280_instance->temp_cal.dig_T1, - bmp280_instance->temp_cal.dig_T2, - bmp280_instance->temp_cal.dig_T3); -#endif - - if(!unitemp_i2c_readRegArray( - i2c_sensor, PRESS_CAL_START_ADDR, 18, (uint8_t*)&bmp280_instance->press_cal)) - return false; -#ifdef UNITEMP_DEBUG - FURI_LOG_D( - APP_NAME, - "Sensor BMP280 (0x%02X): P1-9: %d, %d, %d, %d, %d, %d, %d, %d, %d", - i2c_sensor->currentI2CAdr, - bmp280_instance->press_cal.dig_P1, - bmp280_instance->press_cal.dig_P2, - bmp280_instance->press_cal.dig_P3, - bmp280_instance->press_cal.dig_P4, - bmp280_instance->press_cal.dig_P5, - bmp280_instance->press_cal.dig_P6, - bmp280_instance->press_cal.dig_P7, - bmp280_instance->press_cal.dig_P8, - bmp280_instance->press_cal.dig_P9); -#endif - - bmp280_instance->last_cal_update_time = furi_get_tick(); - return true; -} -static bool bmp280_isMeasuring(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - return (bool)((unitemp_i2c_readReg(i2c_sensor, BMP280_REG_STATUS) & 0x08) >> 3); -} - -bool unitemp_BMP280_alloc(Sensor* sensor, char* args) { - UNUSED(args); - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BMP280_instance* bmp280_instance = malloc(sizeof(BMP280_instance)); - if(bmp280_instance == NULL) { - FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name); - return false; - } - i2c_sensor->sensorInstance = bmp280_instance; - - i2c_sensor->minI2CAdr = 0x76 << 1; - i2c_sensor->maxI2CAdr = 0x77 << 1; - return true; -} - -bool unitemp_BMP280_init(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перезагрузка - unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6); - //Чтение ID датчика - uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); - if(id != BMP280_ID) { - FURI_LOG_E( - APP_NAME, - "Sensor %s returned wrong ID 0x%02X, expected 0x%02X", - sensor->name, - id, - BMP280_ID); - return false; - } - - //Чтение калибровочных значений - if(!bmp280_readCalValues(i2c_sensor)) { - FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name); - return false; - } - //Настройка режимов работы - unitemp_i2c_writeReg( - i2c_sensor, - BMP280_REG_CTRL_MEAS, - BMP280_TEMP_OVERSAMPLING_2 | BMP280_PRESS_OVERSAMPLING_4 | BMP280_MODE_NORMAL); - //Настройка периода опроса и фильтрации значений - unitemp_i2c_writeReg( - i2c_sensor, - BMP280_REG_CONFIG, - BMP280_STANDBY_TIME_500 | BMP280_FILTER_COEFF_16 | BMP280_SPI_3W_DISABLE); - - return true; -} - -bool unitemp_BMP280_deinit(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - //Перевод в сон - unitemp_i2c_writeReg(i2c_sensor, BMP280_REG_CTRL_MEAS, BMP280_MODE_SLEEP); - return true; -} - -UnitempStatus unitemp_BMP280_update(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - BMP280_instance* instance = i2c_sensor->sensorInstance; - - uint32_t t = furi_get_tick(); - - if(furi_get_tick() - instance->last_cal_update_time > BMP280_CAL_UPDATE_INTERVAL) { - bmp280_readCalValues(i2c_sensor); - } - - uint8_t buff[3]; - //Проверка инициализированности датчика - unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff); - if(buff[0] == 0) { - FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name); - return UT_SENSORSTATUS_ERROR; - } - - while(bmp280_isMeasuring(sensor)) { - if(furi_get_tick() - t > 100) { - return UT_SENSORSTATUS_TIMEOUT; - } - } - - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFA, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF7, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; - int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); - sensor->temp = bmp280_compensate_T_float(i2c_sensor, adc_T); - sensor->pressure = bmp280_compensate_P_float(i2c_sensor, adc_P); - return UT_SENSORSTATUS_OK; -} - -bool unitemp_BMP280_free(Sensor* sensor) { - I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; - free(i2c_sensor->sensorInstance); - return true; -} \ No newline at end of file diff --git a/sensors/BMx280.c b/sensors/BMx280.c new file mode 100644 index 0000000..a64daaa --- /dev/null +++ b/sensors/BMx280.c @@ -0,0 +1,352 @@ +/* + Unitemp - Universal temperature reader + Copyright (C) 2022 Victor Nikitchuk (https://github.com/quen0n) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +#include "BMx280.h" + +const SensorType BMP280 = { + .typename = "BMP280", + .interface = &I2C, + .datatype = UT_TEMPERATURE | UT_PRESSURE, + .pollingInterval = 500, + .allocator = unitemp_BMx280_alloc, + .mem_releaser = unitemp_BMx280_free, + .initializer = unitemp_BMx280_init, + .deinitializer = unitemp_BMx280_deinit, + .updater = unitemp_BMx280_update}; +const SensorType BME280 = { + .typename = "BME280", + .interface = &I2C, + .datatype = UT_TEMPERATURE | UT_HUMIDITY | UT_PRESSURE, + + .pollingInterval = 500, + .allocator = unitemp_BMx280_alloc, + .mem_releaser = unitemp_BMx280_free, + .initializer = unitemp_BMx280_init, + .deinitializer = unitemp_BMx280_deinit, + .updater = unitemp_BMx280_update}; + +//Интервал обновления калибровочных значений +#define BOSCH_CAL_UPDATE_INTERVAL 60000 + +#define TEMP_CAL_START_ADDR 0x88 +#define PRESS_CAL_START_ADDR 0x8E +#define HUM_CAL_H1_ADDR 0xA1 +#define HUM_CAL_H2_ADDR 0xE1 + +#define BMP280_ID 0x58 +#define BME280_ID 0x60 + +#define BMx280_I2C_ADDR_MIN (0x76 << 1) +#define BMx280_I2C_ADDR_MAX (0x77 << 1) + +#define BMx280_REG_STATUS 0xF3 +#define BMx280_REG_CTRL_MEAS 0xF4 +#define BMx280_REG_CONFIG 0xF5 +#define BME280_REG_CTRL_HUM 0xF2 +//Преддескретизация температуры +#define BMx280_TEMP_OVERSAMPLING_SKIP 0b00000000 +#define BMx280_TEMP_OVERSAMPLING_1 0b00100000 +#define BMx280_TEMP_OVERSAMPLING_2 0b01000000 +#define BMx280_TEMP_OVERSAMPLING_4 0b01100000 +#define BMx280_TEMP_OVERSAMPLING_8 0b10000000 +#define BMx280_TEMP_OVERSAMPLING_16 0b10100000 +//Преддескретизация давления +#define BMx280_PRESS_OVERSAMPLING_SKIP 0b00000000 +#define BMx280_PRESS_OVERSAMPLING_1 0b00000100 +#define BMx280_PRESS_OVERSAMPLING_2 0b00001000 +#define BMx280_PRESS_OVERSAMPLING_4 0b00001100 +#define BMx280_PRESS_OVERSAMPLING_8 0b00010000 +#define BMx280_PRESS_OVERSAMPLING_16 0b00010100 +//Преддескретизация влажности +#define BME280_HUM_OVERSAMPLING_SKIP 0b00000000 +#define BME280_HUM_OVERSAMPLING_1 0b00000001 +#define BME280_HUM_OVERSAMPLING_2 0b00000010 +#define BME280_HUM_OVERSAMPLING_4 0b00000011 +#define BME280_HUM_OVERSAMPLING_8 0b00000100 +#define BME280_HUM_OVERSAMPLING_16 0b00000101u +//Режимы работы датчика +#define BMx280_MODE_SLEEP 0b00000000 //Наелся и спит +#define BMx280_MODE_FORCED 0b00000001 //Обновляет значения 1 раз, после чего уходит в сон +#define BMx280_MODE_NORMAL 0b00000011 //Регулярно обновляет значения +//Период обновления в нормальном режиме +#define BMx280_STANDBY_TIME_0_5 0b00000000 +#define BMx280_STANDBY_TIME_62_5 0b00100000 +#define BMx280_STANDBY_TIME_125 0b01000000 +#define BMx280_STANDBY_TIME_250 0b01100000 +#define BMx280_STANDBY_TIME_500 0b10000000 +#define BMx280_STANDBY_TIME_1000 0b10100000 +#define BMx280_STANDBY_TIME_2000 0b11000000 +#define BMx280_STANDBY_TIME_4000 0b11100000 +//Коэффициент фильтрации значений +#define BMx280_FILTER_COEFF_1 0b00000000 +#define BMx280_FILTER_COEFF_2 0b00000100 +#define BMx280_FILTER_COEFF_4 0b00001000 +#define BMx280_FILTER_COEFF_8 0b00001100 +#define BMx280_FILTER_COEFF_16 0b00010000 +//Разрешить работу по SPI +#define BMx280_SPI_3W_ENABLE 0b00000001 +#define BMx280_SPI_3W_DISABLE 0b00000000 + +static float BMx280_compensate_temperature(I2CSensor* i2c_sensor, int32_t adc_T) { + BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; + int32_t var1, var2; + var1 = ((((adc_T >> 3) - ((int32_t)bmx280_instance->temp_cal.dig_T1 << 1))) * + ((int32_t)bmx280_instance->temp_cal.dig_T2)) >> + 11; + var2 = (((((adc_T >> 4) - ((int32_t)bmx280_instance->temp_cal.dig_T1)) * + ((adc_T >> 4) - ((int32_t)bmx280_instance->temp_cal.dig_T1))) >> + 12) * + ((int32_t)bmx280_instance->temp_cal.dig_T3)) >> + 14; + bmx280_instance->t_fine = var1 + var2; + return ((bmx280_instance->t_fine * 5 + 128) >> 8) / 100.0f; +} + +static float BMx280_compensate_pressure(I2CSensor* i2c_sensor, int32_t adc_P) { + BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; + + int32_t var1, var2; + uint32_t p; + var1 = (((int32_t)bmx280_instance->t_fine) >> 1) - (int32_t)64000; + var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t)bmx280_instance->press_cal.dig_P6); + var2 = var2 + ((var1 * ((int32_t)bmx280_instance->press_cal.dig_P5)) << 1); + var2 = (var2 >> 2) + (((int32_t)bmx280_instance->press_cal.dig_P4) << 16); + var1 = (((bmx280_instance->press_cal.dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + + ((((int32_t)bmx280_instance->press_cal.dig_P2) * var1) >> 1)) >> + 18; + var1 = ((((32768 + var1)) * ((int32_t)bmx280_instance->press_cal.dig_P1)) >> 15); + if(var1 == 0) { + return 0; // avoid exception caused by division by zero + } + p = (((uint32_t)(((int32_t)1048576) - adc_P) - (var2 >> 12))) * 3125; + if(p < 0x80000000) { + p = (p << 1) / ((uint32_t)var1); + } else { + p = (p / (uint32_t)var1) * 2; + } + var1 = (((int32_t)bmx280_instance->press_cal.dig_P9) * + ((int32_t)(((p >> 3) * (p >> 3)) >> 13))) >> + 12; + var2 = (((int32_t)(p >> 2)) * ((int32_t)bmx280_instance->press_cal.dig_P8)) >> 13; + p = (uint32_t)((int32_t)p + ((var1 + var2 + bmx280_instance->press_cal.dig_P7) >> 4)); + return p; +} + +static float BMx280_compensate_humidity(I2CSensor* i2c_sensor, int32_t adc_H) { + BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; + int32_t v_x1_u32r; + v_x1_u32r = (bmx280_instance->t_fine - ((int32_t)76800)); + + v_x1_u32r = + (((((adc_H << 14) - (((int32_t)bmx280_instance->hum_cal.dig_H4) << 20) - + (((int32_t)bmx280_instance->hum_cal.dig_H5) * v_x1_u32r)) + + ((int32_t)16384)) >> + 15) * + (((((((v_x1_u32r * ((int32_t)bmx280_instance->hum_cal.dig_H6)) >> 10) * + (((v_x1_u32r * ((int32_t)bmx280_instance->hum_cal.dig_H3)) >> 11) + + ((int32_t)32768))) >> + 10) + + ((int32_t)2097152)) * + ((int32_t)bmx280_instance->hum_cal.dig_H2) + + 8192) >> + 14)); + + v_x1_u32r = + (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * + ((int32_t)bmx280_instance->hum_cal.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 ((uint32_t)(v_x1_u32r >> 12)) / 1024.0f; +} + +static bool bmx280_readCalValues(I2CSensor* i2c_sensor) { + BMx280_instance* bmx280_instance = (BMx280_instance*)i2c_sensor->sensorInstance; + if(!unitemp_i2c_readRegArray( + i2c_sensor, TEMP_CAL_START_ADDR, 6, (uint8_t*)&bmx280_instance->temp_cal)) + return false; +#ifdef UNITEMP_DEBUG + FURI_LOG_D( + APP_NAME, + "Sensor BMx280 (0x%02X) T1-T3: %d, %d, %d", + i2c_sensor->currentI2CAdr, + bmx280_instance->temp_cal.dig_T1, + bmx280_instance->temp_cal.dig_T2, + bmx280_instance->temp_cal.dig_T3); +#endif + + if(!unitemp_i2c_readRegArray( + i2c_sensor, PRESS_CAL_START_ADDR, 18, (uint8_t*)&bmx280_instance->press_cal)) + return false; +#ifdef UNITEMP_DEBUG + FURI_LOG_D( + APP_NAME, + "Sensor BMx280 (0x%02X): P1-P9: %d, %d, %d, %d, %d, %d, %d, %d, %d", + i2c_sensor->currentI2CAdr, + bmx280_instance->press_cal.dig_P1, + bmx280_instance->press_cal.dig_P2, + bmx280_instance->press_cal.dig_P3, + bmx280_instance->press_cal.dig_P4, + bmx280_instance->press_cal.dig_P5, + bmx280_instance->press_cal.dig_P6, + bmx280_instance->press_cal.dig_P7, + bmx280_instance->press_cal.dig_P8, + bmx280_instance->press_cal.dig_P9); +#endif + + if(bmx280_instance->chip_id == BME280_ID) { + uint8_t buff[7] = {0}; + if(!unitemp_i2c_readRegArray(i2c_sensor, HUM_CAL_H1_ADDR, 1, buff)) return false; + bmx280_instance->hum_cal.dig_H1 = buff[0]; + + if(!unitemp_i2c_readRegArray(i2c_sensor, HUM_CAL_H2_ADDR, 7, buff)) return false; + bmx280_instance->hum_cal.dig_H2 = (uint16_t)(buff[0] | ((uint16_t)buff[1] << 8)); + bmx280_instance->hum_cal.dig_H3 = buff[2]; + bmx280_instance->hum_cal.dig_H4 = ((int16_t)buff[3] << 4) | (buff[4] & 0x0F); + bmx280_instance->hum_cal.dig_H5 = (buff[4] & 0x0F) | ((int16_t)buff[5] << 4); + bmx280_instance->hum_cal.dig_H6 = buff[6]; + +#ifdef UNITEMP_DEBUG + FURI_LOG_D( + APP_NAME, + "Sensor BMx280 (0x%02X): H1-H6: %d, %d, %d, %d, %d, %d", + i2c_sensor->currentI2CAdr, + bmx280_instance->hum_cal.dig_H1, + bmx280_instance->hum_cal.dig_H2, + bmx280_instance->hum_cal.dig_H3, + bmx280_instance->hum_cal.dig_H4, + bmx280_instance->hum_cal.dig_H5, + bmx280_instance->hum_cal.dig_H6); +#endif + } + + bmx280_instance->last_cal_update_time = furi_get_tick(); + return true; +} +static bool bmp280_isMeasuring(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + return (bool)((unitemp_i2c_readReg(i2c_sensor, BMx280_REG_STATUS) & 0x08) >> 3); +} + +bool unitemp_BMx280_alloc(Sensor* sensor, char* args) { + UNUSED(args); + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + BMx280_instance* bmx280_instance = malloc(sizeof(BMx280_instance)); + if(bmx280_instance == NULL) { + FURI_LOG_E(APP_NAME, "Failed to allocation sensor %s instance", sensor->name); + return false; + } + + if(sensor->type == &BMP280) bmx280_instance->chip_id = BMP280_ID; + if(sensor->type == &BME280) bmx280_instance->chip_id = BME280_ID; + + i2c_sensor->sensorInstance = bmx280_instance; + + i2c_sensor->minI2CAdr = BMx280_I2C_ADDR_MIN; + i2c_sensor->maxI2CAdr = BMx280_I2C_ADDR_MAX; + return true; +} + +bool unitemp_BMx280_init(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + //Перезагрузка + unitemp_i2c_writeReg(i2c_sensor, 0xE0, 0xB6); + //Чтение ID датчика + uint8_t id = unitemp_i2c_readReg(i2c_sensor, 0xD0); + if(id != BMP280_ID && id != BME280_ID) { + FURI_LOG_E( + APP_NAME, + "Sensor %s returned wrong ID 0x%02X, expected 0x%02X or 0x%02X", + sensor->name, + id, + BMP280_ID, + BME280_ID); + return false; + } + + //Настройка режимов работы + if(id == BME280_ID) { + unitemp_i2c_writeReg(i2c_sensor, BME280_REG_CTRL_HUM, BME280_HUM_OVERSAMPLING_1); + unitemp_i2c_writeReg( + i2c_sensor, BME280_REG_CTRL_HUM, unitemp_i2c_readReg(i2c_sensor, BME280_REG_CTRL_HUM)); + } + unitemp_i2c_writeReg( + i2c_sensor, + BMx280_REG_CTRL_MEAS, + BMx280_TEMP_OVERSAMPLING_2 | BMx280_PRESS_OVERSAMPLING_4 | BMx280_MODE_NORMAL); + //Настройка периода опроса и фильтрации значений + unitemp_i2c_writeReg( + i2c_sensor, + BMx280_REG_CONFIG, + BMx280_STANDBY_TIME_500 | BMx280_FILTER_COEFF_16 | BMx280_SPI_3W_DISABLE); + //Чтение калибровочных значений + if(!bmx280_readCalValues(i2c_sensor)) { + FURI_LOG_E(APP_NAME, "Failed to read calibration values sensor %s", sensor->name); + return false; + } + return true; +} + +bool unitemp_BMx280_deinit(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + //Перевод в сон + unitemp_i2c_writeReg(i2c_sensor, BMx280_REG_CTRL_MEAS, BMx280_MODE_SLEEP); + return true; +} + +UnitempStatus unitemp_BMx280_update(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + BMx280_instance* instance = i2c_sensor->sensorInstance; + + uint32_t t = furi_get_tick(); + + uint8_t buff[3]; + //Проверка инициализированности датчика + unitemp_i2c_readRegArray(i2c_sensor, 0xF4, 2, buff); + if(buff[0] == 0) { + FURI_LOG_W(APP_NAME, "Sensor %s is not initialized!", sensor->name); + return UT_SENSORSTATUS_ERROR; + } + + while(bmp280_isMeasuring(sensor)) { + if(furi_get_tick() - t > 100) { + return UT_SENSORSTATUS_TIMEOUT; + } + } + + if(furi_get_tick() - instance->last_cal_update_time > BOSCH_CAL_UPDATE_INTERVAL) { + bmx280_readCalValues(i2c_sensor); + } + + if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFA, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; + int32_t adc_T = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); + if(!unitemp_i2c_readRegArray(i2c_sensor, 0xF7, 3, buff)) return UT_SENSORSTATUS_TIMEOUT; + int32_t adc_P = ((int32_t)buff[0] << 12) | ((int32_t)buff[1] << 4) | ((int32_t)buff[2] >> 4); + if(!unitemp_i2c_readRegArray(i2c_sensor, 0xFD, 2, buff)) return UT_SENSORSTATUS_TIMEOUT; + int32_t adc_H = ((uint16_t)buff[0] << 8) | buff[1]; + sensor->temp = BMx280_compensate_temperature(i2c_sensor, adc_T); + sensor->pressure = BMx280_compensate_pressure(i2c_sensor, adc_P); + sensor->hum = BMx280_compensate_humidity(i2c_sensor, adc_H); + return UT_SENSORSTATUS_OK; +} + +bool unitemp_BMx280_free(Sensor* sensor) { + I2CSensor* i2c_sensor = (I2CSensor*)sensor->instance; + free(i2c_sensor->sensorInstance); + return true; +} \ No newline at end of file diff --git a/sensors/BMP280.h b/sensors/BMx280.h similarity index 76% rename from sensors/BMP280.h rename to sensors/BMx280.h index 3650909..fe52a36 100644 --- a/sensors/BMP280.h +++ b/sensors/BMx280.h @@ -15,8 +15,9 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -#ifndef UNITEMP_BMP280 -#define UNITEMP_BMP280 +#ifndef UNITEMP_BMx280 +#define UNITEMP_BMx280 + #include "../unitemp.h" #include "../Sensors.h" #include "../interfaces/I2CSensor.h" @@ -25,7 +26,7 @@ typedef struct { uint16_t dig_T1; int16_t dig_T2; int16_t dig_T3; -} BMP280_temp_cal; +} BMx280_temp_cal; typedef struct { uint16_t dig_P1; @@ -37,51 +38,65 @@ typedef struct { int16_t dig_P7; int16_t dig_P8; int16_t dig_P9; -} BMP280_press_cal; +} BMx280_press_cal; + +typedef struct { + uint8_t dig_H1; + int16_t dig_H2; + uint8_t dig_H3; + int16_t dig_H4; + int16_t dig_H5; + int8_t dig_H6; +} BMx280_hum_cal; typedef struct { //Калибровочные значения температуры - BMP280_temp_cal temp_cal; + BMx280_temp_cal temp_cal; //Калибровочные значения давления - BMP280_press_cal press_cal; + BMx280_press_cal press_cal; + //Калибровочные значения влажности воздуха + BMx280_hum_cal hum_cal; //Время последнего обновления калибровочных значений uint32_t last_cal_update_time; + //Индификатор датчика + uint8_t chip_id; //Корректировочное значение температуры int32_t t_fine; -} BMP280_instance; +} BMx280_instance; extern const SensorType BMP280; +extern const SensorType BME280; /** * @brief Выделение памяти и установка начальных значений датчика BMP280 * @param sensor Указатель на создаваемый датчик * @return Истина при успехе */ -bool unitemp_BMP280_alloc(Sensor* sensor, char* args); +bool unitemp_BMx280_alloc(Sensor* sensor, char* args); /** * @brief Инициализации датчика BMP280 * @param sensor Указатель на датчик * @return Истина если инициализация упспешная */ -bool unitemp_BMP280_init(Sensor* sensor); +bool unitemp_BMx280_init(Sensor* sensor); /** * @brief Деинициализация датчика * @param sensor Указатель на датчик */ -bool unitemp_BMP280_deinit(Sensor* sensor); +bool unitemp_BMx280_deinit(Sensor* sensor); /** * @brief Обновление значений из датчика * @param sensor Указатель на датчик * @return Статус опроса датчика */ -UnitempStatus unitemp_BMP280_update(Sensor* sensor); +UnitempStatus unitemp_BMx280_update(Sensor* sensor); /** * @brief Высвободить память датчика * @param sensor Указатель на датчик */ -bool unitemp_BMP280_free(Sensor* sensor); +bool unitemp_BMx280_free(Sensor* sensor); #endif \ No newline at end of file diff --git a/views/General_view.c b/views/General_view.c index 456ccb2..e21b04d 100644 --- a/views/General_view.c +++ b/views/General_view.c @@ -364,8 +364,8 @@ static void _draw_carousel_info(Canvas* canvas) { ((I2CSensor*)unitemp_sensor_getActive(generalview_sensor_index)->instance) ->currentI2CAdr); canvas_draw_str(canvas, 57, 35, app->buff); - canvas_draw_str(canvas, 54, 46, "16 (C1)"); - canvas_draw_str(canvas, 54, 58, "15 (C0)"); + canvas_draw_str(canvas, 54, 46, "15 (C0)"); + canvas_draw_str(canvas, 54, 58, "16 (C1)"); } } static void _draw_view_sensorsCarousel(Canvas* canvas) {