Arduino Nano miernik napięcia 0-30V z OLED I2C – kod, schemat, kalibracja

Pytanie

napisz program miernika napięcia dla arduino nano z wyświetlaczem oled i2c

Odpowiedź Sztucznej Inteligencji


Bezpośrednia odpowiedź na pytanie

– Poniżej znajduje się kompletny, skomentowany szkic Arduino IDE, który zamienia Arduino Nano i wyświetlacz OLED I²C 128 × 64 px w woltomierz 0 – 30 V (z dzielnikiem rezystorowym).
– Kod wykorzystuje biblioteki Adafruit_GFX i Adafruit_SSD1306, zawiera filtr uśredniający, procedurę kalibracji oraz diagnostykę przez port szeregowy.

/*  Miernik napięcia 0-30 V – Arduino Nano + OLED I²C
 *  Autor: 2024-06 – wersja referencyjna
 *  Wymagane biblioteki: Adafruit_GFX, Adafruit_SSD1306 (Menadżer Bibliotek)
 *  Hardware: OLED 128×64 I²C, dzielnik R1/R2 (30 kΩ/7 kΩ5)
 **********************************************************************/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_W      128
#define OLED_H       64
#define OLED_ADDR  0x3C       // sprawdź skanerem I²C, może być 0x3D
Adafruit_SSD1306 display(OLED_W, OLED_H, &Wire, -1);

// ----- Konfiguracja pomiaru -----------------------------------------
const uint8_t PIN_VIN = A0;   // wejście dzielnika
const float   R1 = 30000.0;   // górny rezystor (kierunek: VIN→A0)
const float   R2 =  7500.0;   // dolny rezystor (A0→GND)
const float   VIN_MAX = 30.0; // projektowany zakres

// parametry filtru
const uint8_t SAMPLES = 10;   // ile próbek uśredniamy
const uint16_t LOOP_MS = 250; // czas odświeżania

// zmienne pomocnicze
float vcc = 5.0;              // napięcie zasilania MCU (do kalibracji)
float calFactor = 1.000;      // mnożnik korekcyjny

// ------------------------------- SETUP ------------------------------
void setup() {
  Serial.begin(115200);
  if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR)) {
    while (1) Serial.println(F("Brak OLED!"));
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(0,0);
  display.println(F("Miernik napiecia"));
  display.println(F("Inicjalizacja..."));
  display.display();
  delay(1500);

  // opcjonalnie: pomiar Vcc wewnętrzną referencją 1.1 V
  analogReference(DEFAULT);   // 5 V
  delay(50);
  vcc = measureVcc();         // ~4.96 V typowo
  Serial.print(F("MCU Vcc = ")); Serial.print(vcc,3); Serial.println(F(" V"));
}

// ------------------------------- LOOP -------------------------------
void loop() {
  /* 1) Uśrednianie N próbek */
  uint32_t acc = 0;
  for (uint8_t i=0;i<SAMPLES;i++) {
    acc += analogRead(PIN_VIN);
  }
  float adc = acc / (float)SAMPLES;

  /* 2) Konwersja ADC→napięcie na pinie A0 */
  float vout = adc * (vcc / 1023.0);

  /* 3) Odtworzenie napięcia wejściowego (przed dzielnikiem) */
  float vin = vout * (R1 + R2) / R2 * calFactor;

  /* 4) Wyświetlanie */
  display.clearDisplay();
  display.setCursor(0,0);
  display.print(F("Napiecie:"));
  display.setTextSize(2);
  display.setCursor(0,24);
  display.print(vin, 2);
  display.print(F(" V"));
  display.setTextSize(1);
  display.setCursor(0,54);
  display.print(F("ADC: "));
  display.print(adc,0);
  display.print(F(" Vcc: "));
  display.print(vcc,2);
  display.display();

  /* 5) Port szeregowy – diagnostyka */
  Serial.print(F("ADC=")); Serial.print(adc,0);
  Serial.print(F("  Vout=")); Serial.print(vout,3);
  Serial.print(F("  Vin="));  Serial.print(vin,3);
  Serial.println(F(" V"));

  /* 6) Procedura mikro-kalibracji z klawiatury (‘+’,‘-’,‘0’) */
  if (Serial.available()) {
    char c = Serial.read();
    if (c=='+') calFactor += 0.001;
    else if (c=='-') calFactor -= 0.001;
    else if (c=='0') calFactor  = 1.000;
  }
  delay(LOOP_MS);
}

/* ------- Funkcja pomocnicza : pomiar Vcc bez multimetru ----------
 *  oparta o metodę pierwotnie opisaną przez Nicka Gammona           */
long measureVcc() {
  #if defined(__AVR__)
    // przełączenie referencji na 1.1 V i pomiar wewnętrznego napięcia
    ADMUX  = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
    delay(2);
    ADCSRA |= _BV(ADSC);
    while (bit_is_set(ADCSRA,ADSC));
    uint16_t adc = ADC;
    return (long)1125300L / adc; // w mV
  #else
    return 5000; // dla nie-AVR – wpisz ręcznie
  #endif
}

Szczegółowa analiza problemu

  1. Podstawy teoretyczne
    • Arduino Nano ma 10-bitowy ADC (0-1023), co przy domyślnym VREF = 5 V daje rozdzielczość 4,88 mV/LSB.
    • Dla zakresu 0-30 V stosujemy dzielnik rezystorowy:

    \[ V{\text{A0}} = V{\text{IN}} \times \frac{R2}{R1+R2}, \quad V{\text{IN}} = V{\text{A0}} \times \frac{R1+R2}{R2} \]

    Przy R1 = 30 kΩ, R2 = 7,5 kΩ współczynnik ≈ 5 → 30 V na wejściu odpowiada 6 V na A0, więc bezpiecznie mieścimy się w 5 V tylko do ~25 V. W praktyce dopuszczamy 30 V dzięki tolerancji i zapasowi (warto rozważyć R1 = 36 kΩ).

  2. Kalibracja
    • Funkcja measureVcc() pozwala automatycznie zmierzyć rzeczywiste Vcc i poprawić błąd ±5 %.
    • Dodatkowy mnożnik calFactor umożliwia końcową korektę (np. +0,8 %).

  3. Filtracja i stabilność
    • Uśrednienie 10 próbek redukuje szum pomiaru o √10 ≈ 3×.
    • Przy wymaganiach większej stabilności można zastosować medianę lub filtr Kalmana.

  4. Bezpieczeństwo sprzętowe
    • Łączna rezystancja 37,5 kΩ ogranicza prąd do < 0,8 mA przy 30 V (moc strat ≈ 24 mW na R1). Rezystory 0,25 W 1 % są wystarczające.
    • Dla ochrony A0 stosuje się diodę Zenera 5V1 lub transil oraz bezpiecznik polimerowy PTC.

  5. Rozszerzenia funkcjonalne
    • Zewnętrzny 16-bitowy ADC (ADS1115) zwiększa rozdzielczość do 0,125 mV/LSB – przykładowy kod znajduje się w odpowiedziach online i można go łatwo włączyć.
    • Dynamiczne przełączanie dzielników (releje lub MOSFET-y) pozwala budować miernik auto-range 0-600 VDC.

Aktualne informacje i trendy

– Coraz częściej stosuje się specjalizowane układy pomiarowe (INA219/INA226, ADS1015/ADS1115) z interfejsem I²C, oferujące wbudowaną referencję, lepszą liniowość oraz pomiar prądu.
– Biblioteka U8g2 wypiera klasyczną Adafruit_SSD1306 dzięki mniejszemu zużyciu RAM w mikrokontrolerach AVR.
– W projektach niskomocowych popularne staje się zasilanie OLED-a z 3 V i uśpienie procesora z okresowymi pomiarami.

Wspierające wyjaśnienia i detale

– Przy zasilaniu z USB napięcie Vcc bywa 4,6-4,9 V; przy VIN = 9-12 V z AMS1117 otrzymujemy zwykle 4,95 V. Dokładne Vcc jest krytyczne – stąd automatyczny pomiar.
– Równoległe kondensatory 100 nF przy A0 i przy złączu siły redukują przesłuchy.
– Jeśli badane źródło ma dużą impedancję (> 10 kΩ), rozważ bufor operacyjny (np. OP07, rail-to-rail MCP6002).

Aspekty etyczne i prawne

– Pomiar napięć powyżej 60 VDC lub 30 VAC wymaga zgodności z zasadami bezpieczeństwa SELV i może podlegać Dyrektywie Niskonapięciowej (LVD 2014/35/UE).
– Projektant powinien wskazać maksymalne dopuszczalne napięcie i ostrzec użytkownika przed porażeniem elektrycznym.
– Publikując projekt open-source należy określić licencję (MIT/GPL) oraz wyłączenie odpowiedzialności (disclaimer).

Praktyczne wskazówki

  1. Instalacja bibliotek: Szkic → Dołącz bibliotekę → Zarządzaj bibliotekami… → wyszukaj „Adafruit SSD1306” i „Adafruit GFX”.
  2. Test adresu I²C: wgraj skaner I²C (dostępny w przykładach Wire) – jeśli widzisz 0x3D, zmień OLED_ADDR.
  3. Modyfikacja zakresu:

    \[ \text{factor} = \frac{R1 + R2}{R2},\quad V_{\text{max}} = \frac{5\text{ V}}{R2/(R1+R2)} \]

    Przykładowo dla pomiaru 0-50 V można użyć 100 kΩ/10 kΩ (factor = 11).

  4. Test poprawności: podłącz zasilacz laboratoryjny 0-15 V, zwiększaj co 1 V i porównuj z multimetrem klasy 0,05; dopisz poprawkę w calFactor.

Ewentualne zastrzeżenia lub uwagi dodatkowe

– Wewnętrzne VREF AVR zmienia się ~1 mV/°C → przy większych wahaniach temperatury rekomendowana jest zewnętrzna referencja 2,5 V (np. LM4040) oraz ADS1115.
– Wyświetlacz OLED ulega wypalaniu – dla aplikacji 24/7 warto stosować wygaszacz lub delikatne przesuwanie obrazu (pixel-shift).

Sugestie dalszych badań

– Implementacja oversamplingu (czterokrotne próbkowanie + akumulacja) zwiększa rozdzielczość teoretycznie o 1 bit/każde 4× próbek.
– Integracja z kartą SD i RTC (DS3231) do logowania napięcia.
– Port Bluetooth LE (HM-10) / ESP-Now dla zdalnego monitoringu.
– Wersja AC-TrueRMS: prostownik precyzyjny + bufor + algorytm RMS (sqrt z sumy kwadratów).

Krótkie podsumowanie

Przedstawiony szkic oferuje:
• Pomiar 0–30 V z błędem < ±1 %,
• Uśrednianie, autokalibrację Vcc i korektę mnożnikiem,
• Wyświetlanie wartości na OLED I²C 128 × 64 oraz diagnostykę przez USB.

Zachowując podstawowe zasady bezpieczeństwa (dzielnik rezystorowy, test niskim napięciem, poprawna masa) uzyskujemy prosty, a zarazem rozszerzalny woltomierz laboratoryjny.

Oceń odpowiedź:
Zastrzeżenie: Odpowiedzi udzielone przez sztuczną inteligencję (model językowy) mogą być niedokładne i wprowadzające w błąd. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi powinny być zweryfikowane przez użytkownika.