Skip to content

Instantly share code, notes, and snippets.

@gkluoe
Last active December 16, 2022 11:04
Show Gist options
  • Save gkluoe/585ef3eaac59af82ec3527a0959966dc to your computer and use it in GitHub Desktop.
Save gkluoe/585ef3eaac59af82ec3527a0959966dc to your computer and use it in GitHub Desktop.
#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