#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <Wire.h>
// =====================================================
// Display: SH1106 128x64 I2C
// Rotação: U8G2_R2 = 180° (ajuste se a tela estiver invertida)
// =====================================================
U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0);
// =====================================================
// Variáveis de pressão (em centésimos de psi)
// =====================================================
int boostPressure = 0;
int boostMax = 0;
int boostMin = 0;
// =====================================================
// Controle de tempo (para leitura periódica)
// =====================================================
unsigned long startMillis;
unsigned long currentMillis;
const unsigned long period = 50; // 50 ms = 20 Hz
// =====================================================
// Histórico de leituras (para o gráfico)
// =====================================================
const int sensorHistoryLength = 128;
int sensorHistory[sensorHistoryLength];
int sensorHistoryPos = sensorHistoryLength - 1;
// =====================================================
// Funções auxiliares
// =====================================================
// Converte leitura analógica (0-1023) para pressão (0–5000 centésimos de psi)
float normaliseSensorData(int m) {
// Sensor 0.5V a 4.5V → 102 a 921 (ADC)
// 0 a 50 psi → 0 a 5000 (centésimos)
// ((m − 102) / 819) * 5000 = (m − 102) / 0.1638
return (m - 102) / 0.1638;
}
// Adiciona nova leitura ao histórico circular
void addSensorHistory(int val) {
sensorHistory[sensorHistoryPos] = val;
sensorHistoryPos--;
if (sensorHistoryPos < 0) sensorHistoryPos = sensorHistoryLength - 1;
}
// Retorna valor do histórico em ordem temporal correta
int getSensorHistory(int index) {
index += sensorHistoryPos;
if (index >= sensorHistoryLength) index -= sensorHistoryLength;
return sensorHistory[index];
}
// Mapeia valor em “val” para coordenada Y do gráfico
int mapValueToYPos(int val, int range, int y, int height) {
float valueY = ((float)val / range) * height;
return y + height - (int)valueY;
}
// Linha pontilhada horizontal
void drawHorizontalDottedLine(int x, int y, int len) {
for (int i = 0; i < len; i += 4)
u8g2.drawPixel(x + i, y);
}
// =====================================================
// Leitura do sensor
// =====================================================
void readSensorData(void) {
float absolutePressure = normaliseSensorData(analogRead(A0));
// Subtrai pressão atmosférica e offset de calibração
boostPressure = absolutePressure - 1727;
// Atualiza limites
if (boostPressure > boostMax) boostMax = boostPressure;
if (boostPressure < boostMin) boostMin = boostPressure;
// Armazena histórico
addSensorHistory(boostPressure);
}
// =====================================================
// Desenho do gráfico e elementos visuais
// =====================================================
// Barrinha horizontal mostrando pressão instantânea
void drawBarGraph(int x, int y, int len, int height) {
if (boostMax <= 0) return;
if (boostPressure < 0) return;
int barLength = (float)boostPressure / boostMax * len;
barLength = constrain(barLength, 0, len); // evita "estourar" a barra
u8g2.setDrawColor(2);
u8g2.drawBox(x, y, barLength, height);
u8g2.setDrawColor(1);
}
// Gráfico histórico
void drawGraph(int x, int y, int len, int height) {
// Linhas de referência
drawHorizontalDottedLine(x, y, len);
drawHorizontalDottedLine(x, y + height, len);
int absMin = abs(boostMin);
int range = absMin + boostMax;
if (range == 0) range = 1;
int zeroYPos = mapValueToYPos(absMin, range, y, height);
drawHorizontalDottedLine(x, zeroYPos, len);
// Gráfico histórico
for (int i = 0; i < len - 1; i++) { // evita estourar canto esquerdo
int valueY = getSensorHistory(i) + absMin;
int yPos = mapValueToYPos(valueY, range, y, height);
int xPos = len - 1 - i; // desloca para dentro da tela
if (yPos < zeroYPos)
u8g2.drawVLine(xPos, yPos, zeroYPos - yPos);
else
u8g2.drawPixel(xPos, yPos);
}
}
// =====================================================
// Setup e loop principal
// =====================================================
void setup(void) {
u8g2.begin();
u8g2.setFontMode(1);
startMillis = millis();
}
void loop(void) {
// Atualiza leitura a cada 50 ms
currentMillis = millis();
if (currentMillis - startMillis >= period) {
readSensorData();
startMillis = currentMillis;
}
// Desenha tudo
u8g2.firstPage();
do {
// --- Cabeçalho ---
u8g2.setFont(u8g2_font_6x12_tr);
u8g2.drawStr(0, 10, "BOOST PRESSURE (PSI)");
// --- Valor principal ---
u8g2.setFont(u8g2_font_fub20_tf);
char cstr[8];
dtostrf((float)boostPressure / 100.0, 4, 2, cstr);
u8g2.drawStr(0, 34, cstr);
// --- Máximo ---
u8g2.setFont(u8g2_font_6x12_tr);
char cmax[8];
dtostrf((float)boostMax / 100.0, 4, 2, cmax);
int w = u8g2.getStrWidth(cmax);
u8g2.drawStr(128 - w, 10, cmax);
// --- Barrinha ---
drawBarGraph(0, 38, 128, 6);
// --- Gráfico ---
drawGraph(0, 46, 128, 18);
// --- Linha de separação visual ---
u8g2.drawHLine(0, 44, 128);
} while (u8g2.nextPage());
}