napisz program miernika napięcia dla arduino nano z wyświetlaczem oled i2c
Tak — poniżej masz gotowy, działający program miernika napięcia dla Arduino Nano z wyświetlaczem OLED I2C.
Program:
Poniżej przedstawiam kompletny projekt: połączenia, kod, wyjaśnienie działania i uwagi kalibracyjne.
Arduino Nano z ATmega328P ma przetwornik ADC 10-bitowy, czyli:
\[
ADC \in \langle 0,\ 1023 \rangle
\]
Przy domyślnym napięciu odniesienia:
\[
V_{REF} \approx 5.0\text{ V}
\]
bezpośrednio można mierzyć tylko napięcia z zakresu:
\[
0 \text{ V} \; \text{do} \; 5 \text{ V}
\]
Jeżeli chcesz mierzyć wyższe napięcie, musisz zastosować dzielnik rezystorowy.
Proponuję:
Współczynnik przeliczenia:
\[
k = \frac{R1 + R2}{R2} = \frac{56k + 10k}{10k} = 6.6
\]
Zatem napięcie wejściowe:
\[
V{IN} = V{A0} \cdot 6.6
\]
Dla 30 V na wejściu:
\[
V_{A0} = 30 \cdot \frac{10}{56+10} \approx 4.55\text{ V}
\]
czyli bezpiecznie poniżej 5 V.
| OLED | Arduino Nano |
|---|---|
| VCC | 5V |
| GND | GND |
| SDA | A4 |
| SCL | A5 |
| Element | Połączenie |
|---|---|
| badane napięcie „+” | do R1 |
| R1 = 56 kΩ | między wejściem napięcia a punktem pomiarowym |
| punkt pomiarowy | do A0 |
| R2 = 10 kΩ | między punktem pomiarowym a GND |
| badane napięcie „−” | do GND Arduino |
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// =========================
// Konfiguracja OLED
// =========================
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
#define OLED_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// =========================
// Konfiguracja pomiaru
// =========================
const byte VOLTAGE_PIN = A0;
// Dzielnik napięcia:
// Vin --- R1 ---+--- A0
// |
// R2
// |
// GND
const float R1 = 56000.0; // 56k
const float R2 = 10000.0; // 10k
// Ustaw rzeczywiste napięcie zasilania Arduino.
// Zmierz multimetrem napięcie między 5V i GND.
// Na początek zostaw 5.00, potem skalibruj.
const float VREF = 5.00;
// Dodatkowy współczynnik kalibracyjny.
// Po porównaniu z dobrym multimetrem możesz np. ustawić 0.995 lub 1.008
const float CAL_FACTOR = 1.000;
// Parametry pracy
const byte NUM_SAMPLES = 32;
const unsigned long REFRESH_MS = 200;
const float MAX_DISPLAY_VOLTAGE = 30.0; // skala paska
unsigned long lastRefresh = 0;
// =========================
// Funkcja pomiaru napięcia
// =========================
float measureVoltage()
{
unsigned long sum = 0;
for (byte i = 0; i < NUM_SAMPLES; i++)
{
sum += analogRead(VOLTAGE_PIN);
delayMicroseconds(200);
}
float adcAvg = (float)sum / NUM_SAMPLES;
// Napięcie na pinie A0
float vA0 = adcAvg * (VREF / 1023.0);
// Napięcie wejściowe przed dzielnikiem
float vIn = vA0 * ((R1 + R2) / R2);
// Kalibracja
vIn *= CAL_FACTOR;
// Odcinanie drobnych śmieci przy 0V
if (vIn < 0.02) vIn = 0.0;
return vIn;
}
// =========================
// Rysowanie ekranu
// =========================
void drawScreen(float voltage)
{
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
// Nagłówek
display.setTextSize(1);
display.setCursor(0, 0);
display.print(F("Miernik napiecia DC"));
display.drawLine(0, 10, 127, 10, SSD1306_WHITE);
// Duzy odczyt
display.setTextSize(3);
display.setCursor(0, 18);
display.print(voltage, 2);
display.setTextSize(2);
display.print(F("V"));
// Pasek
int barWidth = (int)(voltage / MAX_DISPLAY_VOLTAGE * 120.0);
if (barWidth < 0) barWidth = 0;
if (barWidth > 120) barWidth = 120;
display.setTextSize(1);
display.setCursor(0, 46);
display.print(F("Zakres wyswietlania: 0-30V"));
display.drawRect(4, 56, 120, 6, SSD1306_WHITE);
display.fillRect(4, 56, barWidth, 6, SSD1306_WHITE);
display.display();
}
void setup()
{
Serial.begin(115200);
pinMode(VOLTAGE_PIN, INPUT);
analogReference(DEFAULT); // dla klasycznego Nano: odniesienie do VCC (~5V)
if (!display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDRESS))
{
Serial.println(F("Blad inicjalizacji OLED"));
while (true) { }
}
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setTextSize(2);
display.setCursor(8, 16);
display.println(F("WOLTOMIERZ"));
display.setTextSize(1);
display.setCursor(22, 42);
display.println(F("Arduino Nano + OLED"));
display.display();
delay(1500);
}
void loop()
{
if (millis() - lastRefresh >= REFRESH_MS)
{
lastRefresh = millis();
float voltage = measureVoltage();
drawScreen(voltage);
Serial.print(F("Napiecie: "));
Serial.print(voltage, 3);
Serial.println(F(" V"));
}
}
Ten program jest lepszy od najprostszej wersji z kilku powodów:
VREF i CAL_FACTOR,W dostarczonych odpowiedziach były dwie częste nieścisłości, które warto skorygować:
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
a nie w formie charakterystycznej dla innych bibliotek lub błędnych makr.
Na podstawie dostarczonych odpowiedzi online i praktyki projektowej można przyjąć, że obecnie najczęściej w takich projektach stosuje się:
Adafruit_GFXAdafruit_SSD1306W praktyce konstrukcyjnej coraz częściej zamiast prostego pomiaru na wejściu ADC stosuje się również:
Dla prostego hobbystycznego woltomierza Arduino Nano + SSD1306 nadal jednak jest rozwiązaniem wystarczającym.
Arduino mierzy napięcie na pinie A0:
\[
V{A0} = \frac{ADC}{1023} \cdot V{REF}
\]
Ponieważ na A0 trafia napięcie już podzielone przez dzielnik, napięcie rzeczywiste wynosi:
\[
V{IN} = V{A0} \cdot \frac{R1 + R2}{R2}
\]
Po podstawieniu:
\[
V{IN} = \frac{ADC}{1023} \cdot V{REF} \cdot \frac{R1 + R2}{R2}
\]
To właśnie realizuje kod.
Wejście analogowe i długi przewód pomiarowy łatwo zbierają zakłócenia.
Kondensator 100 nF z A0 do GND tworzy prosty filtr RC, który:
Zbyt duża rezystancja dzielnika pogarsza warunki pracy wejścia ADC.
ATmega328P lubi źródło o niezbyt dużej impedancji.
Układ 56 kΩ / 10 kΩ daje kompromis między:
W tym projekcie najważniejsze są kwestie bezpieczeństwa elektrycznego.
Adafruit GFXAdafruit SSD1306VREF.Jeżeli multimetr pokazuje 12.00 V, a Arduino 11.82 V, to:
\[
CAL_FACTOR = \frac{12.00}{11.82} \approx 1.015
\]
Wtedy ustaw:
const float CAL_FACTOR = 1.015;
VREF,Jeżeli potrzebujesz większej dokładności, warto przejść na:
Jeżeli chcesz rozbudować projekt, kolejne sensowne kroki to:
Można też przygotować wersję:
Najprostsza poprawna realizacja miernika napięcia dla Arduino Nano i OLED I2C to:
VREF.Podałem Ci gotowy, praktyczny i technicznie poprawny program.
Jeśli chcesz, mogę od razu przygotować także: