Last active
December 16, 2022 11:04
-
-
Save gkluoe/585ef3eaac59af82ec3527a0959966dc to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Arduino.h> | |
#include <Wire.h> | |
#include <BMx280I2C.h> | |
#include <M5StickCPlus.h> | |
#include <CircularBuffer.h> | |
// Connect to a BME280 sensor and draw a graph of the temperature. | |
// the graph constantly auto-scales so that all of the plotted points | |
// fit into the Y axis. | |
#define I2C_ADDRESS 0x76 | |
BMx280I2C bmx280(I2C_ADDRESS); | |
// Draw the Y axis 25 pixels in from the extrele left of the screen | |
// so that we have space to draw the scale | |
int y_axis_offset = 25; | |
// Unused | |
int x_axis_offset; | |
// Create a circular buffer to hold the data points | |
// that we will plot | |
typedef CircularBuffer<double, 215> DataBuffer; | |
DataBuffer data; | |
// Do we read temperature, pressure or humidity? | |
int tph_reading = 0; | |
// A struct to hold data about the scale of an axis | |
struct ScaleData { | |
int max_val; | |
int min_val; | |
// The value of each pixel on the scale ((max - min) / number_of_pixels) | |
double pixel_value; | |
}; | |
// Calculate the max, min and resulting value-per-pixel | |
// of an axis based on the set of values to be plotted | |
struct ScaleData calc_scale(DataBuffer *data_buf) { | |
// initialise to some implausible non-zero values | |
// to compare against | |
double max_value = -1000; | |
double min_value = 1000; | |
ScaleData scale; | |
// Find max and min values in our dataset | |
for (int i=0; i < data_buf->size(); i++) { | |
if ((*data_buf)[i] > max_value) max_value = (*data_buf)[i]; | |
if ((*data_buf)[i] < min_value) min_value = (*data_buf)[i]; | |
} | |
Serial.printf("Max: %.2f, Min %.2f\n", max_value, min_value); | |
// Store integer versions of our max and min values, giving | |
// a little bit of headroom | |
scale.max_val = round(max_value * 1.05); | |
scale.min_val = round(min_value * 0.95); | |
// Calculate the value of each pixel | |
scale.pixel_value = ((double)scale.max_val - (double)scale.min_val) / 127.0; | |
Serial.printf("Max: %i, Min %i, Pixel value: %.2f\n", scale.max_val, scale.min_val, scale.pixel_value); | |
return scale; | |
} | |
void setup() { | |
// put your setup code here, to run once: | |
M5.begin(); | |
M5.Lcd.begin(); | |
M5.Lcd.setRotation(3); | |
Serial.begin(9600); | |
while (!Serial) { | |
; // wait for serial port to connect. Needed for native USB | |
} | |
// Fire up the I2C bus, using pins 25 and 26 | |
Wire.begin(25, 26); | |
if (!bmx280.begin()) | |
{ | |
M5.Lcd.drawString("begin() failed. check your BMx280 Interface and I2C Address.", 3, 50); | |
while (1); | |
} | |
bmx280.resetToDefaults(); | |
//by default sensing is disabled and must be enabled by setting a non-zero | |
//oversampling setting. | |
//set an oversampling setting for pressure and temperature measurements. | |
bmx280.writeOversamplingPressure(BMx280MI::OSRS_P_x16); | |
bmx280.writeOversamplingTemperature(BMx280MI::OSRS_T_x16); | |
if (bmx280.isBME280()) { | |
bmx280.writeOversamplingHumidity(BMx280MI::OSRS_H_x16); | |
} | |
// X axis | |
M5.Lcd.drawLine(y_axis_offset, 130, 256, 130, GREEN); | |
// Y axis | |
M5.Lcd.drawLine(y_axis_offset, 0, y_axis_offset, 130, GREEN); | |
Serial.println("Setup done."); | |
} | |
void loop() { | |
Serial.printf("%s\n", "In loop."); | |
// Get temperature and draw a pixel at the appropriate point | |
if (!bmx280.measure()) | |
{ | |
M5.Lcd.drawString("could not start measurement, is a measurement already running?", 3, 50); | |
return; | |
} | |
//wait for the measurement to finish | |
do | |
{ | |
delay(100); | |
} while (!bmx280.hasValue()); | |
M5.update(); | |
if (M5.BtnA.wasPressed()) { | |
M5.update(); | |
tph_reading += 1; | |
if (tph_reading > 2) tph_reading = 0; | |
data.clear(); | |
} | |
float reading; | |
switch(tph_reading) { | |
case 0: | |
reading = bmx280.getTemperature(); | |
break; | |
case 1: | |
reading = bmx280.getPressure() / 100; | |
break; | |
case 2: | |
reading = bmx280.getHumidity(); | |
break; | |
} | |
Serial.printf("Reading: %.2f\n", reading); | |
// Returns false if our circular queue is full | |
// nb it's circular, so not a problem! | |
if (! data.push(reading)) { | |
Serial.println("Queue full!"); | |
} | |
// Clear the graph by drawing a black rect over the whole | |
// graph area | |
M5.Lcd.fillRect(y_axis_offset + 1, 0, 255, 129, BLACK); | |
// Calculate max, min and pixel value | |
ScaleData y_scale_data; | |
y_scale_data = calc_scale(&data); | |
// Blank, then draw, the numbers at the top and bottom of the scale | |
// this is horrible. | |
M5.Lcd.drawString(" ", 0, 0); | |
M5.Lcd.drawString(" ", 0, 120); | |
M5.Lcd.drawNumber(y_scale_data.max_val, 0, 0); | |
M5.Lcd.drawNumber(y_scale_data.min_val, 0, 120); | |
// Plot each point onto the graph | |
for (int i=0; i<data.size(); i++) { | |
int y_coord = 130 - round((data[i] - y_scale_data.min_val) / y_scale_data.pixel_value); | |
// The x coordinate is just i plus the necessary offset | |
// plus the width of the line | |
int x_coord = i + y_axis_offset + 1; | |
M5.Lcd.drawPixel(x_coord, y_coord, RED); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment