BME280

Strannic1924
Offline
Зарегистрирован: 30.08.2016

Может кто из гуру подскажет...

Но, помоему, какая -то мудренная схема подключения у Вас..

1. Всегда подключал датчик BME280 без подтягивающих резисторов и конденсаторов, т.к. это все дело есть в плате датчика (стабилизатор напряжения), к примеру вид подключения датчика bmp180 http://adatum.ru/podklyuchenie-tsifrovogo-barometra-bmp180-k-arduino.html

2. Прошивку в формате hex, вряд ли кто то будет ковырять, а вот скетч, в формате ino, могли бы посмотреть. 

3. Попробуйте подключить один датчик bme 280  без всяких прибамбасов, залить тестовый скетч и проверить показания датчика в мониторе порта, к примеру...

#include <Wire.h>

#define BME280_ADDRESS 0x76
unsigned long int hum_raw,temp_raw,pres_raw;
signed long int t_fine;

uint16_t dig_T1;
 int16_t dig_T2;
 int16_t dig_T3;
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;
 int8_t  dig_H1;
 int16_t dig_H2;
 int8_t  dig_H3;
 int16_t dig_H4;
 int16_t dig_H5;
 int8_t  dig_H6;

void setup()
{
    uint8_t osrs_t = 1;             //Temperature oversampling x 1
    uint8_t osrs_p = 1;             //Pressure oversampling x 1
    uint8_t osrs_h = 1;             //Humidity oversampling x 1
    uint8_t mode = 3;               //Normal mode
    uint8_t t_sb = 5;               //Tstandby 1000ms
    uint8_t filter = 0;             //Filter off 
    uint8_t spi3w_en = 0;           //3-wire SPI Disable
    
    uint8_t ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode;
    uint8_t config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en;
    uint8_t ctrl_hum_reg  = osrs_h;
    
    Serial.begin(9600);
    Wire.begin();
    
    writeReg(0xF2,ctrl_hum_reg);
    writeReg(0xF4,ctrl_meas_reg);
    writeReg(0xF5,config_reg);
    readTrim();                    //
}


void loop()
{
    double temp_act = 0.0, press_act = 0.0,hum_act=0.0;
    signed long int temp_cal;
    unsigned long int press_cal,hum_cal;
    
    readData();
    
    temp_cal = calibration_T(temp_raw);
    press_cal = calibration_P(pres_raw);
    hum_cal = calibration_H(hum_raw);
    temp_act = (double)temp_cal / 100.0;
    press_act = (double)press_cal / 100.0;
    hum_act = (double)hum_cal / 1024.0;
    Serial.print("TEMP : ");
    Serial.print(temp_act);
    Serial.print(" DegC  PRESS : ");
    Serial.print(press_act);
    Serial.print(" hPa  HUM : ");
    Serial.print(hum_act);
    Serial.println(" %");    
    
    delay(1000);
}
void readTrim()
{
    uint8_t data[32],i=0;
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0x88);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,24);
    while(Wire.available()){
        data[i] = Wire.read();
        i++;
    }
    
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0xA1);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,1);
    data[i] = Wire.read();
    i++;
    
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0xE1);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,7);
    while(Wire.available()){
        data[i] = Wire.read();
        i++;    
    }
    dig_T1 = (data[1] << 8) | data[0];
    dig_T2 = (data[3] << 8) | data[2];
    dig_T3 = (data[5] << 8) | data[4];
    dig_P1 = (data[7] << 8) | data[6];
    dig_P2 = (data[9] << 8) | data[8];
    dig_P3 = (data[11]<< 8) | data[10];
    dig_P4 = (data[13]<< 8) | data[12];
    dig_P5 = (data[15]<< 8) | data[14];
    dig_P6 = (data[17]<< 8) | data[16];
    dig_P7 = (data[19]<< 8) | data[18];
    dig_P8 = (data[21]<< 8) | data[20];
    dig_P9 = (data[23]<< 8) | data[22];
    dig_H1 = data[24];
    dig_H2 = (data[26]<< 8) | data[25];
    dig_H3 = data[27];
    dig_H4 = (data[28]<< 4) | (0x0F & data[29]);
    dig_H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F);
    dig_H6 = data[31];   
}
void writeReg(uint8_t reg_address, uint8_t data)
{
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(reg_address);
    Wire.write(data);
    Wire.endTransmission();    
}


void readData()
{
    int i = 0;
    uint32_t data[8];
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0xF7);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,8);
    while(Wire.available()){
        data[i] = Wire.read();
        i++;
    }
    pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
    temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
    hum_raw  = (data[6] << 8) | data[7];
}


signed long int calibration_T(signed long int adc_T)
{
    
    signed long int var1, var2, T;
    var1 = ((((adc_T >> 3) - ((signed long int)dig_T1<<1))) * ((signed long int)dig_T2)) >> 11;
    var2 = (((((adc_T >> 4) - ((signed long int)dig_T1)) * ((adc_T>>4) - ((signed long int)dig_T1))) >> 12) * ((signed long int)dig_T3)) >> 14;
    
    t_fine = var1 + var2;
    T = (t_fine * 5 + 128) >> 8;
    return T; 
}

unsigned long int calibration_P(signed long int adc_P)
{
    signed long int var1, var2;
    unsigned long int P;
    var1 = (((signed long int)t_fine)>>1) - (signed long int)64000;
    var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed long int)dig_P6);
    var2 = var2 + ((var1*((signed long int)dig_P5))<<1);
    var2 = (var2>>2)+(((signed long int)dig_P4)<<16);
    var1 = (((dig_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((signed long int)dig_P2) * var1)>>1))>>18;
    var1 = ((((32768+var1))*((signed long int)dig_P1))>>15);
    if (var1 == 0)
    {
        return 0;
    }    
    P = (((unsigned long int)(((signed long int)1048576)-adc_P)-(var2>>12)))*3125;
    if(P<0x80000000)
    {
       P = (P << 1) / ((unsigned long int) var1);   
    }
    else
    {
        P = (P / (unsigned long int)var1) * 2;    
    }
    var1 = (((signed long int)dig_P9) * ((signed long int)(((P>>3) * (P>>3))>>13)))>>12;
    var2 = (((signed long int)(P>>2)) * ((signed long int)dig_P8))>>13;
    P = (unsigned long int)((signed long int)P + ((var1 + var2 + dig_P7) >> 4));
    return P;
}

unsigned long int calibration_H(signed long int adc_H)
{
    signed long int v_x1;
    
    v_x1 = (t_fine - ((signed long int)76800));
    v_x1 = (((((adc_H << 14) -(((signed long int)dig_H4) << 20) - (((signed long int)dig_H5) * v_x1)) + 
              ((signed long int)16384)) >> 15) * (((((((v_x1 * ((signed long int)dig_H6)) >> 10) * 
              (((v_x1 * ((signed long int)dig_H3)) >> 11) + ((signed long int) 32768))) >> 10) + (( signed long int)2097152)) * 
              ((signed long int) dig_H2) + 8192) >> 14));
   v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((signed long int)dig_H1)) >> 4));
   v_x1 = (v_x1 < 0 ? 0 : v_x1);
   v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1);
   return (unsigned long int)(v_x1 >> 12);   
}

DeVit
Offline
Зарегистрирован: 07.06.2016

AlexRat пишет:

1. Про защиту от осадков пока вопос открытый пока использую просто пластиковый контейнер с мелкими дырочками для вентиляции. Насекомых думаю не стоит особо опасаться. Особенно на 6-м этаже. У нас их тут в принципе мало.

2. Схему подключения нарисовал. Правда в библиотеке не было моего модуля. Поставил какой был. У меня такой. На нём явно есть стабилизатор. Значит питать можно от 5 вольт. Скетч прилагаю.

3. Провода обычные... Для макетки. Вот фото в сборе.

4. Вообще конечно погрешность грустная. Вряд ли такой модуль подходит для уличного термометра...

Я извиняюсь, а не подскажете скетч у Вас в чём?

Просто как то привык что скетч идёт с .ino на конце.

P.S. из архива распаковал.

AlexRat
Offline
Зарегистрирован: 23.04.2017

DeVit пишет:

Я извиняюсь, а не подскажете скетч у Вас в чём?

Просто как то привык что скетч идёт с .ino на конце.

P.S. из архива распаковал.

Этот скетч я делал для PlatformIO. Довольно удобная среда для программирования. Ardiuino IDE как IDE всё-таки совершено убог. Где-то в прошлом веке остался. Примерно в его начале

AlexRat
Offline
Зарегистрирован: 23.04.2017

Strannic1924 пишет:

1. Всегда подключал датчик BME280 без подтягивающих резисторов и конденсаторов, т.к. это все дело есть в плате датчика (стабилизатор напряжения), к примеру вид подключения датчика bmp180 http://adatum.ru/podklyuchenie-tsifrovogo-barometra-bmp180-k-arduino.html

2. Прошивку в формате hex, вряд ли кто то будет ковырять, а вот скетч, в формате ino, могли бы посмотреть. 

1. Попробую без подтягивающих сопротивлений.

2. А где hex? Я выложил чистый С++

AlexRat
Offline
Зарегистрирован: 23.04.2017

Ну и потом. Разве может помешать кондесатор на питании? Подтягивающие резисторы на шине i2c? Какое они могут оказать влияние на измерения датчика? Что даст проверка показаний в мониторе порта? Показания идут. С этим проблем нет. Вопрос в том как проверить их правильность?

Strannic1924
Offline
Зарегистрирован: 30.08.2016

AlexRat пишет:

Ну и потом. Разве может помешать кондесатор на питании? Подтягивающие резисторы на шине i2c? Какое они могут оказать влияние на измерения датчика? Что даст проверка показаний в мониторе порта? Показания идут. С этим проблем нет. Вопрос в том как проверить их правильность?

Вот Вы и проверьте, с показаниями обычного ртутного термометра...

Strannic1924
Offline
Зарегистрирован: 30.08.2016

AlexRat пишет:

Strannic1924 пишет:

1. Всегда подключал датчик BME280 без подтягивающих резисторов и конденсаторов, т.к. это все дело есть в плате датчика (стабилизатор напряжения), к примеру вид подключения датчика bmp180 http://adatum.ru/podklyuchenie-tsifrovogo-barometra-bmp180-k-arduino.html

2. Прошивку в формате hex, вряд ли кто то будет ковырять, а вот скетч, в формате ino, могли бы посмотреть. 

1. Попробую без подтягивающих сопротивлений.

2. А где hex? Я выложил чистый С++

В архиве, в папке , у меня такой путь,   C:\Users\Комп\Downloads\radio_3\radio_3\.pioenvs\nanoatmega328\firmware.hex

ulis
ulis аватар
Offline
Зарегистрирован: 09.03.2011

ЕвгенийП пишет:

Ну, Вы знаете, людям свойственно приписывать всему старому самые замечательные свойства :)

Если бы Вы часто бывали на хоккейных стадионах и были бы примерно моего возрата, то наверняка согласились бы с моим мнением: "Вот лет сорок назад ... и лёд блестел ярче, и шайбы лучше скользили, и девки на трибунах пофигуристее были" :)

Ностальгия - признак молодости

PM007
Offline
Зарегистрирован: 09.05.2016

С температурой все понятно, а вот как проверить правильность показания влажности... У меня три латчика, правдва все китайские, показывают три разных значения :)

AlexRat
Offline
Зарегистрирован: 23.04.2017

Strannic1924 пишет:

В архиве, в папке , у меня такой путь,   C:\Users\Комп\Downloads\radio_3\radio_3\.pioenvs\nanoatmega328\firmware.hex

Пардон, просто упаковал всю папку, забыл, что он там скомпилированные прошивки держит :)

То есть вы полагаете, что проблема в библиотеке?

Strannic1924
Offline
Зарегистрирован: 30.08.2016

PM007 пишет:

С температурой все понятно, а вот как проверить правильность показания влажности... У меня три латчика, правдва все китайские, показывают три разных значения :)

У разных датчиков - разная погрешность и диапазон измерений...

Как вариант, узнайте телефон местной (городской) метеостанции, запросите у них значения относительной влажности для вашего населенного пункта и проведите замеры относительной влажности рядом с вашей метеостанцией...

Strannic1924
Offline
Зарегистрирован: 30.08.2016

AlexRat пишет:

Strannic1924 пишет:

В архиве, в папке , у меня такой путь,   C:\Users\Комп\Downloads\radio_3\radio_3\.pioenvs\nanoatmega328\firmware.hex

Пардон, просто упаковал всю папку, забыл, что он там скомпилированные прошивки держит :)

То есть вы полагаете, что проблема в библиотеке?

Я собственно, не Гуру, а новичок в данной области.

Просто, если Вы выложите конкректный скетч в формате ino, шансы, что Вам помогут возрастают...

AlexRat
Offline
Зарегистрирован: 23.04.2017

Strannic1924 пишет:

Просто, если Вы выложите конкректный скетч в формате ino, шансы, что Вам помогут возрастают...

Переконвертировал в ino :)

Strannic1924
Offline
Зарегистрирован: 30.08.2016

Ваш скетч

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <printf.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <AM2320.h>
#include "LED.h"

Adafruit_BME280 bme;
AM2320 am2320;

#define DHT_INTERVAL_CHECK 10000
#define DHT_RESPONSE_OK 1
#define DHT_RESPONSE_ERROR 0

#define MODULE_ID 0x04
#define SENSOR1_ID 14
#define SENSOR1_TYPE 0x01
#define SENSOR2_ID 15
#define SENSOR2_TYPE 0x02
#define SENSOR3_ID 16
#define SENSOR3_TYPE 0x03
#define SENSOR4_ID 19
#define SENSOR4_TYPE 0x01
#define SENSOR5_ID 20
#define SENSOR5_TYPE 0x02
#define RADIO_INTERVAL 100

struct sensor_data {
    unsigned char   sensor_id;
    unsigned char   sensor_type;
    unsigned short  value;
};

struct message_header {
    unsigned char module_id;
    unsigned char message_number;
    unsigned char message_type;
    unsigned char crc;
    unsigned long timestamp;
};

struct message {
    struct message_header header;
    struct sensor_data sensors[6];
};

struct meteo_info {
  unsigned long time;
  byte state;
  float temperature;
  float humidity;
  float temperature2;
  float humidity2;
  float pressure;
};

struct meteo_info info;
unsigned long lastReadTime = 0;
unsigned long now = 0;
unsigned char message_num = 0;
unsigned long checkInterval = DHT_INTERVAL_CHECK;

#define BUFFER_SIZE 32
RF24 radio(9, 10);
unsigned char buffer[BUFFER_SIZE];
const uint64_t pipe = 0x0601170001LL;
unsigned long restart_time = 0;
unsigned long last_sent_time = 0;
unsigned int radio_error_counter = 0;
LED led_power(2);
LED led_send(3);
LED led_error(4);
int pinDebug = 5;
bool debugMode = false;

const unsigned char crc8Table[256] = {
    0x00, 0x31, 0x62, 0x53, 0xC4, 0xF5, 0xA6, 0x97,
    0xB9, 0x88, 0xDB, 0xEA, 0x7D, 0x4C, 0x1F, 0x2E,
    0x43, 0x72, 0x21, 0x10, 0x87, 0xB6, 0xE5, 0xD4,
    0xFA, 0xCB, 0x98, 0xA9, 0x3E, 0x0F, 0x5C, 0x6D,
    0x86, 0xB7, 0xE4, 0xD5, 0x42, 0x73, 0x20, 0x11,
    0x3F, 0x0E, 0x5D, 0x6C, 0xFB, 0xCA, 0x99, 0xA8,
    0xC5, 0xF4, 0xA7, 0x96, 0x01, 0x30, 0x63, 0x52,
    0x7C, 0x4D, 0x1E, 0x2F, 0xB8, 0x89, 0xDA, 0xEB,
    0x3D, 0x0C, 0x5F, 0x6E, 0xF9, 0xC8, 0x9B, 0xAA,
    0x84, 0xB5, 0xE6, 0xD7, 0x40, 0x71, 0x22, 0x13,
    0x7E, 0x4F, 0x1C, 0x2D, 0xBA, 0x8B, 0xD8, 0xE9,
    0xC7, 0xF6, 0xA5, 0x94, 0x03, 0x32, 0x61, 0x50,
    0xBB, 0x8A, 0xD9, 0xE8, 0x7F, 0x4E, 0x1D, 0x2C,
    0x02, 0x33, 0x60, 0x51, 0xC6, 0xF7, 0xA4, 0x95,
    0xF8, 0xC9, 0x9A, 0xAB, 0x3C, 0x0D, 0x5E, 0x6F,
    0x41, 0x70, 0x23, 0x12, 0x85, 0xB4, 0xE7, 0xD6,
    0x7A, 0x4B, 0x18, 0x29, 0xBE, 0x8F, 0xDC, 0xED,
    0xC3, 0xF2, 0xA1, 0x90, 0x07, 0x36, 0x65, 0x54,
    0x39, 0x08, 0x5B, 0x6A, 0xFD, 0xCC, 0x9F, 0xAE,
    0x80, 0xB1, 0xE2, 0xD3, 0x44, 0x75, 0x26, 0x17,
    0xFC, 0xCD, 0x9E, 0xAF, 0x38, 0x09, 0x5A, 0x6B,
    0x45, 0x74, 0x27, 0x16, 0x81, 0xB0, 0xE3, 0xD2,
    0xBF, 0x8E, 0xDD, 0xEC, 0x7B, 0x4A, 0x19, 0x28,
    0x06, 0x37, 0x64, 0x55, 0xC2, 0xF3, 0xA0, 0x91,
    0x47, 0x76, 0x25, 0x14, 0x83, 0xB2, 0xE1, 0xD0,
    0xFE, 0xCF, 0x9C, 0xAD, 0x3A, 0x0B, 0x58, 0x69,
    0x04, 0x35, 0x66, 0x57, 0xC0, 0xF1, 0xA2, 0x93,
    0xBD, 0x8C, 0xDF, 0xEE, 0x79, 0x48, 0x1B, 0x2A,
    0xC1, 0xF0, 0xA3, 0x92, 0x05, 0x34, 0x67, 0x56,
    0x78, 0x49, 0x1A, 0x2B, 0xBC, 0x8D, 0xDE, 0xEF,
    0x82, 0xB3, 0xE0, 0xD1, 0x46, 0x77, 0x24, 0x15,
    0x3B, 0x0A, 0x59, 0x68, 0xFF, 0xCE, 0x9D, 0xAC
};

unsigned char crc8(struct message *pmessage)
{
    unsigned char *pcBlock = (unsigned char *)(void *)pmessage;
    unsigned char len = sizeof(*pmessage);
    unsigned char crc = 0xFF;

    for (int i = 0; i < len; i++) {
        unsigned char b = *pcBlock++;
        if (i == 3) b = 0;
        crc = crc8Table[crc ^ b];
    }

    return crc;
}

void setup_radio() {
  if (::debugMode) {
    return;
  }
  radio.begin();
  radio.setChannel(1);
  radio.setPALevel(RF24_PA_MAX);
  radio.setDataRate(RF24_2MBPS);
  radio.setAutoAck(1);
  radio.setRetries(15,15);
  radio.setCRCLength(RF24_CRC_16);
  radio.openWritingPipe(pipe);         // Open the default reading and writing pipe
  radio.powerUp();
  radio.startListening();
  radio.stopListening();
  radio.printDetails();
  ::restart_time = millis();
  ::radio_error_counter = 0;
}

void setup() {
    Serial.begin(115200);
    printf_begin();
    Serial.print(F("Meteo module "));
    Serial.println (MODULE_ID);
    pinMode(pinDebug, OUTPUT);
    digitalWrite (pinDebug, LOW);
    pinMode(pinDebug, INPUT);
    if (digitalRead(pinDebug) == HIGH) {
      ::debugMode = true;
      Serial.println (F("Debug mode ON!"));
      led_error.on();
      ::checkInterval = 1000;
    }

    while (!bme.begin(0x76)) {
        Serial.println(F("Could not find a valid BME280 sensor, check wiring!"));
        delay(500);
    }
    setup_radio();
    led_power.blink(250);
    ::info.state = DHT_RESPONSE_ERROR;

    Serial.println();
}

void printValues();

void prepareDate() {
  if (::debugMode) {
    return;
  }
  memset(&buffer, 0, BUFFER_SIZE);
  struct message * pmessage = (struct message *)(void *)&buffer;
  pmessage->header.module_id = MODULE_ID;
  pmessage->header.message_number = ::message_num;
  //pmessage->header.message_type = MESSAGE_TYPE_BROADCAST;
  pmessage->header.timestamp = info.time;
  pmessage->sensors[0].sensor_id = SENSOR1_ID;
  pmessage->sensors[0].sensor_type = SENSOR1_TYPE;
  pmessage->sensors[0].value = (unsigned short)((info.temperature + 100) * 10);
  pmessage->sensors[1].sensor_id = SENSOR2_ID;
  pmessage->sensors[1].sensor_type = SENSOR2_TYPE;
  pmessage->sensors[1].value = (unsigned short)(info.humidity * 10);
  pmessage->sensors[2].sensor_id = SENSOR3_ID;
  pmessage->sensors[2].sensor_type = SENSOR3_TYPE;
  pmessage->sensors[2].value = (unsigned short)((info.pressure - 650) * 100);
  pmessage->sensors[3].sensor_id = SENSOR4_ID;
  pmessage->sensors[3].sensor_type = SENSOR4_TYPE;
  pmessage->sensors[3].value = (unsigned short)((info.temperature2 + 100) * 10);
  pmessage->sensors[4].sensor_id = SENSOR5_ID;
  pmessage->sensors[4].sensor_type = SENSOR5_TYPE;
  pmessage->sensors[4].value = (unsigned short)(info.humidity2 * 10);
  pmessage->header.crc = crc8(pmessage);
}

void checkTemperature() {
  bool allOk = true;
  float t = bme.readTemperature();
  float h = bme.readHumidity();
  float p = bme.readPressure();
  if (isnan(t) || isnan(h) || isnan(p)) {
    allOk = false;
  }
  else if (t < -100.0) {
    allOk = false;
  }
  else {
    ::info.time = ::now;
    ::info.state = DHT_RESPONSE_OK;
    ::info.temperature = t - 1.5;
    ::info.humidity = h;
    ::info.pressure = p * 0.0075;
  }
  switch(am2320.Read()) {
    case 2:
      Serial.println("CRC failed");
      allOk = false;
      break;
    case 1:
      Serial.println("Sensor offline");
      allOk = false;
      break;
    case 0:
      ::info.temperature2 = am2320.t;
      ::info.humidity2 = am2320.h;
      break;
  }
  if (allOk) {
    printValues();
    prepareDate();
    //sendDate(::info);
    ::lastReadTime = now;
  }
}

void printValues() {
    Serial.print("Temperature = ");
    Serial.print(::info.temperature);
    Serial.print(" *C; ");
    Serial.print(::info.temperature2);
    Serial.println(" *C");

    Serial.print("Pressure = ");
    Serial.print(::info.pressure);
    Serial.println(" mm");

    Serial.print("Humidity = ");
    Serial.print(::info.humidity);
    Serial.print(" %; ");
    Serial.print(::info.humidity2);
    Serial.println(" %");

    Serial.println();
}

void sendMessage() {
  int retry = 0;
  bool ok = false;
  do {
    ok = radio.write(&buffer, BUFFER_SIZE);
    if (!ok) {
      led_send.off();
      led_error.flash(30);
      ::radio_error_counter++;
      //printf("Error send!!!\n");
    }
    else {
      led_send.flash(30);
      led_error.off();
      radio_error_counter = 0;
      break;
    }
    if (--retry <= 0) {
      ok = true;
    }
    delay(50);
  } while(!ok);
  message_num++;
}

void sendDate(struct meteo_info info) {
  if (::info.state != DHT_RESPONSE_OK)
    return;
  led_send.on();
  sendMessage();
  ::last_sent_time = ::now;
  led_send.off();
}

void checkRadio() {
  if (::debugMode) {
    return;
  }
  if (last_sent_time + RADIO_INTERVAL < ::now) {
    sendDate(::info);
  }
  if (::radio_error_counter > 0) {
    printf("Radio error count = %i\n", ::radio_error_counter);
    if (::radio_error_counter > 10) {
      setup_radio();
    }
  }
}

void loop() {
  led_power.touch();
  led_error.touch();
  ::now = millis();
  if (::now - ::lastReadTime >= checkInterval) {
    //printValues();
    checkTemperature();
    ::lastReadTime = now;
  }
  checkRadio();
}

 

XOR
Offline
Зарегистрирован: 25.04.2015

а может кто выручит калибровочными константами и сырыми данными с ацп BME280

sadman41
Offline
Зарегистрирован: 19.10.2016

Калибровочные для каждого экземпляра свои, на заводе прописываются. Что вы будете с чужими-то делать?

XOR
Offline
Зарегистрирован: 25.04.2015

ну разумеется подсуну в свой код для проверки работоспособности.

есть сомнения что датчик живой, люди пишут что такое часто случается.

константы и выхлоп

7036 66A9 0032
8E1C D5FE 0BD0 1910 FFF5 FFF9 300C D120 1388  
00 018A 00 290F 0329 1E

00087829 0005788D 00003051
00087808 00057880 00003551
000877ED 0005786A 0000F550
000877CC 0005785C 0000DD50
000877B5 00057866 0000C150
000877AC 00057876 0000C950
0008778D 00057844 0000BB50
00087759 0005782D 00009E50
00087746 0005780D 0000B150
00087733 0005784B 0000BE50

XOR
Offline
Зарегистрирован: 25.04.2015

и вот что получается, с моими константами датчик не может работать в принципе
сырые данные ацп - влажность
0xDB02 1.013
0xFFFE 60.002

а вот с константами из инета, в диапазон укладывается
0x4C6B 1.006
0x8F74 99.996

dig_H1 = 0x4B
dig_H2 = 0x0171
dig_H3 = 0x00
dig_H4 = 0x012F
dig_H5 = 0x0000
dig_H6 = 0x1E

p-a-h-a
Offline
Зарегистрирован: 17.01.2019

Может кому пригодится опрос BME BMP280 без библиотеки. Писал на скорость опроса для метеостанции в автономной работе

// Всегда мерять сначала температуру, потом остальное т.к. температура запоминается и влияет на давление и влажность.
//Время на измерение всех трех показателей около 20 мс.
#define BME280 0x60
#include <Wire.h>
int32_t t_fine;//служебная переменная

struct { //Структура, рекомендую хранить в RTC памяти и пользоваться при просыпании
  uint32_t crc32;
  // калибровочные биты
  uint16_t dig_T1; int16_t  dig_T2, dig_T3;//температура
  uint16_t dig_P1; int16_t  dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9;//давление
  uint8_t  dig_H1, dig_H3; int16_t  dig_H2, dig_H4, dig_H5; int8_t   dig_H6;//влажность
  //прочитанный chip_id
  uint8_t chip_id;
} rtcData;

void setup() {
  pinMode(12, OUTPUT); digitalWrite(12, HIGH); //d6 пока что сюда подключен датчик, позже отключу
  Serial.begin(115200);
  Wire.begin();
  if (!BMxbegin()) {ESP.restart();}// настраиваем датчик. если датчик не подключен то перезагружаемся. Рекомендую настраивать при первом запуске и не отключать питание на время сна
  Serial.print("\n\nchip_id: 0x");
  Serial.println(rtcData.chip_id, HEX);
//  printCalibData();
}

void loop() {
  Serial.println();
  startMeasurement();
  if (measureOk())// если измерение проведено то читаем данные. Тут идет проверка и ожидание готовности датчика до 25 мс
  {
    Serial.println(readTemperature());
    Serial.println(readPressure() / 100.0F);
    if (rtcData.chip_id == BME280) Serial.println(readHumidity());
  }
  else
  {
    Serial.println("Measure timeout");
  }
  delay (1000);
}

// дальше код рекомендую в отдельную вкладку вставить

void setRegister(uint8_t reg, const uint8_t value) {
  Wire.beginTransmission(0x76);
  Wire.write(reg);
  Wire.write(value);
  Wire.endTransmission(true);
}

int32_t getRegister(uint8_t reg, uint8_t len) {
  if (len<1 || len>4) return NAN;
  Wire.beginTransmission(0x76);
  Wire.write(reg);
  Wire.endTransmission(false);
  Wire.requestFrom(0x76, len, true);
  int32_t value = 0;
  for (byte i = 0; i < len; i++) {
    value <<= 8;
    value |= (uint8_t)Wire.read();
  }
  Wire.endTransmission(true);
  return value;
}

 bool BMxbegin(){
  rtcData.chip_id = (uint8_t)getRegister(0xD0, 1);
  if (rtcData.chip_id < 0x56 || rtcData.chip_id > 0x60 || rtcData.chip_id == 0x59) {return 0;} // если датчик не обнаружен то перезагружаемся
  if (rtcData.chip_id == BME280) setRegister(0xF2, B00000001);//Измерять влажность если BME
  setRegister(0xF5, B11100000);// измерение раз в 4 сек(оно отключено в 0хF4) и фильтрация по 4м измерениям
  getCalibData();
  return 1;
  }


void getCalibData() {  // читаю калибровочные биты
  Wire.beginTransmission(0x76);
  Wire.write(0x88);
  Wire.endTransmission(false);
  Wire.requestFrom(0x76, 26, true);
  rtcData.dig_T1 = Wire.read() | (Wire.read() << 8); //88/89
  rtcData.dig_T2 = Wire.read() | (Wire.read() << 8); //8A/8B
  rtcData.dig_T3 = Wire.read() | (Wire.read() << 8); //8C/8D
  rtcData.dig_P1 = Wire.read() | (Wire.read() << 8); //8E/8F
  rtcData.dig_P2 = Wire.read() | (Wire.read() << 8); //90/91
  rtcData.dig_P3 = Wire.read() | (Wire.read() << 8); //92/93
  rtcData.dig_P4 = Wire.read() | (Wire.read() << 8); //94/95
  rtcData.dig_P5 = Wire.read() | (Wire.read() << 8); //96/97
  rtcData.dig_P6 = Wire.read() | (Wire.read() << 8); //98/99
  rtcData.dig_P7 = Wire.read() | (Wire.read() << 8); //9A/9B
  rtcData.dig_P8 = Wire.read() | (Wire.read() << 8); //9C/9D
  rtcData.dig_P9 = Wire.read() | (Wire.read() << 8); //9E/9F
  Wire.read();// A0 пропускаю
  rtcData.dig_H1 = Wire.read(); //A1
  
  Wire.beginTransmission(0x76);
  Wire.write(0xE1);
  Wire.endTransmission(false);
  Wire.requestFrom(0x76, 7, true);
  rtcData.dig_H2 = Wire.read() | Wire.read() << 8; //E1/E2
  rtcData.dig_H3 = Wire.read();                   //E3
  rtcData.dig_H4 |= Wire.read() << 4;             //E4
  { uint8_t E5;
    E5 |= Wire.read();                              //E5
    rtcData.dig_H4 |= E5 & 0b00000111;
    rtcData.dig_H5 |= ((E5 & 0b11110000) >> 4) | (Wire.read() << 4);
  } //E6
  rtcData.dig_H6 |= Wire.read();                  //E7
}

void printCalibData() {

  Serial.println F("---------Temp----------");
  Serial.println(rtcData.dig_T1, HEX);
  Serial.println(rtcData.dig_T2, HEX);
  Serial.println(rtcData.dig_T3, HEX);

  Serial.println F("---------Pres----------");
  Serial.println(rtcData.dig_P1, HEX);
  Serial.println(rtcData.dig_P2, HEX);
  Serial.println(rtcData.dig_P3, HEX);
  Serial.println(rtcData.dig_P4, HEX);
  Serial.println(rtcData.dig_P5, HEX);
  Serial.println(rtcData.dig_P6, HEX);
  Serial.println(rtcData.dig_P7, HEX);
  Serial.println(rtcData.dig_P8, HEX);
  Serial.println(rtcData.dig_P9, HEX);

  Serial.println("-----------Hum-----------");
  Serial.println(rtcData.dig_H1, HEX);
  Serial.println(rtcData.dig_H2, HEX);
  Serial.println(rtcData.dig_H3, HEX);
  Serial.println(rtcData.dig_H4, HEX);
  Serial.println(rtcData.dig_H5, HEX);
  Serial.println(rtcData.dig_H6, HEX);
  Serial.println("------------------------");
}

void startMeasurement(){
  setRegister(0xF4, B01001101);//Запуск измерения температуры и давления//010(17бит температура)011(18бит давление)01(однократное измерение и переход в спячку 00)//было 10110111
}

bool measureOk() { // Ждем окончания измерений
  uint32_t lastmillis = millis();
  while (getRegister (0xF3, 1) & 0b00001001)
  {
    if (millis() - lastmillis > 25) return 0;// стандартное время измерений 16мс даем 25 на всякий случай
  }
    return 1;
}


float readTemperature() {
  // читаю значение АЦП BMx
  int32_t adc_T = (uint32_t)getRegister(0xFA, 3);
  adc_T >>= 4; // младший регистр содержит только 4 бита. Сдвигаем все данные на 4 бита
  //Расчет по даташиту
  float var1 = ((((adc_T >> 3) - ((int32_t)rtcData.dig_T1 << 1))) * ((int32_t)rtcData.dig_T2)) >> 11;
  float var2 = (((((adc_T >> 4) - ((int32_t)rtcData.dig_T1)) *  ((adc_T >> 4) - ((int32_t)rtcData.dig_T1))) >>  12) * ((int32_t)rtcData.dig_T3)) >> 14;
  t_fine = var1 + var2 ;
  float  T = (t_fine * 5 + 128) >> 8;
  return T / 100;
}

float readPressure() {
  int64_t var1, var2, p;
  int32_t adc_P = getRegister(0xF7, 3);
  if (adc_P == 0x800000) // value in case pressure measurement was disabled
    return NAN;
  adc_P >>= 4;
  var1 = ((int64_t)t_fine) - 128000;
  var2 = var1 * var1 * (int64_t)rtcData.dig_P6;
  var2 = var2 + ((var1 * (int64_t)rtcData.dig_P5) << 17);
  var2 = var2 + (((int64_t)rtcData.dig_P4) << 35);
  var1 = ((var1 * var1 * (int64_t)rtcData.dig_P3) >> 8) +
         ((var1 * (int64_t)rtcData.dig_P2) << 12);
  var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)rtcData.dig_P1) >> 33;
  if (var1 == 0) return 0; // avoid exception caused by division by zero
  p = 1048576 - adc_P;
  p = (((p << 31) - var2) * 3125) / var1;
  var1 = (((int64_t)rtcData.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
  var2 = (((int64_t)rtcData.dig_P8) * p) >> 19;
  p = ((p + var1 + var2) >> 8) + (((int64_t)rtcData.dig_P7) << 4);
  return (float)p / 256;
}

float readHumidity() {
  while (getRegister (0xF3, 1) & 0b00001001) {}
  int32_t adc_H = getRegister(0xFD, 2);
  if (adc_H == 0x8000) return NAN;// value in case humidity measurement was disabled
  int32_t v_x1_u32r;
  v_x1_u32r = (t_fine - ((int32_t)76800));
  v_x1_u32r = (((((adc_H << 14) - (((int32_t)rtcData.dig_H4) << 20) -
                  (((int32_t)rtcData.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) *
               (((((((v_x1_u32r * ((int32_t)rtcData.dig_H6)) >> 10) *
                    (((v_x1_u32r * ((int32_t)rtcData.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) +
                  ((int32_t)2097152)) * ((int32_t)rtcData.dig_H2) + 8192) >> 14));

  v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
                             ((int32_t)rtcData.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;
  float h = (v_x1_u32r >> 12);
  return  h / 1024.0;
}

 

b707
Offline
Зарегистрирован: 26.05.2017

ужос...

я смотрю, работать с массивами вы так и не научились...

p-a-h-a
Offline
Зарегистрирован: 17.01.2019

Согласен, вы смотрите.

Типы разные в масив научите запихивать, будут масивы.

По делу будут предложения?

  uint16_t dig_P1; int16_t  dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9;//давление
  uint8_t  dig_H1, dig_H3; int16_t  dig_H2, dig_H4, dig_H5; int8_t   dig_H6;//влажность

 

b707
Offline
Зарегистрирован: 26.05.2017

p-a-h-a пишет:

Согласен, вы смотрите.

Типы разные в масив научите запихивать, будут масивы.

По делу будут предложения?

  uint16_t dig_P1; int16_t  dig_P2, dig_P3, dig_P4, dig_P5, dig_P6, dig_P7, dig_P8, dig_P9;//давление
  uint8_t  dig_H1, dig_H3; int16_t  dig_H2, dig_H4, dig_H5; int8_t   dig_H6;//влажность

 

Вы все равно с этими "разными типами" работаете в коде как с непрерывным байтовым массивом. Тасуете  их туда-сюда, преобразуете по своей прихоти то в 32битный лонг. то в 64-битный лонг лонг. Ну и какй смысл был давать этим полям отдельные названия? - зададли бы непрерывный массив да и все

И что помешало в строчках 82-93 всю структуру прочитать  по i2c одним блоком?

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ты думаешь, такой код 

053  if (1<len>4) return NAN;

будет кто-то всерьёз рассматривать?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

p-a-h-a пишет:
По делу будут предложения?

А разве код выложен для предложений?

Мне казалось, что он выложен на тот случай, если

p-a-h-a пишет:
Может кому пригодится

Ну, пусть себе лежит, может кому и пригодится.

А предложений, вроде, никто не запрашивал :-)

sadman41
Offline
Зарегистрирован: 19.10.2016

b707 пишет:

И что помешало в строчках 82-93 всю структуру прочитать  по i2c одним блоком?

Тут прокол, верно.

А в целом - код есть калька с Адафруитовской библиотеки, там такая же акробатика с преобразованиями типов.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

массив структур?

p-a-h-a
Offline
Зарегистрирован: 17.01.2019

b707 пишет:

Вы все равно с этими "разными типами" работаете в коде как с непрерывным байтовым массивом. Тасуете  их туда-сюда, преобразуете по своей прихоти то в 32битный лонг. то в 64-битный лонг лонг

Это по делу написано. Не получается у меня одним циклом в масив все прочесть. Если меняю типы данных dig_P1..dig_P9 на uint16_t..int16_t..uint32_t..int32_t, не трогая основной код, то получаю неверный результат давления

Например dig_P2 при неверном типе печатается в сериал как D668 а при верном как FFFFD668. Тут я и не соображу почему FFFF добавляется. Конечно было бы проще в один масив считать все и сразу. Знаю что это можно сделать для dig_P2..dig_P9.

 

ua6em пишет:

массив структур?

Пока не дорос до них. Нужно изучать.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

p-a-h-a, дык может и не стоит велосипед изобретать? Смотрю код, много лет гуляющий по сети, ну очень похож...

Prostovova
Offline
Зарегистрирован: 17.10.2017

Подскажите плз

С этими датчиками, на длинной линии желательны подтягивающие резисторы.

На какой стороне их правильнее ставить? На стороне датчика или на стороне ардуины?

PS

так получилось, что использован именно такой датчик и именно на длинной линии. Кабель - не помню, как называется, но просто тонкий четырех проводный (типа телефонного). Система постоянно сбоит. Однократно, при перезагрузке по питанию, считывает, а потом начинает врать. При стендировании, в лабораторных условиях, на том же кабеле, все работало без сбоев.

Коротко проект такой - датчик в презервативе - помещается на дно бочки и по давлению считается заполненность бочки. Есть кнопка обнуления (можно поднять датчик на поверхность, сбросить показания и считать их за Ноль. Верхний срез бочки примерно на уровне 4-х метров от земли, бочка на "будке", в будке ардуина. То есть кабель идет из "будки" до верха бочки и опускается обратно, но уже в бочке. "Рабочий ход" примерно 1,3 метра (бочка не наполняется под срез и не высасывается досуха.

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Шина i2c не предназначена для работы на длинных линиях, это внутриплатная шина.  Тебе надо врЕзать в бок бочки внизу датчик давления и поставить там Тиньку + JDY-40 или RS-485. Если просыпаться раз в 10сек. одного заряда 18650 хватить на сезон с запасом. 

p-a-h-a
Offline
Зарегистрирован: 17.01.2019

Привет. Вижу несколько вариантов. Первые два, как ты хочешь - повозиться:

1) Попробовать витую пару вместо телефонного кабеля причем линию данных пустить именно через скрученную пару. Установить доп. конденсатор по питанию датчика микрофарад на 100. Дописать алгоритм "Долбления" датчика пока не будет результата. Питание датчика через пин ардуино для возможности принудительного отключения/включения питания. Не факт что поможет. Также любая дырочка в кабеле приведет к затоплению датчика. Кабель нужен хороший с экранирующей оплеткой.

2) Поставить ардуино нано в презерватив с датчиком и передавать данные на наружную ардуино например по протоколу One-wire.

3) Сделать штуцер на бочке внизу куда прикрутить датчик давления, предназначенный для этого, а там хоть радиоканал с батарейным питанием. Не прослужит долго презерватив и рано или поздно кабель потечет, а он как трубка, все вниз польется. Можно посмотреть в сторону автомобильных датчиков давления, можно специализированные глянуть. Цены не кусаются в 5-10$ думаю возможно вложиться.

Prostovova
Offline
Зарегистрирован: 17.10.2017

Эх-хе-хе-хе-хе
А поначалу идея казалась неплохой. 

Буду смотреть в сторону поплавка с магнитом на трубе. В трубу засуну цепочку резисторов с герконами. Будет сильно дискретно, но точнее 10 градаций в принципе и не надо.

Про герметичность. Сейчас в воде, но думал поднять датчик выше уровня воды в трубе с открытым низом и герметичным верхом. Тогда давление в трубе будет то же, но датчик будет уже не в воде. Заглушенная канализационная труба с резинкой, щедро смазанной силиконом, вполне держит. Сложнее обеспечить герметичный вывод провода, без утечек воздуха по изоляции.

Спасибо за советы. JDY-40 то же поизучаю.

p-a-h-a
Offline
Зарегистрирован: 17.01.2019

Слушай, Prostovova а если сверху датчик расстояния приколхозить? Чем дальше поверхность жидкости или поплавка тем меньше уровень. Варианты: GY-530, VL53L0X, HC-SR04, JSN-SR04T

https://www.youtube.com/watch?v=q4x6ypaXGf8&ab_channel=ArduinoProm

https://youtu.be/TiVjCRc9-60?t=317

Prostovova
Offline
Зарегистрирован: 17.10.2017

Я думал в этом направлении
Как поведет себя ультразвук в железной бочке неизвестно

лазер - то же не понятно. От воды неизвестно как отразится. От "поплавка" - тоже не все стабильно: переменное освещение, "поплавок" не должен уходить в сторону, наклоняться и т.д. Например лазер GY-530 не вдохновил стабильной работой. Хотя по правде я его в других целях тестировал. Может и вариант по физике, но по интерфейсу он же тот же I2C

"бочка" - это параллелепипед примерно 2м*1,5м в плане высотой 1,5м. Доступ - люк 50см*50см в углу

b707
Offline
Зарегистрирован: 26.05.2017

p-a-h-a пишет:

Слушай, Prostovova а если сверху датчик расстояния приколхозить? Чем дальше поверхность жидкости или поплавка тем меньше уровень. Варианты: GY-530, VL53L0X, HC-SR04, JSN-SR04T

так вроде не более пары недель назад кто-то уже приходил с вопросом, на что поменять датчик HC-SR04 в бочке. а то он гниет буквально за пару месяцев