napisz program miernika napięcia dla arduino nano z wyświetlaczem oled i2c
– 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
}
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Ω).
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 %).
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.
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.
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.
– 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.
– 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).
– 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).
OLED_ADDR
. 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).
calFactor
. – 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).
– 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).
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.