Thursday, December 1, 2016

BMP280 and ESP8266

The BMP280 is the next generation sensor from Bosch and follows its predecessors BMP085 - BMP180. Price for it is now under $2 with free shipping.




Key parameters

  •  Pressure range 300 … 1100 hPa (equiv. to +9000…-500 m above/below sea level)
  •  Package 8-pin LGA metal-lid
  • Footprint : 2.0 × 2.5 mm², height: 0.95 mm
  •  Relative accuracy ±0.12 hPa, equiv. to ±1 m
  •  (950 … 1050hPa @25°C)
  •  Absolute accuracy typ. ±1 hPa  (950 ...1050 hPa, 0 ...+40 °C)
  •  Temperature coefficient offset 1.5 Pa/K, equiv. to 12.6 cm/K  (25 ... 40°C @900hPa)
  •  Digital interfaces I²C (up to 3.4 MHz) SPI (3 and 4 wire, up to 10 MHz)
  •  Current consumption 2.7µA @ 1 Hz sampling rate
  •  Temperature range -40 … +85 °C


Typical applications

  • Enhancement of GPS navigation
  •  (e.g. time-to-first-fix improvement, dead-reckoning, slope detection)
  •  Indoor navigation (floor detection, elevator detection)
  •  Outdoor navigation, leisure and sports applications
  •  Weather forecast
  •  Health care applications (e.g. spirometry)
  •  Vertical velocity indication (e.g. rise/sink speed)









For connecting the BMP280 to ESP8266 the following pins need to be connected: 


BMP280
NodeMCU / WeMos D1 mini
Other ESP8266
VCC
3V3

GND
GND

SCL
D1
GPIO 5
SDA
D2
GPIO 4
CSB
3V3

SDO
3V3




The BMP280 supports the I²C and SPI digital interfaces; it acts as a slave for both protocols. 

The I²C interface supports the Standard, Fast and High Speed modes. 

The SPI interface supports both SPI mode ‘00’ (CPOL = CPHA = ‘0’) and mode ‘11’ (CPOL = CPHA = ‘1’) in 4- wire and 3-wire configuration. The following transactions are supported: Single byte write  multiple byte write (using pairs of register addresses and register data) single byte read multiple byte read (using a single register address which is auto-incremented) 


Connect the CSB pin to GND to have SPI and to VCC(3V3) for I2C.

The 7-bit device address is 111011x. The 6 MSB bits are fixed. The last bit is changeable by SDO value and can be changed during operation. 

Connecting SDO to GND results in slave address 1110110 (0x76), connecting it to VCC results in slave address 1110111 (0x77), which is the same as BMP180’s I²C address. 

The SDO pin cannot be left floating, if left floating, the I²C address will be undefined.

In my setup I've connected CSB and SDO to VCC to have I2C and 0x77 as address.


To run a quick test I've installed the Adafruit Sensor library and Adafruit BMP280 library .

The code to test the BMP280 is the example code from library.

This code assume that the SDA and SCL are connected on GPIO 4 and GPIO 5. If you need to assign new pins to your BMP280 use the Wire.begin(2,0) where the GPIO 2 is connected to SDA and GPIO 0 is connected to  SCL.

Now its time to add some code to read the temperature and pressure, post them to the thingspeak.com and also update the temperature gauge on this blog.



/**********************************************
 * Catalin Batrinu bcatalin@gmail.com 
 * Read temperature and pressure from BMP280
 * and send it to thingspeaks.com
**********************************************/

#include <Wire.h>
#include <SPI.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include <ESP8266WiFi.h>

#define BMP_SCK 13
#define BMP_MISO 12
#define BMP_MOSI 11 
#define BMP_CS 10

Adafruit_BMP280 bme; // I2C
// replace with your channel’s thingspeak API key,
String apiKey = "YOUR-API-KEY";
const char* ssid = "YOUR-SSID";
const char* password = "YOUR-ROUTER-PASSWORD";
const char* server = "api.thingspeak.com";
WiFiClient client;


/**************************  
 *   S E T U P
 **************************/
void setup() {
  Serial.begin(9600);
  Serial.println(F("BMP280 test"));
  
  if (!bme.begin()) {  
    Serial.println("Could not find a valid BMP280 sensor, check wiring!");
    while (1);
  }
  WiFi.begin(ssid, password);
  
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");  
}

  /**************************  
 *  L O O P
 **************************/
void loop() {
    Serial.print("T=");
    Serial.print(bme.readTemperature());
    Serial.print(" *C");
    
    Serial.print(" P=");
    Serial.print(bme.readPressure());
    Serial.print(" Pa");

    Serial.print(" A= ");
    Serial.print(bme.readAltitude(1013.25)); // this should be adjusted to your local forcase
    Serial.println(" m");

    if (client.connect(server,80))  // "184.106.153.149" or api.thingspeak.com
    {
        String postStr = apiKey;
        postStr +="&field1=";
        postStr += String(bme.readTemperature());
        postStr +="&field2=";
        postStr += String(bme.readPressure());
        postStr += "\r\n\r\n";
        
        client.print("POST /update HTTP/1.1\n");
        client.print("Host: api.thingspeak.com\n");
        client.print("Connection: close\n");
        client.print("X-THINGSPEAKAPIKEY: "+apiKey+"\n");
        client.print("Content-Type: application/x-www-form-urlencoded\n");
        client.print("Content-Length: ");
        client.print(postStr.length());
        client.print("\n\n");
        client.print(postStr);    
    }
    client.stop(); 
    //every 20 sec   
    delay(20000);
}


Temperature logging


A post about BMP180 attached to a battery shield can be found here.











41 comments:

  1. I follow your procedure but it doesn't work.

    ReplyDelete
  2. Perfectly working, thank you very much.

    ReplyDelete
  3. thank you so much... this really help me...

    ReplyDelete
  4. funciona realmente bien, estoy muy agradecido por tu aporte.

    thank you so much... this sketch its great ...

    ReplyDelete
  5. Thank you very much. It works perfectly.

    Could you include some instructions for the gauge meter ? I don't know how to make it.

    ReplyDelete
    Replies
    1. Go to thingspeak.com and then go to Apps. After that click on Plugins then to New.
      Select Google Gauge and click Create. After that use the JavaScript code to add your API_KEY and be sure to check the "Create a public URL". Have fun !

      Delete
  6. Hi, very nice use of ESP8266 without thingspeak library. What needs to be added/changed if HTU21 moisture detector is to be read and uploaded? Are GPIO4 and GPIO5 standard I2C pins?

    ReplyDelete
    Replies
    1. You can use any pin for I2C. I like to use the 4 and 5 in my projects, but you can use any pin.
      To add humidity I've used a DHT22. Check it here: https://myesp8266.blogspot.nl/2017/11/with-help-of-iotcentral.html

      Delete
  7. Hi, thanks for that very fast answer. A few more questions:
    1. why do you use "\r\n\r\n" instead of "\r\n" as last postStr descriptor?
    2. why do you use bme reads instead of bmp reads? BMP280 is the sensor used, right?
    3. if I want to add another field (say HTU21), I assume that the following lines are needed to be added to the string to be uploaded to thingspeak:

    postStr +="&field3=";
    postStr += String(htu.readHumidity());

    4. what is the purpose of the client.print("\n\n"); statement at the end of the thingspeak upload?

    Thanks a lot!
    Erik


    ReplyDelete
    Replies
    1. 1. HTML header
      2. BME280 is an enhanced version of BMP280. Same code works with both.
      3. Correct
      4. HTML header format.

      Delete
  8. Hi Catalin,
    thanks for your fast answer!
    Here a few more questions:
    1. should postStr +="&field1="; not be postStr +="field1="; for the first field?
    2. should postStr += String(bme.redaTemperature()); not be postStr += String(bme.redaTemperature(), DEC); so that a decimal is used for this value? The examples I see on this subject in these cases use DEC; is that superfluous?
    3. where can I find information on the HTML header use of \n and \r for thingspeak? I know \n = new line and \r = carriage return but I have no clue why they are used here?
    Thanks!
    Erik

    ReplyDelete
    Replies
    1. 1. The desired URI is ti have fields as parameters delimited by &. like field1=33&field2=44&fieldX=YY. Thingspeak accept up to 8 fields.
      2. Output from readTemp is DEC not OCT or HEX so no need to convert it
      3. Structure of the HTTP heder is:

      The HTTP generic message format is as follows:

      start-line
      message-headers
      empty-line
      message-body
      message-trailers

      See the empty-line ?

      Search for HTTP header info. Also you can read this: http://www.tcpipguide.com/free/t_HTTPGenericMessageFormat.htm

      Delete
    2. Hi Catalin, thank you for your fast reply!
      My first question refers to the & sign in front of field1: I see most examples on internet do not use & in front of the first field definition. Is it better to use it in the first field definition?
      Thks
      Erik

      Delete
    3. The & is mandatory. It is a parameter separator in the HTTP GET command.
      http://api.thingspeak.com/update?api_key=xxxxzzzzzzyyyyy&field1=33&field2=5454&field3=44

      Please see more examples on https://de.mathworks.com/help/thingspeak/examples.html

      Delete
    4. ok, thanks for your input. I find this one of the best examples of code (and instructions) for the use of ESP8266 + sensor + thingspeak available on internet. And the use of code without library adds to its interest.

      It would be perfect if you could post this code for use with a DS3231 RTC (without library) to get sensor readings sent at fixed times instead of a delay function. I am writing some code for that too but I am interested in seeing your way of doing it.

      Delete
    5. If your esp8266 need to stay in low power and you want to log data to an sd card and you don't have wifi connection than is ok to us ds3231. If your code need to do more and not wait in delay you ca use something like this in your loop function:

      loop(){
      unsigned long currentMillis = millis();

      if (currentMillis - previousMillis >= interval) {
      // save the last
      previousMillis = currentMillis;

      // Call your function to read and post your data
      }

      // Here you can call other function.
      }

      Delete
  9. I do no understand why I cannot get connected to wifi with your code, but when using below it works:
    #include
    ESP8266WiFiMulti WiFiMulti;
    In setup I use following code instead of yours for wifi connect:
    WiFiMulti.addAP(ssid, password);
    Serial.println();
    Serial.println();
    Serial.print("Wait for WiFi... ");

    while(WiFiMulti.run() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
    }

    ReplyDelete
    Replies
    1. Strange, I've just tested it and is working fine. I've added a new module so I can get the outside temperature with Alexa. Don't see any reason for using WiFiMulti if you are seeting just one SSID. AFAIK WiFiMulti is just calling WiFi.begin. Post some output please.

      Delete
  10. Hi Catalin, I found the issue. The ESP8266 remained stuck in the loop checking for the BMP280. For some reason this module is not found. When removing this check wifi does get connected.
    The I2C wiring seems correct to me: pull-ups to 3.3V (500R), SDA to GPIO4, SCL to GPIO5. A HTU21 I added (incl library Adafruit_HTU21DF.h and Adafruit_HTU21DF htu = Adafruit_HTU21DF(); statements).
    When using the BMP280 only I get values of 0, when adding the HTU21 the program stops when trying to read Serial.print(htu.readTemperature());
    Would you maybe have a hint?
    Thks!

    ReplyDelete
    Replies
    1. Hi Erik,

      Try first the example from here:
      https://learn.sparkfun.com/tutorials/htu21d-humidity-sensor-hookup-guide/htu21d-library-and-functions

      and if is working it means that you connections between HTU21 and ESP are correct.


      After that try the code from here:

      https://learn.adafruit.com/pages/6077/elements/2957962/download

      If this example is working then also the connections for the BMP280 are ok.

      Run both examples with both sensors (BMP280 and HTU21) attached to the ESP8266. If you have the shield modules, I guess that both have pull-up resistors and there is no need to add more.

      I am sure that both sensors are not sharing the same address.

      To figure it out I need more info about what shields are you using and the entire code.

      Delete
    2. Hi Catalin, the BMP280 is this one: https://tinyurl.com/ya8wnngn , the HTU-21: https://tinyurl.com/y9l3gapj
      Both sensors use a different I2C address.
      I will test your proposal and feed back. May be a few days..

      Delete
    3. HTU21 is ok, BMP280 defective.
      Program working perfect (BMP280 code commented).
      Thank you Catalin!
      Erik

      Delete
    4. Erik, I hope you connected the CSB and SDO to 3V3 on the BMP280 module.

      Delete
    5. Good point; I had SDO to 3.3V; changed to GND (I2C address 0x76), working now, in your program too. Thank you for all your help!!
      Erik

      Delete
    6. Hi Catalin, why do you use the F in Serial.println(F("BMP280 test")); there only?

      Delete
    7. String to be printed will be saved in flash and not in RAM. Is good if you have a lot of strings to be printed, as in debug mode.

      Delete
    8. But why do you use it only once (and not for example in the other related lines)?

      Delete
    9. Got today some BME280 sensors. All are working nice.

      Delete
  11. I wrote code for your program to be executed once a minute (or once an hour, once a day, twice, more etc..) using a DS3231 without library. I tried to include her ebut it does not accept it. I would like you to have a critical look at it, how can i send it to you?
    Thank you, Erik

    ReplyDelete
    Replies
    1. Sure, I can take a look on it. Send me an email with it. Email address is here: https://myesp8266.blogspot.ro/2016/01/eink-display.html

      Delete
  12. Auto-reset and auto-program using DTR, on bare-bones 12E/F modules: connect DTR with 2.2uF cap in series to RESET. Add 10k pull-up between RST and 3.3V, add small signal diode (1N4148) in parallel (anode to RST).
    Auto-program: connect DTR to GPIO0 with second small signal diode in series, anode to GPIO0.
    Works with any USB-to-serial adapter where DTR is broken out (beware: use 3.3V on adapter connections to ESP8266).

    ReplyDelete
    Replies
    1. After several weeks testing I find that auto-reset and auto-program cannot be made to work robustly. I need to do much more research but currently the above setup is not satisfactory.

      Delete
  13. OKK,Work perfect.

    ReplyDelete
  14. Hi Catalin,

    I grabbed the code in this post and put it in place. Then I downloaded the two libraries you mentioned (Adafruit Sensor library and Adafruit BMP280 library) and installed them.

    When I compile (Arduino IDE) it complains that it cannot find ESP8266WiFi.h

    Any idea what I can do?

    ReplyDelete
    Replies
    1. Yes, I know what is wrong. Please go to this post https://myesp8266.blogspot.ro/2016/11/esp8266-esp201-step-by-step-guide.html and follow the Arduino IDE part were the compiler and libraries are installed.

      The fast way is to go to File->Preferences and in the input box that has the label "Aditional Bords Manager URL" paste this link http://arduino.esp8266.com/stable/package_esp8266com_index.json

      Delete
    2. wow - quick response - thanks - that worked

      Delete
  15. How can I run two BMP280's on the same 8266. Can I set one on SDO @ GND address (0x76) and the other on SDO @ VCC both on the same buss? Where is code to change addresses?

    ReplyDelete
  16. Why dont you use the https://github.com/adafruit/Adafruit_BME280_Library library? when im using the BMP library my temp readings are way to high (4 degrees\already tried replacing the BME chip)

    ReplyDelete
    Replies
    1. I didn't have problems with the BMP library, other then normal RF heating that affects the temperature value, but this can be avoided.

      Delete
  17. Do not forget to include the even though you are using only the i2c interface. It didnt read anything from the sensor even though I am using only the i2c interface

    ReplyDelete