Now that we've successfully read temperature, humidity, and air pressure from a BME280, we turn to the problem of making this data available without having to use a serial monitor. Our first solution is to use a tiny OLED display.
In this tutorial we will:
- Install the Correct Library
- Add the Display to the Breadboard
- Test the Display
- Show Sensor Data in the Display
Install the Correct Library
A wide variety of tiny OLED displays are available, and for this tutorial we'll be using a 0.96 inch, monochrome, 128 x 64 pixel screen that is driven by the SSD1306, and that has an I2C interface. As it goes, this device has I2C address 0x3c. There are several libraries for the SSD1306, and we will use the one entitled "ESP8266 and ESP32 Oled Driver for SSD1306 display by Daniel Eichhorn, Fabrice Weinberg". To install this library:
- In the Arduino IDE, choose the menu Sketch | Include Library | Manage Libraries...
- Enter SSD1306, click the right one, and install the latest version of that library (currently version 3.2.7).
Add the Display to the Breadboard
Along the top of the display there will be four pins that read something like
- GND, VCC, SCL, and SDA
- or GND, VDD, SCK, and SDA
First disconnect the BME280, then wire the display as follows:
- ESP8266 <--> OLED
- 3V3 <--> VCC
- GND <--> GND
- SCL <--> D5
- SDA <--> D6
If there isn't room on the breadboard to add the display, either use a full-size breadboard or use a second half-sized breadboard!
Test the Display
Ignoring the BME280 for a minute, the following sketch tests the features we will be using when we display data from the BME280.
The library works as follows:
- We initialize it in the setup() function, and we flip the screen vertically. The end result is to create a memory buffer
- Drawing commands will be written to this buffer - they will NOT be immediately visible
- When we are ready, write the buffer to the display using the command:
display.display();
We will be using the following commands in the final sketch:
display.setFont(fontName);
display.drawString(x, y, message);
display.display();
display.clear();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | /* * Simple-OLED-Test * * By: Mike Klepper * Date: 29 March 2017 * * This program demonstrates a VERY few simple commands from the * "ESP8266 Oled driver library for SSD1306 display" library * by Daniel Eichhorn, Fabrice Weinberg. * * Connections: * Display VCC --> NodeMCU 3V3 * Display GND --> NodeMCU GND * Display SCL --> NodeMCU D5 * Display SDA --> NodeMCU D6 */ #include "SSD1306.h" SSD1306 display(0x3c, D6, D5); void setup() { display.init(); display.flipScreenVertically(); } void loop() { display.clear(); display.drawRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); display.setFont(ArialMT_Plain_16); display.drawString(20, 7, "Hello, world!"); display.setFont(ArialMT_Plain_10); display.drawString(8, 30, "DISPLAY_WIDTH = " + String(DISPLAY_WIDTH)); display.drawString(8, 45, "DISPLAY_HEIGHT = " + String(DISPLAY_HEIGHT)); display.display(); yield(); delay(2000); } |
18 | Include the library we downloaded earlier |
20 | Create a display with I2C address 0x3c, the SDA connected to D6, and the SCL connected to D5 |
24 | Initialize the display (this creates the buffer) |
25 | Change the orientation of the display |
30 | Clear the buffer |
32 | Draw a border around the screen - notice that the library makes two constants available to us: DISPLAY_WIDTH and |
34 | Set the font we'll be using. |
35 | Print "Hello, world!" at x = 20 and y = 7 |
37 | Change font to ArialMT_Plain_10 |
38 - 39 | Print the screen width - note that this value is available in the constants DISPLAY_WIDTH and DISPLAY_HEIGHT |
41 | Copy the buffer to the physical display |
43-44 | Wait for a bit before doing it all again |
The library includes three fonts: ArialMT_Plain_10, ArialMT_Plain_16, and ArialMT_Plain_24. Additional fonts can be created using the tools found at:
Show Sensor Data on the Display
Now we will show the temperature, humidity and barometric pressure on the display. To make this a little more interesting, we will alternate showing British units and metric units.
You would think that pulling this off would be simply a matter combining the above code with the sketch from the last tutorial - after all, there is no pin overlap, right? As it goes, restoring the jumper wires as follows WILL NOT WORK!
The ESP8266 has exactly one I2C bus, so the two devices (the BME280 and the OLED display) must be on that one I2C bus! Here's what the connections will look like on a full-sized breadboard.
Once the connections are correct, the code is very easy!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | /** * BME280-OLED * * By: Mike Klepper * Date: 31 March 2017 * * This program reads data from the BMP280 and shows it on a * SSD1306 OLED display. It will alternte between British and * metric units. * * See blog post on patriot-geek.blogspot.com * for connections. */ #include "Wire.h" #include "Adafruit_Sensor.h" #include "Adafruit_BME280.h" #include "SSD1306.h" const float SEA_LEVEL_PRESSURE_HPA = 1013.25; const int DELAY = 3000; const int STARTUP_DELAY = 500; Adafruit_BME280 bme; SSD1306 display(0x3c, D6, D5); void setup() { Serial.begin(115200); if(!bme.begin()) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1) { yield(); delay(DELAY); } } delay(STARTUP_DELAY); display.init(); display.flipScreenVertically(); } void loop() { float tempC = bme.readTemperature(); float humidity = bme.readHumidity(); float pressurePascals = bme.readPressure(); // Print to serial monitor printToSerial(tempC, humidity, pressurePascals); // Display data on screen in British units drawWithBritishUnits(tempC, humidity, pressurePascals); yield(); delay(DELAY); // Display data on screen in metric units drawWithMetricUnits(tempC, humidity, pressurePascals); yield(); delay(DELAY); } void drawWithBritishUnits(float tempC, float humidity, float pressurePascals) { float tempF = 9.0/5.0 * tempC + 32.0; float pressureInchesOfMercury = 0.000295299830714 * pressurePascals; display.clear(); display.drawRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); display.setFont(ArialMT_Plain_16); display.drawString(35, 3, "BME280"); display.setFont(ArialMT_Plain_10); display.drawString(5, 22, "Temperature = " + String(tempF) + " *F"); display.drawString(5, 35, "Humidity = " + String(humidity) + "%"); display.drawString(5, 48, "Pressure = " + String(pressureInchesOfMercury) + " inHg"); display.display(); } void drawWithMetricUnits(float tempC, float humidity, float pressurePascals) { float pressureHectoPascals = pressurePascals / 100.0; display.clear(); display.drawRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT); display.setFont(ArialMT_Plain_16); display.drawString(35, 3, "BME280"); display.setFont(ArialMT_Plain_10); display.drawString(5, 22, "Temperature = " + String(tempC) + " *C"); display.drawString(5, 35, "Humidity = " + String(humidity) + "%"); display.drawString(5, 48, "Pressure = " + String(pressureHectoPascals) + " h,Pa"); display.display(); } void printToSerial(float tempC, float humidity, float pressurePascals) { // Temperature float tempF = 9.0/5.0 * tempC + 32.0; Serial.println("Temperature:"); printValueAndUnits(tempC, "*C"); printValueAndUnits(tempF, "*F"); //printValueAndUnits(tempC, "°C"); //printValueAndUnits(tempF, "°F"); Serial.println(""); // Barometric pressure float pressureHectoPascals = pressurePascals / 100.0; float pressureInchesOfMercury = 0.000295299830714 * pressurePascals; Serial.println("Pressure:"); printValueAndUnits(pressurePascals, "Pa"); printValueAndUnits(pressureHectoPascals, "hPa"); printValueAndUnits(pressureInchesOfMercury, "inHg"); Serial.println(""); // Humidity Serial.println("Humidity:"); printValueAndUnits(humidity, "%"); Serial.println(""); // Approximate altitude float altitudeMeters = bme.readAltitude(SEA_LEVEL_PRESSURE_HPA); float altitudeFeet = 3.28 * altitudeMeters; Serial.println("Approx. Altitude:"); printValueAndUnits(altitudeMeters, "m"); printValueAndUnits(altitudeFeet, "ft"); Serial.println(); } void printValueAndUnits(float value, String units) { Serial.print(" "); Serial.print(value); Serial.print(" "); Serial.println(units); } |
This completes our attempt to display sensor data using hardware. Although we were successful, we did not use the WiFi capabilities of the ESP8266! That's what the next tutorial will be about!
Hi,
ReplyDeleteThank you for the great guide !
Could you please tel me if all the wires need to be joined together or the 3.3v and GND can be connected separately for the BME280 and the oled display.
Hi MSG,
DeleteTry using the "power rail" approach like in the last Fritzig shows. It works great and is quite easy!
- MMK
Hmmm... why do I have -190°C and -1500 m and 100% humidity?
ReplyDeleteThanks.
Hello,
DeleteCheck the following:
1. Wiring
2. Use latest version of Adafruit libraries
3. Check the BME280's I2C address
Hope this helps!
- Mike K
Hi Mike,
ReplyDeleteyour tutorials are excellent, easy to understand and very instructive.
I miss the sequel to the tutorial ESP8266 with BME280 and OLED display with using the WiFi capabilities.
Hi sunnyboy66,
DeleteSorry for the late response! Here's the one for exposing the BME280 data through wifi:
https://patriot-geek.blogspot.com/2017/09/exposing-data-in-captive-portal.html
Hope this helps!
Mike
I have a similar problem to 'Unknown' - weird values from the BME280, but only when the OLED display is enabled (it can remain physically connected without any issues)
ReplyDeleteTo try and work out where the problem is, I used a "#define oled" and wrapped everything related to the OLED in "if(oled){ ... }".
With "#define oled 0", I get sensible values (t= 20.29 *C, h= 33.70 % and pressure= 1018.08 hPa
With "#define oled 1", I get t= -143.81 *C, h= 100% and pressure= 1135.39 hPa
I2C addresses are 0x76 for the BME280 and 0x3C for the OLED.
Does anybody know what the problem is?
hi I get this error
ReplyDeleteC:\Users\worth\Documents\Arduino\temperature sensors\test_useless\test_useless.ino: In function 'void drawWithBritishUnits(float, float, float)':
test_useless:77:26: error: 'DISPLAY_WIDTH' was not declared in this scope
display.drawRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
^
test_useless:77:41: error: 'DISPLAY_HEIGHT' was not declared in this scope
display.drawRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
^
C:\Users\worth\Documents\Arduino\temperature sensors\test_useless\test_useless.ino: In function 'void drawWithMetricUnits(float, float, float)':
test_useless:96:26: error: 'DISPLAY_WIDTH' was not declared in this scope
display.drawRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
^
test_useless:96:41: error: 'DISPLAY_HEIGHT' was not declared in this scope
display.drawRect(0, 0, DISPLAY_WIDTH, DISPLAY_HEIGHT);
^
exit status 1
'DISPLAY_WIDTH' was not declared in this scope
Hello!
DeleteThere has been a change in one of the libraries - DISPLAY_WIDTH and DISPLAY_HEIGHT used to be defined, but isn't anymore!
Try adding the following lines near the top:
const int DISPLAY_WIDTH = 128;
const int DISPLAY_HEIGHT = 64;
It is also possible to revert to an older version of the library.
Hope this helps!
Hi
ReplyDeletethanks for the nice tutorial.
I'm getting the error: 'DISPLAY_WIDTH' was not declared in this scope
Is something wrong with the library or do you know how to solve this problem?
Thanks
nevermind, problem solved
DeleteGlad you got it to work! There was a change in the library and that's what's causing the error!
Delete