Skip to content

Instantly share code, notes, and snippets.

@bukowa
Last active September 24, 2025 16:37
Show Gist options
  • Select an option

  • Save bukowa/8db047fc52b5e56581b41dae7145fb02 to your computer and use it in GitHub Desktop.

Select an option

Save bukowa/8db047fc52b5e56581b41dae7145fb02 to your computer and use it in GitHub Desktop.
INA226 Arduino Uno LCD Shield 2.4 TFT
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
// --- Konfiguracja ADS1115 ---
Adafruit_ADS1115 ads;
// --- Konfiguracja Pinów Multipleksera ---
const int MUX_S0_PIN = 2; // Pin A na CD4051
const int MUX_S1_PIN = 3; // Pin B na CD4051
const int MUX_S2_PIN = 4; // Pin C na CD4051
// Funkcja do wyboru kanału na multiplekserze (bez zmian)
void selectMuxChannel(byte channel) {
digitalWrite(MUX_S0_PIN, bitRead(channel, 0));
digitalWrite(MUX_S1_PIN, bitRead(channel, 1));
digitalWrite(MUX_S2_PIN, bitRead(channel, 2));
delayMicroseconds(50);
}
void setup() {
Serial.begin(9600);
Wire.begin();
// Inicjalizacja ADS1115 (bez zmian)
if (!ads.begin()) {
Serial.println("Nie znaleziono ADS1115");
while (1);
}
// Ustaw piny sterujące MUX jako wyjścia (bez zmian)
pinMode(MUX_S0_PIN, OUTPUT);
pinMode(MUX_S1_PIN, OUTPUT);
pinMode(MUX_S2_PIN, OUTPUT);
Serial.println("System gotowy. Rozpoczynam odczyt wszystkich kanałow MUX.");
}
// ====================================================================
// == NOWA, ZAKTUALIZOWANA FUNKCJA LOOP ==
// ====================================================================
void loop() {
Serial.println("--- Nowy cykl pomiarowy ---");
// Pętla 'for', która przejdzie przez wszystkie 8 kanałów, od 0 do 7
for (int channel = 0; channel < 8; channel++) {
// Krok 1: Wybierz aktualny kanał na multiplekserze
selectMuxChannel(channel);
// Krok 2: Odczytaj napięcie z wyjścia multipleksera (które jest podłączone do A1 na ADS1115)
float muxVoltage = ads.computeVolts(ads.readADC_SingleEnded(1));
// Krok 3: Wyświetl wynik dla tego kanału
Serial.print(" Kanal MUX Y");
Serial.print(channel);
Serial.print(": ");
Serial.print(muxVoltage, 4); // Drukuj z dużą precyzją
Serial.println(" V");
}
// Czekaj 2 sekundy przed rozpoczęciem kolejnego pełnego cyklu odczytów
delay(2000);
}
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <INA226_WE.h> // Upewnij się, że ta biblioteka jest zainstalowana
// --- Konfiguracja Sieci i Serwera ---
const char *ssid = "ESP_POMIAROWY";
WiFiServer server(80);
// --- Konfiguracja INA226 ---
#define I2C_ADDRESS 0x40
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
// --- Konfiguracja logiki pomiarowej (przeniesiona z Twojego kodu) ---
#define NUM_SAMPLES 150
int voltage_samples_mV[NUM_SAMPLES];
int current_samples_mA[NUM_SAMPLES];
// Zmienne do automatycznego zakresu
float v_min_dynamic = 4.9, v_max_dynamic = 5.1;
float c_min_dynamic = 0.0, c_max_dynamic = 100.0;
// === Zmienne globalne do przechowywania OSTATNICH wyników ===
// Te zmienne będą odczytywane przez serwer WWW
volatile float last_Vavg = 0.0;
volatile float last_Iavg = 0.0;
volatile float last_freqV = 0.0;
volatile float last_freqC = 0.0;
volatile float last_minV = 0.0;
volatile float last_maxV = 0.0;
volatile float last_minC = 0.0;
volatile float last_maxC = 0.0;
volatile float last_time_span_s = 0.0;
void setup() {
Serial.begin(115200);
// Inicjalizacja I2C dla ESP8266 (GPIO0 = SDA, GPIO2 = SCL)
// WAŻNE: Po wgraniu kodu, odłącz GPIO0 od masy!
Wire.begin(0, 2);
if(!ina226.init()){
Serial.println("Nie znaleziono INA226!");
while(1);
}
Serial.println("Znaleziono INA226!");
// Ustawienia INA226 z Twojego kodu
ina226.setAverage(AVERAGE_1);
ina226.setConversionTime(CONV_TIME_140);
ina226.setResistorRange(0.1, 0.5); // Ustaw rezystor i maksymalny spodziewany prąd
// Konfiguracja punktu dostępowego
Serial.println("Konfiguracja Access Point...");
WiFi.softAP(ssid);
IPAddress myIP = WiFi.softAPIP();
Serial.print("Adres IP: ");
Serial.println(myIP);
// Uruchomienie serwera WWW
server.begin();
Serial.println("Serwer WWW uruchomiony.");
}
void loop() {
// === BLOK 1: ZBIERANIE DANYCH ===
float minV = 100.0, maxV = 0.0, sumV = 0.0;
float minC = 1000.0, maxC = 0.0, sumC = 0.0;
long startTime = micros();
for(int i=0; i<NUM_SAMPLES; i++){
float voltage = ina226.getBusVoltage_V();
float current = ina226.getCurrent_mA();
// Zapisywanie próbek nie jest konieczne, jeśli nie wysyłamy wykresu,
// ale zostawiam logikę na przyszłość.
voltage_samples_mV[i] = voltage * 1000;
current_samples_mA[i] = current;
if(voltage < minV) minV = voltage;
if(voltage > maxV) maxV = voltage;
sumV += voltage;
if(current < minC) minC = current;
if(current > maxC) maxC = current;
sumC += current;
}
long endTime = micros();
// === BLOK 2: OBLICZENIA ===
int v_zero_crossings = 0, c_zero_crossings = 0;
long v_avg_mV = sumV * 1000 / NUM_SAMPLES;
long c_avg_mA = sumC / NUM_SAMPLES;
for (int i = 1; i < NUM_SAMPLES; i++) {
if ((voltage_samples_mV[i-1] < v_avg_mV && voltage_samples_mV[i] >= v_avg_mV) || (voltage_samples_mV[i-1] > v_avg_mV && voltage_samples_mV[i] <= v_avg_mV)) v_zero_crossings++;
if ((current_samples_mA[i-1] < c_avg_mA && current_samples_mA[i] >= c_avg_mA) || (current_samples_mA[i-1] > c_avg_mA && current_samples_mA[i] <= c_avg_mA)) c_zero_crossings++;
}
float time_span_s = (endTime - startTime) / 1000000.0f;
// === AKTUALIZACJA ZMIENNYCH GLOBALNYCH ===
// To jest "atomowa" operacja, która udostępnia nowe dane serwerowi
last_Vavg = sumV / NUM_SAMPLES;
last_Iavg = sumC / NUM_SAMPLES;
last_freqV = (v_zero_crossings / 2.0) / time_span_s;
last_freqC = (c_zero_crossings / 2.0) / time_span_s;
last_minV = minV;
last_maxV = maxV;
last_minC = minC;
last_maxC = maxC;
last_time_span_s = time_span_s;
// === BLOK 4: AKTUALIZACJA ZAKRESU (dla następnej pętli) ===
v_min_dynamic = minV - (maxV - minV)*0.1;
v_max_dynamic = maxV + (maxV - minV)*0.1;
c_min_dynamic = minC - (maxC - minC)*0.1;
c_max_dynamic = maxC + (maxC - minC)*0.1;
if(v_max_dynamic <= v_min_dynamic) v_max_dynamic = v_min_dynamic + 0.1;
if(c_max_dynamic <= c_min_dynamic) c_max_dynamic = c_min_dynamic + 10;
// === BLOK 5: OBSŁUGA KLIENTA WWW ===
// Ta część kodu nie blokuje pomiarów. Działa tylko, gdy ktoś się połączy.
handle_web_client();
}
void handle_web_client() {
WiFiClient client = server.available();
if (!client) {
return;
}
while(!client.available()){
delay(1);
}
// Odpowiedź HTTP
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Refresh: 2"); // Odśwież stronę co 2 sekundy
client.println();
client.println("<!DOCTYPE HTML><html><head><title>ESP Pomiar Mocy</title>");
client.println("<style>body { font-family: sans-serif; background-color: #282c34; color: #abb2bf; } table { border-collapse: collapse; width: 50%; } td, th { border: 1px solid #61afef; text-align: left; padding: 8px; } th { background-color: #3e4451; } .val { color: #98c379; }</style>");
client.println("</head><body><h1>Pomiar poboru pradu przez ESP-01</h1>");
client.println("<table>");
client.println("<tr><th>Parametr</th><th>Wartosc</th></tr>");
client.print("<tr><td>Srednie Napiecie</td><td class='val'>"); client.print(last_Vavg, 3); client.println(" V</td></tr>");
client.print("<tr><td>Sredni Prad</td><td class='val'>"); client.print(last_Iavg, 2); client.println(" mA</td></tr>");
client.print("<tr><td>Srednia Moc</td><td class='val'>"); client.print(last_Vavg * last_Iavg, 2); client.println(" mW</td></tr>");
client.print("<tr><td>Min/Max Napiecie</td><td class='val'>"); client.print(last_minV, 3); client.print(" / "); client.print(last_maxV, 3); client.println(" V</td></tr>");
client.print("<tr><td>Min/Max Prad</td><td class='val'>"); client.print(last_minC, 2); client.print(" / "); client.print(last_maxC, 2); client.println(" mA</td></tr>");
client.print("<tr><td>Czestotliwosc (V/I)</td><td class='val'>"); client.print((int)last_freqV); client.print(" / "); client.print((int)last_freqC); client.println(" Hz</td></tr>");
client.print("<tr><td>Czas probkowania</td><td class='val'>"); client.print(last_time_span_s * 1000, 2); client.println(" ms (dla 150 probek)</td></tr>");
client.println("</table></body></html>");
delay(1);
client.stop();
}
/***************************************************************************
* Finalny, działający kod do wyświetlania danych z czujnika INA226
* na wyświetlaczu TFT. Działa po fizycznym rozdzieleniu połączeń I2C.
***************************************************************************/
// Biblioteki dla czujnika INA226
#include <Wire.h>
#include <INA226_WE.h>
// Biblioteki dla wyświetlacza TFT
#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
// --- Konfiguracja Czujnika INA226 ---
#define I2C_ADDRESS 0x40
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
// Definicje pinów sterujących dla Twojego shielda
#define LCD_CS A3
#define LCD_RS A2
#define LCD_WR A1
#define LCD_RD A0
// TUTAJ JEST NASZA ZMIANA! Mówimy, że RESET jest teraz na pinie 10
#define LCD_RESET 0
// Inicjalizujemy sterownik, podając mu wszystkie piny ręcznie
MCUFRIEND_kbv tft(LCD_CS, LCD_RS, LCD_WR, LCD_RD, LCD_RESET);
// Definicje kolorów
#define BLACK 0x0000
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
void setup() {
Serial.begin(9600);
Wire.begin();
// --- Inicjalizacja czujnika INA226 ---
if(!ina226.init()){
Serial.println("Nie udalo sie zainicjowac INA226. Sprawdz polaczenia.");
while(1){}
}
ina226.setMeasureMode(CONTINUOUS);
// --- Inicjalizacja wyświetlacza TFT ---
uint16_t id = 0x9341;
tft.begin(id);
tft.setRotation(1);
tft.fillScreen(BLACK);
tft.setTextSize(2);
// Wyświetl statyczne etykiety
tft.setTextColor(WHITE);
tft.setCursor(10, 20);
tft.println("Pomiar Mocy - INA226");
tft.drawRect(5, 10, 310, 35, CYAN);
tft.setTextColor(YELLOW);
tft.setCursor(10, 70);
tft.print("Napiecie V-Bus:");
tft.setCursor(10, 100);
tft.print("Napiecie bocznik:");
tft.setCursor(10, 130);
tft.print("Prad:");
tft.setCursor(10, 160);
tft.print("Moc:");
}
void loop() {
// Zmienne do przechowywania odczytów
float shuntVoltage_mV = 0.0;
float busVoltage_V = 0.0;
float current_mA = 0.0;
float power_mW = 0.0;
// Wartość rezystora i maksymalny oczekiwany prąd
ina226.setResistorRange(0.1, 0.5);
// Odczytaj wartości z czujnika
shuntVoltage_mV = ina226.getShuntVoltage_mV();
busVoltage_V = ina226.getBusVoltage_V();
current_mA = ina226.getCurrent_mA();
power_mW = ina226.getBusPower();
// --- Wyświetlanie danych na ekranie TFT ---
tft.setTextColor(GREEN);
tft.setTextSize(2);
// 1. Napięcie magistrali
tft.fillRect(210, 70, 100, 20, BLACK);
tft.setCursor(210, 70);
tft.print(busVoltage_V, 3);
tft.print(" V");
// 2. Napięcie bocznika
tft.fillRect(210, 100, 100, 20, BLACK);
tft.setCursor(210, 100);
tft.print(shuntVoltage_mV, 3);
tft.print(" mV");
// 3. Prąd
tft.fillRect(210, 130, 100, 20, BLACK);
tft.setCursor(210, 130);
tft.print(current_mA, 3);
tft.print(" mA");
// 4. Moc
tft.fillRect(210, 160, 100, 20, BLACK);
tft.setCursor(210, 160);
tft.print(power_mW, 3);
tft.print(" mW");
// Wyświetl status przepełnienia
tft.fillRect(10, 210, 300, 20, BLACK);
tft.setCursor(10, 210);
if(!ina226.overflow){
tft.setTextColor(GREEN);
tft.print("Status: OK");
} else {
tft.setTextColor(RED);
tft.print("Status: PRZEPELNIENIE!");
}
delay(1000); // Odświeżaj dane co sekundę
}
/***************************************************************************
* INA-skop v3.1: Wersja zoptymalizowana pod kątem RAM
* Zmniejszona liczba próbek, aby zmieścić się w pamięci Arduino Uno.
***************************************************************************/
#include <Wire.h>
#include <INA226_WE.h>
#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
// --- Konfiguracja ---
#define I2C_ADDRESS 0x40
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
#define LCD_CS A3
#define LCD_RS A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET 0
MCUFRIEND_kbv tft(LCD_CS, LCD_RS, LCD_WR, LCD_RD, LCD_RESET);
// --- Definicje kolorów ---
#define BLACK 0x0000
#define GREEN 0x07E0
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define GREY 0x8410
// --- Konfiguracja Oscyloskopu ---
// OPTYMALIZACJA RAM: Zmniejszamy liczbę próbek
#define NUM_SAMPLES 150
byte samples_voltage_y[NUM_SAMPLES];
byte samples_current_y[NUM_SAMPLES];
#define GRID_Y_TOP 50
#define GRID_Y_BOTTOM 210
#define GRID_X_LEFT 40
#define GRID_X_RIGHT 280
// Zmienne do automatycznego zakresu
float v_min_dynamic = 4.9, v_max_dynamic = 5.1;
float c_min_dynamic = 0.0, c_max_dynamic = 100.0;
void draw_grid_dual_axis(float v_min, float v_max, float c_min, float c_max);
void setup() {
Wire.begin();
if(!ina226.init()){ while(1); }
ina226.setAverage(AVERAGE_1);
ina226.setConversionTime(CONV_TIME_140);
ina226.setResistorRange(0.1, 0.5);
uint16_t id = 0x9341;
tft.begin(id);
tft.setRotation(1);
tft.fillScreen(BLACK);
}
void loop() {
float minV = 100.0, maxV = 0.0, sumV = 0.0;
float minC = 1000.0, maxC = 0.0, sumC = 0.0;
// 1. ZBIERANIE DANYCH
for(int i=0; i<NUM_SAMPLES; i++){
float voltage = ina226.getBusVoltage_V();
float current = ina226.getCurrent_mA();
if(voltage < minV) minV = voltage;
if(voltage > maxV) maxV = voltage;
sumV += voltage;
if(current < minC) minC = current;
if(current > maxC) maxC = current;
sumC += current;
int y_v = map(voltage*1000, v_min_dynamic*1000, v_max_dynamic*1000, GRID_Y_BOTTOM, GRID_Y_TOP);
int y_c = map(current*1000, c_min_dynamic*1000, c_max_dynamic*1000, GRID_Y_BOTTOM, GRID_Y_TOP);
samples_voltage_y[i] = constrain(y_v, GRID_Y_TOP, GRID_Y_BOTTOM);
samples_current_y[i] = constrain(y_c, GRID_Y_TOP, GRID_Y_BOTTOM);
}
// 2. AKTUALIZACJA ZAKRESU
v_min_dynamic = minV - (maxV - minV)*0.1;
v_max_dynamic = maxV + (maxV - minV)*0.1;
c_min_dynamic = minC - (maxC - minC)*0.1;
c_max_dynamic = maxC + (maxC - minC)*0.1;
if(v_max_dynamic <= v_min_dynamic) v_max_dynamic = v_min_dynamic + 0.1;
if(c_max_dynamic <= c_min_dynamic) c_max_dynamic = c_min_dynamic + 10;
// 3. RYSOWANIE
tft.fillScreen(BLACK);
draw_grid_dual_axis(v_min_dynamic, v_max_dynamic, c_min_dynamic, c_max_dynamic);
for(int i=1; i<NUM_SAMPLES; i++){
int x1 = map(i-1, 0, NUM_SAMPLES, GRID_X_LEFT, GRID_X_RIGHT);
int x2 = map(i, 0, NUM_SAMPLES, GRID_X_LEFT, GRID_X_RIGHT);
tft.drawLine(x1, samples_voltage_y[i-1], x2, samples_voltage_y[i], GREEN);
tft.drawLine(x1, samples_current_y[i-1], x2, samples_current_y[i], YELLOW);
}
// 4. WYŚWIETL STATYSTYKI
float Vavg = sumV / NUM_SAMPLES;
float Iavg = sumC / NUM_SAMPLES;
tft.setTextSize(2);
tft.setCursor(10, 10);
tft.setTextColor(GREEN);
tft.print("V: ");
tft.print(Vavg, 2);
tft.setCursor(160, 10);
tft.setTextColor(YELLOW);
tft.print("I: ");
tft.print(Iavg, 1);
tft.print("mA");
}
void draw_grid_dual_axis(float v_min, float v_max, float c_min, float c_max){
tft.drawRect(GRID_X_LEFT, GRID_Y_TOP, GRID_X_RIGHT - GRID_X_LEFT, GRID_Y_BOTTOM - GRID_Y_TOP, GREY);
tft.setTextSize(1);
tft.setTextColor(GREEN);
tft.setCursor(2, GRID_Y_TOP + 5);
tft.print(v_max, 2);
tft.print("V");
tft.setCursor(2, GRID_Y_BOTTOM - 10);
tft.print(v_min, 2);
tft.print("V");
tft.setTextColor(YELLOW);
tft.setCursor(GRID_X_RIGHT + 5, GRID_Y_TOP + 5);
tft.print(c_max, 0);
tft.print("mA");
tft.setCursor(GRID_X_RIGHT + 5, GRID_Y_BOTTOM - 10);
tft.print(c_min, 0);
tft.print("mA");
}
/***************************************************************************
* INA-skop v4.3: Wersja OSTATECZNA.
* NAPRAWIONO błąd z obcinaniem precyzji w funkcji map() dla prądu.
* Przywrócono oryginalną, działającą logikę skalowania.
***************************************************************************/
#include <Wire.h>
#include <INA226_WE.h>
#include <Adafruit_GFX.h>
#include <MCUFRIEND_kbv.h>
// --- Konfiguracja ---
#define I2C_ADDRESS 0x40
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
#define LCD_CS A3
#define LCD_RS A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET 0
MCUFRIEND_kbv tft(LCD_CS, LCD_RS, LCD_WR, LCD_RD, LCD_RESET);
// --- Definicje kolorów ---
#define BLACK 0x0000
#define GREEN 0x07E0
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define GREY 0x8410
#define ORANGE 0xFD20
// --- Konfiguracja Oscyloskopu ---
#define NUM_SAMPLES 150
byte samples_voltage_y[NUM_SAMPLES];
byte samples_current_y[NUM_SAMPLES];
int voltage_samples_mV[NUM_SAMPLES];
int current_samples_mA[NUM_SAMPLES];
#define GRID_Y_TOP 60
#define GRID_Y_BOTTOM 210
#define GRID_X_LEFT 40
#define GRID_X_RIGHT 280
// Zmienne do automatycznego zakresu (serce oryginalnej logiki)
float v_min_dynamic = 4.9, v_max_dynamic = 5.1;
float c_min_dynamic = 0.0, c_max_dynamic = 100.0;
void draw_grid_dual_axis(float v_min, float v_max, float c_min, float c_max);
void setup() {
Wire.begin();
if(!ina226.init()){ while(1); }
ina226.setAverage(AVERAGE_1);
ina226.setConversionTime(CONV_TIME_140);
ina226.setResistorRange(0.1, 0.5);
uint16_t id = 0x9341;
tft.begin(id);
tft.setRotation(1);
tft.fillScreen(BLACK);
}
void loop() {
// === BLOK 1: ZBIERANIE DANYCH (pozostaje bez zmian) ===
float minV = 100.0, maxV = 0.0, sumV = 0.0;
float minC = 1000.0, maxC = 0.0, sumC = 0.0;
long startTime = micros();
for(int i=0; i<NUM_SAMPLES; i++){
float voltage = ina226.getBusVoltage_V();
float current = ina226.getCurrent_mA();
voltage_samples_mV[i] = voltage * 1000;
current_samples_mA[i] = current;
if(voltage < minV) minV = voltage;
if(voltage > maxV) maxV = voltage;
sumV += voltage;
if(current < minC) minC = current;
if(current > maxC) maxC = current;
sumC += current;
int y_v = map(voltage*1000, v_min_dynamic*1000, v_max_dynamic*1000, GRID_Y_BOTTOM, GRID_Y_TOP);
int y_c = map(current*100, c_min_dynamic*100, c_max_dynamic*100, GRID_Y_BOTTOM, GRID_Y_TOP);
samples_voltage_y[i] = constrain(y_v, GRID_Y_TOP, GRID_Y_BOTTOM);
samples_current_y[i] = constrain(y_c, GRID_Y_TOP, GRID_Y_BOTTOM);
}
long endTime = micros();
// === BLOK 2: OBLICZENIA (pozostaje bez zmian) ===
int v_zero_crossings = 0, c_zero_crossings = 0;
long v_avg_mV = sumV * 1000 / NUM_SAMPLES;
long c_avg_mA = sumC / NUM_SAMPLES;
for (int i = 1; i < NUM_SAMPLES; i++) {
if ((voltage_samples_mV[i-1] < v_avg_mV && voltage_samples_mV[i] >= v_avg_mV) || (voltage_samples_mV[i-1] > v_avg_mV && voltage_samples_mV[i] <= v_avg_mV)) v_zero_crossings++;
if ((current_samples_mA[i-1] < c_avg_mA && current_samples_mA[i] >= c_avg_mA) || (current_samples_mA[i-1] > c_avg_mA && current_samples_mA[i] <= c_avg_mA)) c_zero_crossings++;
}
float time_span_s = (endTime - startTime) / 1000000.0f;
float freqV = (v_zero_crossings / 2.0) / time_span_s;
float freqC = (c_zero_crossings / 2.0) / time_span_s;
float Vavg = sumV / NUM_SAMPLES;
float Iavg = sumC / NUM_SAMPLES;
// === BLOK 3: RYSOWANIE I WYŚWIETLANIE (NOWA KOLEJNOŚĆ) ===
// 3a. Najpierw przygotuj tło i siatkę
tft.fillScreen(BLACK);
draw_grid_dual_axis(v_min_dynamic, v_max_dynamic, c_min_dynamic, c_max_dynamic);
// 3b. Wyświetl statystyki (SZYBKIE) - PRZENIESIONE NA POCZĄTEK
tft.setTextSize(2);
tft.setCursor(10, 10); tft.setTextColor(GREEN); tft.print("V: "); tft.print(Vavg, 2);
tft.setCursor(160, 10); tft.setTextColor(YELLOW); tft.print("I: "); tft.print(Iavg, 1); tft.print("mA");
tft.setCursor(10, 35); tft.setTextColor(ORANGE); tft.print("F(v):"); tft.print((int)freqV);
tft.setCursor(160, 35); tft.print("F(i):"); tft.print((int)freqC);
// 3c. Dopiero teraz narysuj wykres (CZASOCHŁONNE)
for(int i=1; i<NUM_SAMPLES; i++){
int x1 = map(i-1, 0, NUM_SAMPLES, GRID_X_LEFT, GRID_X_RIGHT);
int x2 = map(i, 0, NUM_SAMPLES, GRID_X_LEFT, GRID_X_RIGHT);
tft.drawLine(x1, samples_voltage_y[i-1], x2, samples_voltage_y[i], GREEN);
tft.drawLine(x1, samples_current_y[i-1], x2, samples_current_y[i], YELLOW);
}
// === BLOK 4: AKTUALIZACJA ZAKRESU (pozostaje bez zmian) ===
v_min_dynamic = minV - (maxV - minV)*0.1;
v_max_dynamic = maxV + (maxV - minV)*0.1;
c_min_dynamic = minC - (maxC - minC)*0.1;
c_max_dynamic = maxC + (maxC - minC)*0.1;
if(v_max_dynamic <= v_min_dynamic) v_max_dynamic = v_min_dynamic + 0.1;
if(c_max_dynamic <= c_min_dynamic) c_max_dynamic = c_min_dynamic + 10;
}
void draw_grid_dual_axis(float v_min, float v_max, float c_min, float c_max){
tft.drawRect(GRID_X_LEFT, GRID_Y_TOP, GRID_X_RIGHT - GRID_X_LEFT, GRID_Y_BOTTOM - GRID_Y_TOP, GREY);
tft.setTextSize(1);
tft.setTextColor(GREEN);
tft.setCursor(2, GRID_Y_TOP + 5); tft.print(v_max, 2); tft.print("V");
tft.setCursor(2, GRID_Y_BOTTOM - 10); tft.print(v_min, 2); tft.print("V");
tft.setTextColor(YELLOW);
tft.setCursor(GRID_X_RIGHT + 5, GRID_Y_TOP + 5); tft.print(c_max, 0); tft.print("mA");
tft.setCursor(GRID_X_RIGHT + 5, GRID_Y_BOTTOM - 10); tft.print(c_min, 0); tft.print("mA");
}
#include <Wire.h>
// Dołącz biblioteki do wszystkich trzech urządzeń
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_ADS1X15.h>
#include <INA226_WE.h>
#include <avr/power.h>
#include <avr/sleep.h>
// --- Konfiguracja Wyświetlacza OLED ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// --- Konfiguracja ADS1115 ---
Adafruit_ADS1115 ads;
// --- Konfiguracja INA226 (z użyciem biblioteki INA226_WE) ---
#define I2C_ADDRESS 0x40
INA226_WE ina226 = INA226_WE(I2C_ADDRESS);
void optimizePower_NoSerial() {
// --- Krok 1: Konfiguracja wszystkich nieużywanych pinów ---
// Teraz D0 i D1 są również wolne.
// Piny cyfrowe D0 do D13 (ŻADNYCH WYJĄTKÓW)
for (uint8_t i = 0; i <= 13; i++) {
pinMode(i, INPUT_PULLUP);
}
// Piny analogowe A0 do A3 oraz A6, A7 (A4, A5 zajęte przez I2C)
for (uint8_t i = 14; i <= 17; i++) { // A0-A3
pinMode(i, INPUT_PULLUP);
}
pinMode(20, INPUT_PULLUP); // A6
pinMode(21, INPUT_PULLUP); // A7
// --- Krok 2: Wyłączenie wszystkich nieużywanych peryferiów ---
// Wyłącz wbudowany ADC (przetwornik analogowo-cyfrowy).
power_adc_disable();
// Wyłącz interfejs SPI.
power_spi_disable();
// Wyłącz Timer1.
power_timer1_disable();
// Wyłącz Timer2.
power_timer2_disable();
// NOWOŚĆ: Wyłączamy moduł USART (Serial), ponieważ go nie używamy.
// To daje dodatkową oszczędność energii.
power_usart0_disable();
// UWAGA: Nadal NIE wyłączamy Timer0 (dla millis()) i TWI (dla I2C).
}
void setup() {
optimizePower_NoSerial();
Wire.begin();
// --- Inicjalizacja Urządzeń (bez zmian) ---
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { while(1); }
display.clearDisplay(); display.setTextSize(1); display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0); display.println("Inicjalizacja..."); display.display();
if (!ads.begin()) { while (1); }
if (!ina226.init()) { while (1); }
ina226.setResistorRange(0.1, 1.0);
ina226.setAverage(AVERAGE_16);
ina226.setConversionTime(CONV_TIME_1100);
ads.setGain(GAIN_TWOTHIRDS);
}
// =========================================================================
// == NOWA, ULEPSZONA FUNKCJA WYŚWIETLANIA ==
// Ta funkcja zastępuje Twój obecny blok "display" w pętli loop()
// =========================================================================
void printPadded(float value, int precision) {
// Jeśli liczba jest nieujemna, dodaj spację z przodu, aby wyrównać tekst
if (value >= 0) {
display.print(" ");
}
display.print(value, precision);
}
void loop() {
// --- Zmienne do przechowywania odczytów (bez zmian) ---
float inaVoltage = 0.0;
float inaCurrent = 0.0;
float adsSingleEnded[4];
float adsDifferential[4];
// --- Pomiar z INA226 (bez zmian) ---
inaVoltage = ina226.getBusVoltage_V();
inaCurrent = ina226.getCurrent_mA();
// --- Pomiar wszystkich kanałów ADS1115 (bez zmian) ---
for(int i=0; i<4; i++){
adsSingleEnded[i] = ads.computeVolts(ads.readADC_SingleEnded(i));
}
adsDifferential[0] = ads.computeVolts(ads.readADC_Differential_0_1());
adsDifferential[1] = ads.computeVolts(ads.readADC_Differential_0_3());
adsDifferential[2] = ads.computeVolts(ads.readADC_Differential_1_3());
adsDifferential[3] = ads.computeVolts(ads.readADC_Differential_2_3());
// --- NOWY, ULEPSZONY BLOK WYŚWIETLANIA ---
display.clearDisplay();
display.setTextSize(1);
// Sekcja INA226 z nowymi etykietami
display.setCursor(0, 0);
display.print("IV:"); printPadded(inaVoltage, 3); display.print("V");
display.setCursor(64, 0); // Druga kolumna
display.print("II:"); printPadded(inaCurrent, 1); display.print("mA");
// Linia oddzielająca dla czytelności
display.drawFastHLine(0, 12, SCREEN_WIDTH, SSD1306_WHITE);
// Sekcja ADS1115 Single-Ended z nowymi etykietami
display.setCursor(0, 16);
display.print("0G:"); printPadded(adsSingleEnded[0], 3);
display.setCursor(64, 16);
display.print("1G:"); printPadded(adsSingleEnded[1], 3);
display.setCursor(0, 24);
display.print("2G:"); printPadded(adsSingleEnded[2], 3);
display.setCursor(64, 24);
display.print("3G:"); printPadded(adsSingleEnded[3], 3);
// Linia oddzielająca dla czytelności
display.drawFastHLine(0, 36, SCREEN_WIDTH, SSD1306_WHITE);
// Sekcja ADS1115 Differential
display.setCursor(0, 40);
display.print("01:"); printPadded(adsDifferential[0], 2);
display.setCursor(64, 40);
display.print("03:"); printPadded(adsDifferential[1], 2);
display.setCursor(0, 48);
display.print("13:"); printPadded(adsDifferential[2], 2);
display.setCursor(64, 48);
display.print("23:"); printPadded(adsDifferential[3], 2);
display.display();
// --- Pętla uśpienia (bez zmian) ---
unsigned long startMillis = millis();
while (millis() - startMillis < 1000) { // Zmieniono na 1000ms dla lepszej czytelności
sleep_enable();
sleep_cpu();
sleep_disable();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment