Этот проект представляет собой двухканальный цифровой вольтметр на базе Arduino, предназначенный для одновременного измерения входного и выходного напряжения, а также отображения максимального зафиксированного значения и реального графика изменения напряжения во времени.
🟢 Входное напряжение (V In)
🔵 Выходное напряжение (V Out)
🔺 Максимальное выходное напряжение (V Max)
📉 График изменения выходного напряжения
📊 Вертикальную шкалу напряжения справа
Это отличный проект для начинающих радиолюбителей и разработчиков лабораторных блоков питания: он наглядно показывает работу стабилизаторов, поведение напряжения под нагрузкой и позволяет оценивать динамику процессов.
🔧 Используемые компоненты
⚙️ Схема подключения
🔌 Подключение компонентов
🎛️ Измерение напряжений:
Arduino измеряет напряжения через аналоговые входы A0 и A1. Но напрямую подавать на них более 5 В опасно. Поэтому используются резистивные делители напряжения.
📥 Делитель для входного напряжения (V In → A0):
Входной сигнал подаётся на верхний резистор
Средняя точка подключается к A0
Позволяет измерять до 25 В
📤 Делитель для выходного напряжения (V Out → A1):
Средняя точка подключается к A1
Такой делитель даёт коэффициент ≈ 1/5, что позволяет измерять до 25 В
⚠️ Подбирайте резисторы с учётом нужного диапазона. Программа изначально рассчитана на вход 0–5 В, поэтому при использовании делителей нужно изменить формулу расчёта напряжения.
⚙️ Как работает программа
Программа построена на основе двух объектов класса VoltMeter, каждый из которых отвечает за измерение напряжения по одному из входов.
А также один экземпляр класса Oscilloscope (осциллограф)
📦 Смотри раздел "Скетч Arduino"
Выполняется analogRead() на пинах A0 и A1.
Полученные значения преобразуются в вольты: voltage = raw * (5.0 / 1023.0);
При необходимости можно умножать результат на коэффициент делителя, например voltage *= 2.0;
Все показания (V In, V Out, V Max) отображаются в верхней части дисплея крупным текстом.
Используется шрифт TextSize(1) для чёткости и экономии места.
В каждом измерении программа сравнивает текущее значение с предыдущим максимумом.
При нажатии на кнопку (подключенную к D2) максимум сбрасывается.
Отдельный класс Oscilloscope сохраняет последние измерения в буфере.
В нижней части дисплея рисуется линия, отображающая изменение напряжения во времени.
График занимает 110 пикселей по горизонтали и не наезжает на шкалу.
Вертикальная шкала справа:
Сегментная шкала (10 делений) показывает текущий уровень выходного напряжения.
Обновляется при каждом цикле измерения.
🧠 Дисплей
Размещение основных блоков отображения на экране OLED дисплея
Программа строит интерфейс в несколько этапов:
Верхняя часть дисплея — отображает входное и максимальные значения напряжения
Средняя часть — напряжение на выходе блока питания.
Нижняя часть — график напряжения во времени, построенный с использованием массива graphBuffer[], в котором хранятся последние 128 измерений. Этот массив сдвигается каждый раз и отображается как ломаная линия, повторяя форму изменения напряжения.
Правая часть — визуальный уровень напряжения в виде сегментной шкалы, где каждый сегмент активен в зависимости от уровня сигнала.
Такой подход позволяет использовать OLED-дисплей максимально эффективно: информативно и красиво.
📜 Скетч Arduino
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
const int inputPin = A0; // Входное напряжение
const int outputPin = A1; // Выходное напряжение
const int resetButtonPin = 2; // Кнопка сброса максимума
#define GRAPH_HEIGHT 20
#define GRAPH_WIDTH 110 // Оставляем место справа под шкалу
uint8_t graphBuffer[GRAPH_WIDTH];
// Класс вольтметра
class VoltMeter {
private:
int pin;
float voltage;
float maxVoltage;
public:
VoltMeter(int analogInputPin) { // Кнструктор класса
pin = analogInputPin;
voltage = 0.0;
maxVoltage = 0.0;
}
void measure() { // Метод -измерение
int raw = analogRead(pin);
voltage = raw * (5.0 / 1023.0);
if (voltage > maxVoltage) {
maxVoltage = voltage;
}
}
void resetMax() { // Метод - сброс максимального значения
maxVoltage = voltage;
}
float getVoltage() { // Метод - получить измеренное напряжение
return voltage;
}
float getMax() { // Метод - получить максимальное напряжение
return maxVoltage;
}
};
// Класс осциллограф
class Oscilloscope {
public:
Oscilloscope() { // Кнструктор класса
// pin = analogInputPin;
}
void updateGraph(float voltage) {
for (int i = 0; i < GRAPH_WIDTH - 1; i++) {
graphBuffer[i] = graphBuffer[i + 1];
}
uint8_t newY = map(voltage * 100, 0, 500, 0, GRAPH_HEIGHT);
graphBuffer[GRAPH_WIDTH - 1] = newY;
}
void drawGraph() {
int baseY = SCREEN_HEIGHT - 1;
for (int x = 0; x < GRAPH_WIDTH - 1; x++) {
display.drawLine(x, baseY - graphBuffer[x], x + 1, baseY - graphBuffer[x + 1], SSD1306_WHITE);
}
}
void drawScale(float value) {
const int segments = 10;
const int startX = SCREEN_WIDTH - 10; // Правая сторона экрана
const int startY = 58;
const int segWidth = 8;
const int segHeight = 4;
const int gap = 2;
int activeSegments = map(value * 100, 0, 500, 0, segments);
for (int i = 0; i < segments; i++) {
int y = startY - i * (segHeight + gap);
if (i < activeSegments) {
display.fillRect(startX, y, segWidth, segHeight, SSD1306_WHITE);
} else {
display.drawRect(startX, y, segWidth, segHeight, SSD1306_WHITE);
}
}
}
};
VoltMeter vinMeter(inputPin); //Экземпляр класса вольтметр V In
VoltMeter voutMeter(outputPin); // Экземпляр класса вольтметр V Out
Oscilloscope oscill; //Экземпляр класса осциллограф
void setup() {
pinMode(resetButtonPin, INPUT_PULLUP);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(10, 28);
display.println("Digital Voltmeter");
display.display();
delay(1500);
}
void loop() {
vinMeter.measure();
voutMeter.measure();
if (digitalRead(resetButtonPin) == LOW) {
vinMeter.resetMax();
voutMeter.resetMax();
delay(300);
}
float vin = vinMeter.getVoltage();
float vout = voutMeter.getVoltage();
float vmax = voutMeter.getMax();
oscill.updateGraph(vout);
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.print("V In: ");
display.print(vin, 2);
display.println(" V");
display.setCursor(0, 10);
display.print("V Max: ");
display.print(vmax, 2);
display.println(" V");
display.setCursor(0, 20);
display.print("V Out: ");
display.print(vout, 2);
display.println(" V");
oscill.drawGraph();
oscill.drawScale(vout);
display.display();
delay(200);
}
🧠 Советы и доработки
✅ Добавить коэффициент делителя прямо в класс VoltMeter, чтобы учесть масштабирование.
💾 Сохранять максимум в EEPROM, чтобы он не сбрасывался при перезагрузке.
🧲 Добавить третью строку: ток или мощность, если есть токовый шунт.
📈 Изменить масштаб графика для отображения высокого напряжения.
⚡ Применение
Настройка и тестирование лабораторных блоков питания.
Измерение и контроль напряжения в проектах Arduino.
Демонстрация работы стабилизаторов напряжения.
Учебные и демонстрационные стенды.