Вольтметр на Arduino Uno, з діапазоном вимірювання від 0V до 30 V з відображення на символьному дисплеї LCD1602.
Діапазон АЦП (Аналого Цифровий Прертворювач) у Arduino Uno від 0 вольт до напруги живлення 5V. Отже для вимірювання напруги в діапазоні 0 – 5 вольт, не потрібно додаткових компонентів. Для вимірювання більших напруг, сигнал можна подати через резестивний подільник напруги.
Схема підключення
R1 – 51 kOm
R2 – 10 kOm
D1 – стабілітрон 5.1V, для захисту GPIO мікроконтролора.
Розрахунок подільника напруги
Подільник напруги розраховується за формулою.
Uout = Uin * (R2 / (R1 + R2))
Uin – максимальна вхідна напруга яку ми хочемо вимірювати
Uout – при максимальній Uin має бути менше або рівне 5V
R1 – резистор верхнього плеча подільника
R2 – резистор нижнього плеча подільника
Спробуєм розрахувати, резистори підбираєм з стандартиних рядів. Так при резисторах R1 = 33кОм, R2 = 6.8кОм, вхідна напруга 30V.
30 = (6800 / (33000 + 6800)) = 5,125;
Uin більше 5V.
Змінемо резистори R1 = 51кОм, R2 = 10кОм, вхідна напруга 30V.
30 * (10000 / (51000 + 10000)) = 4,918;
10 кОм та 51 кОм резистори стандартного ряду, вихідна напруга, при 30V вхідній буде менша 5V
Коефіцієнт ділення напруги.
К = Uout / Uin = R2 / (R1 + R2)
Обмеження використання резистивного подільника
Номінали опорів подільника повинен бути в 100 – 1000 разів менше ніж навантаження, в нашому випадку вхідний опір аналогового GPIO у Arduino Uno 1МОм.
Занадто малі значення опорів, призводять до нагрівання резисторів, втрат активної потужоності, зниження ККД, як результат зниження точності результату вимірювання.
Код програми
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define R1 51000.0 // Верхнє плече подільника напруги
#define R2 10000.0 // Нижнє плече подільника напруги
#define SEMPLES 20 // Кількість разів вибірки
#define VOLT_PIN A0 // PIN вольтметра
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup()
{
lcd.init();
lcd.backlight();
lcd.setCursor(2, 0);
lcd.print("Voltmeter");
lcd.setCursor(5, 1);
lcd.print("Qazf.com.ua");
delay(2000);
lcd.clear();
lcd.clear();
lcd.setCursor(4, 0);
lcd.print("Voltmeter");
lcd.setCursor(11, 1);
lcd.print("V");
}
void display_v(float v)
{
if (v < 10)
{
lcd.setCursor(5, 1);
lcd.print(" ");
lcd.setCursor(6, 1);
lcd.print(v);
}
else
{
lcd.setCursor(5, 1);
lcd.print(v);
}
}
float read_v()
{
int sum = 0;
for (int i = 0; i < SEMPLES; i++)
{
sum += analogRead(VOLT_PIN);
}
int raw = sum / SEMPLES;
float v_calc = raw * ((R1 + R2) / R2);
float v = v_calc * (5.0 / 1023.0);
return v;
}
void loop()
{
float volt = read_v();
display_v(volt);
delay(200);
}
Додамо другий канал для вимірювання 0 – 5V
Резестивний подільник збільшує діапазон вимірівуння напруги, але знижує точність. Тому ми додамо ще один канал з діапазоном вимірювання 0 – 5V для точнішого вимірювання.
Схема підключення
R1 – 51 кОм
R2 – 10 кОм
D1, D2 – стабілітрони 5.1V, для захисту GPIO мікроконтролора.
#include <Arduino.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define R1 51000.0 // Верхнє плече подільника напруги
#define R2 10000.0 // Нижнє плече подільника напруги
#define SEMPLE30S 20 // Кількість разів вибірки
#define VOLT_PIN_CH1 A0 // PIN вольтметра
#define VOLT_PIN_CH2 A1 // PIN вольтметра
LiquidCrystal_I2C lcd(0x27, 16, 2);
void setup()
{
lcd.init();
lcd.backlight();
lcd.setCursor(2, 0);
lcd.print("Voltmeter");
lcd.setCursor(5, 1);
lcd.print("Qazf.com.ua");
delay(2000);
lcd.clear();
lcd.setCursor(1, 0);
lcd.print("CH1");
lcd.setCursor(14, 0);
lcd.print("V");
lcd.setCursor(1, 1);
lcd.print("CH2");
lcd.setCursor(14, 1);
lcd.print("V");
}
void display_v(float v1, float v2)
{
if (v1 < 10)
{
lcd.setCursor(8, 0);
lcd.print(" ");
lcd.setCursor(9, 0);
lcd.print(v1);
}
else
{
lcd.setCursor(9, 0);
lcd.print(v1);
}
lcd.setCursor(9, 1);
lcd.print(v2);
}
float read_v1()
{
int sum = 0;
for (int i = 0; i < SEMPLES; i++)
{
sum += analogRead(VOLT_PIN_CH1);
}
int raw = sum / SEMPLES;
float v_calc = raw * ((R1 + R2) / R2);
float v = v_calc * (5.0 / 1023.0);
return v;
}
float read_v2()
{
int sum = 0;
for (int i = 0; i < SEMPLES; i++)
{
sum += analogRead(VOLT_PIN_CH2);
}
int raw = sum / SEMPLES;
float v = raw * (5.0 / 1023.0);
return v;
}
void loop()
{
float v1 = read_v1();
float v2 = read_v2();
display_v(v1, v2);
delay(200);
}
Як працює
int sum = 0;
for (int i = 0; i < SEMPLES; i++)
{
sum += analogRead(analogPin);
}
int raw = sum / SEMPLES;
Зчитоємо дані певну кількість разів, кількість визначаться перемінною SEMPLES. Сумоємо зчитані дані та ділимо на SEMPLES, отримуємо середнє значення (фільтр від випадкового шуму).
float v_calc = raw * (5.0 / 1023.0);
Конвертуємо зчитані дані у напругу.
float v = v_calc * ((R1 + R2) / R2);
Якщо підключено через подільник напруги, зчитане значення напруги множимо на коефіціент подільника.