Вольтметр переменного напряжения на ардуино

Вольтметр переменного напряжения на ардуино

Идея устройства для измерения напряжения, тока, емкости, разряда, а может и заряда возникла давно и не только у меня. Можно найти немало игрушек под названием USB Tester (Doctor) для тестирования различных устройств с USB. Мне же интересно несколько более универсальное устройство, независимое от интерфейса, а просто рассчитанное на определенные напряжения и токи. Например, 0 — 20.00в, 0 — 5.00а, 0 — 99.99Ач. Что касается функций, то я вижу так

  • Отображение текущих напряжения и тока, то есть вольт-ампер-метр. Впринципе, можно и мощность сразу отразить.
  • Подсчет и отображение накопленной емкости. В ампер-часах и всего скорее в ватт-часах.
  • Отображение времени процесса
  • И, всего скорее, настраиваемые нижний и верхний пороги отключения по напряжению (ограничения разряда и заряда)

Разработка

Для реализации расчетов и измерений нам понадобится контроллер. Я вспомнил эту идею в рамках знакомства с Arduino, поэтому контроллером будет простая популярная Atmega328 и программироваться она будет в среде Arduino. С инженерной точки зрения выбор наверно не самый хороший — контроллер для задачи слегка жирноват, а его АЦП не назовешь измерительными, но. будем пробовать.

  • Паять в этом проекте много не будем. В качестве основы возьмем готовый модуль Arduino Pro Mini, благо китайцы готовы их поставлять по $1.5 в розницу.
  • В качестве устройства отображения будет выступать дисплей 1602 — еще $1.5. У меня вариант с интерфейсным модулем I2C, но в этом проекте он не сильно нужен ($0.7).
  • Для разработки нам понадобиться макетная плата. В моем случае это небольшая BreadBoard за $1.
  • Разумеется понадобятся провода и некоторое количество резисторов разного номинала. Для дисплея 1602 без I2C нужен также подбор контрастности — делается переменным резистором на 2 — 20 кОм.
  • Для реализации амперметра понадобится шунт. В первом приближении им может быть резистор 0.1 Ом, 5 Вт.
  • Для реализации автоматики отключения понадобится реле с контактами рассчитанными на максимальный ток устройства и напряжением равным напряжению питания. Для управления реле нужен npn транзистор и защитный диод.
  • Устройство будет питаться от внешнего источника питания, очевидно, что не менее 5 в. Если питание будет сильно варьироваться, то так же потребуется интегральный стабилизатор типа 7805 — он и определит напряжение реле.
  • В случае Arduino Pro Mini для заливки прошивки потребуется USB-TTL конвертер.
  • Для наладки понадобится мультиметр.

Вольтметр

Я реализую простой вольтметр с одним диапазоном примерно 0 — 20в. Это замечанием важно, тк АЦП нашего контроллера имеет разрядность 10 бит (1024 дискретных значения), поэтому погрешность составит не менее 0.02 в (20 / 1024). Для реализации железно нам нужен аналоговый вход контроллера, делитель из пары резисторов и какой-нибудь вывод (дисплей в законченном варианте, для отладки можно последовательный порт).

Принцип измерения АЦП состоит в сравнении напряжения на аналоговом входе с опорным VRef. Выход АЦП всегда целый — 0 соответствует 0в, 1023 соответствует напряжению VRef. Измерение реализовано путем серии последовательных чтений напряжения и усреднения по периоду между обновлениями значения на экране. Выбор опорного напряжения важен, поскольку по умолчанию оно равно напряжению питания, которое может быть не стабильно. Это нам совершенно не подходит — за основу мы будем брать стабильный внутренний опорный источник напряжением 1.1в, инициализируя его вызовом analogReference(INTERNAL). Затем мы откалибруем его значение по показаниям мультиметра.

На схеме слева — вариант с прямым управлением дисплея (он просто управляется — смотрите стандартный скетч LiquidCrystal\HelloWorld). Справа — вариант с I2C, который я и буду использовать дальше. I2C позволяет сэкономить на проводах (коих в обычном варианте — 10, не считая подсветки). Но при этом необходим дополнительный модуль и более сложная инициализация. В любом случае, отображение символов на модуле надо сначала проверить и настроить контрастность — для этого надо просто вывести после инициализации любой текст. Контрастность настраивается резистором R1, либо аналогичным резистором I2C модуля.

Вход представляет собой делитель 1:19, который позволяет при Vref = 1.1 получить максимальное напряжение около 20в (обычно параллельно входу ставят конденсатор + стабилитрон для защиты, но нам пока это не важно). Резисторы имеют разброс, да и опорное Vref контроллера тоже, поэтому после сборки надо измерить напряжение (хотя бы питания) параллельно нашим устройством и эталонным мультиметром и подобрать Vref в коде до совпадения показания. Так же стоить отметить, что любой АЦП имеет напряжение смещения нуля (которое портит показания в начале диапазона), но мы пока не будем в это углубляться.

Также важным будет разделение питающей и измерительной «земли». Наш АЦП имеет разрешение чуть хуже 1мВ, что может создавать проблемы при неправильной разводке, особенно на макете. Поскольку разводка платы модуля уже сделана и нам остается только выбор пинов. «Земляных» пинов у модуля несколько, поэтому мы должны сделать так, чтобы питание в модуль заходило по одной «земле», а измерения по другой. Фактически для изменений я всегда использую «земляной» пин ближайший к аналоговым входам.

Для управление I2C используется вариант библиотеки LiquidCrystal_I2C — в моем случае указывается специфическая распиновка модуля I2C (китайцы производят модули с отличающимся управлением). Так же отмечу, что I2C в Arduino предполагает использование именно пинов A4, A5 — на плате Pro Mini они находятся не с краю, что неудобно для макетирования на BreadBoard.

Исходный код

 #include #include // Простой вольтметр с i2c дисплеем 1602. V 16.11 // Настройки i2c дисплея 1602 с нестандартной распиновкой #define LCD_I2C_ADDR 0x27 #define BACKLIGHT 3 #define LCD_EN 2 #define LCD_RW 1 #define LCD_RS 0 #define LCD_D4 4 #define LCD_D5 5 #define LCD_D6 6 #define LCD_D7 7 LiquidCrystal_I2C lcd(LCD_I2C_ADDR,LCD_EN,LCD_RW,LCD_RS,LCD_D4,LCD_D5,LCD_D6,LCD_D7); // Время обновления показаний, мс (200-2000) #define REFRESH_TIME 330 // Аналоговй вход #define PIN_VOLT A0 // Внутреннее опорное напряжение (подобрать) const float VRef = 1.10; // Коэффициент входного резистивного делителя (Rh + Rl) / Rl. IN <-[ Rh ]--(analogInPin)--[ Rl ]--|GND const float VoltMult = (180.0 + 10.0) / 10.0; float InVolt, Volt; void setup() < analogReference(INTERNAL); // Инициализация дисплея lcd.begin (16, 2); lcd.setBacklightPin(BACKLIGHT, POSITIVE); lcd.setBacklight(HIGH); // включить подсветку lcd.clear(); // очистить дисплей lcd.print("Voltage"); >void loop() < unsigned long CalcStart = millis(); int ReadCnt = 0; InVolt = 0; // Чтение из порта с усреднением while ((millis() - CalcStart) < REFRESH_TIME) < InVolt += analogRead(PIN_VOLT); ReadCnt++; >InVolt = InVolt / ReadCnt; // Смещение 0 для конкретного ADC (подобрать или отключить) if (InVolt > 0.2) InVolt += 3; // Перевод в вольты (Value: 0..1023 -> (0..VRef) scaled by Mult) Volt = InVolt * VoltMult * VRef / 1023; // Вывод данных lcd.setCursor (0, 1); lcd.print(Volt); lcd.print("V "); > 

Ссылки

  • Библиотека LiquidCrystal_I2C, позволяющая задать распиновку
  • Часть 2. Амперметр

Железо

  • Arduino Pro Mini
  • Дисплей 1602 и Модуль I2C
  • Макетные платы
  • Комплект резисторов
  • Резисторы на 0.1 ом (в качестве шунта)
  • USB-TTL конвертер
  • Готовый многофункциональный вольт-ампер-метр
  • Отличный мультиметр UNI-T UT-61E (не дешевый)

Простой вольтметр на Arduino Uno

В данной статье мы рассмотрим создание на основы платы Arduino Uno и делителя напряжения простого цифрового вольтметра, который будет отображать измеренное значение напряжения на экране жидкокристаллического (ЖК) дисплея 16×2.

Внешний вид простого вольтметра на Arduino Uno

Плата Arduino имеет несколько аналоговых входов, к которым внутри платы подсоединены встроенные аналогово-цифровые преобразователи (АЦП). АЦП платы Arduino имеют разрядность 10 бит, поэтому значения на их выходах будут лежать в диапазоне от 0 до 1023. Мы можем считывать эти значения в программе, используя функцию analogRead() . Таким образом, если вы знаете опорное напряжение (reference voltage) АЦП, то вы легко можете рассчитать аналоговое напряжение, присутствующее на входе АЦП. Более подробно об аналогово-цифровом преобразовании в плате Arduino вы можете прочитать в этой статье.

Для измерения напряжения в нашем проекте цифрового вольтметра мы также будем использовать делитель напряжения. Измеренное значение напряжения мы будем показывать на экране ЖК дисплея 16×2 и выводить в окне монитора последовательной связи (Serial Monitor) Arduino IDE. Правильность измеренного значения напряжения мы будем проверять с помощью мультиметра.

Необходимые компоненты

  1. Плата Arduino Uno (купить на AliExpress).
  2. ЖК дисплей 16х2 (купить на AliExpress).
  3. Резисторы 10 кОм и 100 кОм (купить на AliExpress).
  4. Потенциометр 10 кОм (купить на AliExpress).
  5. Макетная плата.
  6. Соединительные провода.

Схема делителя напряжения

Делитель напряжения представляет собой схему из двух резисторов, показанную на следующем рисунке.

В нашем примере резисторы R1 и R2 имеют номиналы 100 кОм и 10 кОм. Средняя точка делителя напряжения используется для подачи сигнала на аналоговый вход платы Arduino. Напряжение, падающее на резисторе R2 (Vout), называется напряжением на выходе делителя напряжения. Оно может быть рассчитано по следующей формуле:

Vout = Vin (R2/R1+R2)

То есть напряжение на выходе делителя прямо пропорционально напряжению на его входе и отношению сопротивлений резисторов R1 и R2.

Используя приведенную формулу в коде программы для Arduino мы легко можем определить напряжение на входе делителя. Максимальное напряжение на входе (контактах) платы Arduino составляет 5 В, поэтому при используемых нами номиналах резисторов (их отношение составляет 100:10) мы с помощью нашего вольтметра сможем измерять напряжения до 55 В.

Работа схемы

Схема цифрового вольтметра на основе платы Arduino представлена на следующем рисунке.

Схема простого вольтметра на Arduino Uno

ЖК-дисплей подключен в 4-битном режиме. Его контакты DB4, DB5, DB6, DB7, RS и EN непосредственно подключены к контактам D4, D5, D6, D7, D8, D9 платы Arduino Uno.

Средняя точка делителя напряжения на резисторах R1 и R2, подключена к аналоговому контакту A0 платы Arduino. Остальные два конца делителя напряжения подключаются к источнику измеряемого напряжения и корпусу (земле).

Исходный код программы для Arduino

Основную часть кода программы составляет преобразование и отображение входного напряжения в отображаемое выходное напряжение с помощью приведенного выше уравнения Vout = Vin (R2/R1+R2). Как упоминалось ранее, выходное значение АЦП Arduino может варьироваться в диапазоне от 0 до 1023, а максимальное входное напряжение Arduino составляет 5 В, поэтому нам нужно умножить значение на выходе АЦП контакта A0 на 5/1024, чтобы рассчитать входное напряжение (на контакте A0).

void loop()
<
int analogvalue = analogRead(A0);
temp = (analogvalue * 5.0) / 1024.0; // формула для конвертирования значения напряжения
input_volt = temp / (r2/(r1+r2));

Мы будем отображать измеренное значение напряжение на экране ЖК-дисплея с помощью функции lcd.print и в окне монитора последовательной связи с помощью функции Serial.println .

Serial.print(«v color: #800080;»> Serial.println(input_volt);
lcd.setCursor(0, 1);
lcd.print(«Voltage color: #800080;»> lcd.print(input_voltage);

Далее представлен полный текст программы.

#include // библиотека для работы с ЖК дисплеем
LiquidCrystal lcd( 4, 5, 6, 7,8 ,9 ); // контакты, к которым подключен ЖК дисплей
float input_volt = 0.0;
float temp=0.0;
float r1=100000.0; //сопротивление резистора r1
float r2=10000.0; // сопротивление резистора r2
void setup()
Serial.begin(9600); // инициализируем последовательный порт связи для передачи на скорости 9600 бод/с
lcd.begin(16, 2); // устанавливаем число столбцов и строк используемого нами ЖК дисплея
lcd.print(«DC DIGI VOLTMETER»);
>
void loop()
int analogvalue = analogRead(A0);
temp = (analogvalue * 5.0) / 1024.0; // формула для конвертирования значения напряжения
input_volt = temp / (r2/(r1+r2));
if (input_volt < 0.1)
input_volt=0.0;
>
Serial.print(«v color: #800000;»>// выводим значение напряжения в окно монитора последовательной связи
Serial.println(input_volt);
lcd.setCursor(0, 1);
lcd.print(«Voltage color: #800000;»> // выводим значение напряжения на экран ЖК дисплея
lcd.print(input_volt);
delay(300);
>

Видео, демонстрирующее работу схемы

Похожие статьи

Комментарии

Простой вольтметр на Arduino Uno — 22 комментария

Serge Kompaniets говорит 24.10.2022 в 01:13 :

Прикладывау свои вариант. Адаптирован под управление по усб. Добавлена коррекция показании.
Исползуетса в автоматике.
Принт START/ STOP отмените если не надо. Я писал под старыи драивер.
Команды:
GET_VDC return Voltage
GET_COR return correction level
GET_NEG return Negative voltage (need add relay for switch measuring wires)
SET_CORR_X.XX (X.XX for example 0.15). write to EEPROM #include
char correction[16];
String correct;
String getCorrect;
String correctFull;
String getCommand;
String minus = «-«;
int set;
int geta;
int getb;
float input_volt = 0.0;
float temp=0.0;
float r1=100000.0; //сопротивление резистора r1
float r2=10000.0; // сопротивление резистора r2
void setup()
pinMode(13, OUTPUT);
digitalWrite(13, LOW);
Serial.begin(115200);
>
void loop()
< String command;
while (Serial.available()) char c = Serial.read(); //gets one byte from serial buffer
command += c; //makes the String readString
delay(2); //slow looping to allow buffer to fill with next character
>
command.toUpperCase();
if (command.length() > 0) geta = command.indexOf(«GET»);
set = command.indexOf(«SET»);
if(geta != -1) getCommand = command.substring(geta,geta + 7);
getCommand.trim();
// Serial.println(getCommand); // GET_VDC, GET_COR
>
if(set != -1) correctFull = command.substring(set,set + 13);
getCommand = command.substring(set,set + 8);
correct = correctFull.substring(9,13);
correctFull.trim();
getCommand.trim();
correct.trim();
//Serial.println(correctFull); //SET_CORR_X.XX
// Serial.println(getCommand); //SET_CORR
// Serial.println(correct); //X.XX
>
>
if (getCommand == «GET_VDC») int analogvalue = analogRead(A0);
getCorrect = EEPROM.get(1, correction);
temp = (analogvalue * 5.0) / 1024.0;
input_volt = temp / (r2/(r1+r2));
if (input_volt < 0.1)
input_volt=0.0;
>
delay(100);
Serial.println(«START»);
delay(100);
input_volt = input_volt + getCorrect.toFloat();
Serial.println(input_volt);
delay(100);
Serial.println(«STOP»);
getCommand = «»;
return;
>
if (getCommand == «SET_CORR») correct.toCharArray(correction, 20);
EEPROM.put(1, correction);
getCorrect = EEPROM.get(1, correction);
delay(100);
Serial.println(«START»);
delay(100);
Serial.println(getCorrect);
delay(100);
Serial.println(«STOP»);
getCommand = «»;
return;
>
if (getCommand == «GET_COR») getCorrect = EEPROM.get(1, correction);
delay(100);
Serial.println(«START»);
delay(100);
Serial.println(getCorrect);
delay(100);
Serial.println(«STOP»);
getCommand = «»;
return;
>
if (getCommand == «GET_NEG») digitalWrite(13, HIGH);
delay(500);
int analogvalue = analogRead(A0);
getCorrect = EEPROM.get(1, correction);
temp = (analogvalue * 5.0) / 1024.0;
input_volt = temp / (r2/(r1+r2));
if (input_volt < 0.1)
input_volt=0.0;
>
delay(100);
Serial.println(«START»);
delay(100);
input_volt = input_volt + getCorrect.toFloat();
Serial.println(minus + input_volt);
delay(100);
Serial.println(«STOP»);
//delay(300);
digitalWrite(13, LOW);
getCommand = «»;
return;
>
>

Хорошо, спасибо за полезную информацию.
Эмиль Ермолаев говорит 13.09.2022 в 20:52 :
вы можете отправить нормальный скетч. исправленный.
Вы имеете ввиду исправление номиналов резисторов в скетче?

Ошибка в описании схемы и кода программы, R1=100k R2=10k
float r1=100000.0; //сопротивление резистора r1
float r2=10000.0; // сопротивление резистора r2 проверяйте перед опубликованием.

Да, Вадим, спасибо за внимательность. Перечитал статью, действительно, при ее чтении может возникнуть впечатление что R1=10k, а R2=100k (и в программе введены эти значения), но на самом деле должно быть наоборот чтобы нашим вольтметром можно было измерять напряжения до 55 В. Либо же просто поменять эти сопротивления местами. Как это лучше исправить чтобы было более понятно, пока не решил. Все таки непростое это дело как что то простое объяснить как можно более доступным языком От админа: исправил

Еще одна ошибка — делить нужно на 1023, не?
Нет, на 1024. Потому что 2 в десятой степени равно 1024

. И одна неточность — лучше кодить так:
input_volt = temp / (10000.0/110000.0);
Зачем отнимать у АЛУ микроконтроллера лишний ресурс на вычисление, зачем занимать память лишний раз под переменные?
На минуточку, система выделяет памяти для переменной типа float аж целых 32 бита. Тут можно было обойтись одной переменной типа float, и все математические действия проводить в ней. И быстродействие повысилось бы.

Да, можно немного повысить и быстродействие, и снизить расход памяти, но это все не критично для такого простого проекта

Вы не учитываете, что есть компилятор и его оптимизацию. Он при компиляции вычислит значение и его будет использовать. Не заморачивайтесь на таких вещах, а код будет понятнее.

Да, и это тоже верно. Для такого сравнительно простого проекта экономия 32 бит памяти не так критична

В нашем примере резисторы R1 и R2 имеют номиналы 10 кОм и 100 кОм
* В нашем примере резисторы R1 и R2 имеют номиналы 100 кОм и 10 кОм соответственно

Спасибо за внимательность. Исправил
Что нужно изменить в программе, чтоб на дисплее показывало три знака после запятой?

Необходимо чтобы значения переменной input_volt рассчитывались с большей точностью чем два знака после запятой. Как это сделать, к сожалению уже не помню. Может быть поможет изменение ее типа с float на double

Изменить строку Serial.println(input_volt); на Serial.println(input_volt, 3); и lcd.print(input_volt); на lcd.print(input_volt, 3);

Спасибо за подсказку. Я сразу как то и не сообразил

Спасибо за информацию, скажите если у меня источник питания может выдать 18,5 вольт и 15 ампер, можно ли через делитель измерить напряжение и не выгорит ли порт и вся ардуина от этих 15 ампер, или она возьмет только столько сколько ей надо?

Не особо силен в этой тематике, но вам сначала нужно разобраться в том, является ли ваш источник питания источником тока или источником напряжения (это зависит от его внутреннего сопротивления) и какой ток пойдет через резисторы в делителе если к нему подключить ваш источник питания. Если сопротивление входа у контакта Ардуино намного больше сопротивлений резисторов в делителе, то по правилу параллельного соединения сопротивлений большой ток в Ардуино не пойдет. Но прежде чем подключать плату Ардуино к представленной схеме, в вашем случае я бы сначала измерил мультиметром ток в делителе и напряжение в его средней точке

Arduino в роли вольтметра. Вывод напряжения на LCD дисплей

Всем привет сегодня я хотел бы показать, как превратить Arduino Uno в вольтметр.

Смотрите видео: Arduino в роли вольтметра. Вывод напряжения на LCD дисплей

Соберем схему как в прошлый раз мы собирали, здесь я добавил еще один переменный резистор, он же сопротивление, и меняя его значение мы можем измерять постоянное напряжение, между минусом и резистором, в пределах 5 вольт.

вид схемы с деталями

Мы запитали 5 вольт по красному проводнику, в A0 на плату Arduino поступает значение напряжения, хотя можно было бы подключить маленькую батарейку и проверить ее вольтаж.

Давайте приступим к написанию скетча, и далее рассмотрим, как это все сделать. Хочу показать вам принципиальную плату, потом будет на сайте изображена схема, она похожа на пример, который мы собирали в прошлый раз с LCD дисплеем.

вид принципиальной схемы

Обратите внимание, мы выводили текст на LCD экран, в принципе здесь отличие единственное это второе сопротивление. Здесь по подключению, я думаю вопросов не возникнет, мы используем 4, 6, 10, 11, 12, 13 разъемы, минус берём общий, он расходится по плате, минус на первый контакт, и на последний(16).

Он здесь обозначен на моей плате буквой К, на сколько я помню на разных схемах по-разному. На одних схемах A и K на других LED+ LED- . Давайте напишем скетч, поскольку мы использовали в ней контакты 4, 6, 10, 11, 12, 13 нам нужно будет их обозначить.

И поскольку мы опять работаем с LCD дисплеем, мы должны будем подключить библиотеку liquidcrystal , константу для нашего аналогового разъёма, объявим массив контактов, которые мы использовали.

#include

Объявим переменную val, в которую мы будем считывать, преобразовывать, так сказать получать, исходя из значение A0.

const int analogIn = A0; LiquidCrystal lcd(4, 6, 10, 11, 12, 13); float val = 0;

В setup мы включим, в принципе это дело по пожеланию, для мониторинга последовательный порт, объявим LCD 16 символов по 2 строки и выведем текст не указывая конкретно на какой строке значение напряжения. Это будет первая строка. В цикле loop мы получим в переменную val значение с нашего разъема, которое у нас определяется как значение между плюс-минус и вот это выводится из A0 .

void setup()

Далее мы его преобразовываем, поскольку мы знаем, что там 5 Вольт, у нас было как максимальное значение, предполагаемое максимальное значение, изменяется значение от 0 до 1024, мы выводим его методом пропорции, поэтому для замера напряжения пальчиковой батарейки в формуле будем умножать не на 5, а на 1,5. Далее выводим значение в последовательный порт и печатаем после него символ вольтажа, английскую букву V.

Теперь на первой строке, она по сути вторая строка, с 6 символа выводим значение нашей переменной val , символ вольтажа, английскую букву V и сделаем небольшую задержку в одну пятую секунды, или 200 миллисекунд. Сохраним наш скетч, в принципе, после этого плата Arduino может стать небольшим вольтметром, который можно проверить напряжение небольшой батарейки.

void loop() < val = analogRead(A0); val = val/1024*5.0; Serial.print(val); Serial.print("V"); lcd.setCursor(6,1); lcd.print(val); lcd.print("V"); delay(200); >

Проверим скетч на ошибки и загрузим его в Arduino. Загрузка завершена, и как я вам в начале показывал, меняя сопротивление переменного резистора, вращая его ручку, мы меняем вольтаж в цепи, что в свою очередь отображается на дисплее.

Начинать измерение лучше всего вывернув резистор в крайнее положение, что бы A0 был замкнут на землю, и постепенно мы будем менять сопротивление, увеличивая сопротивление между A0 и GRD и уменьшая между A0 и плюсом источника питания.

Полный текст скетча вольтметр на ардуино

#include < LiquidCrystal.h>const int analogIn = A0; LiquidCrystal lcd(4, 6, 10, 11, 12, 13); float val = 0; void setup() < Serial.begin(9600); lcd.begin(16, 2); lcd.print("Voltage Value:"); >void loop() < val = analogRead(A0); val = val/1024*5.0; Serial.print(val); Serial.print("V"); lcd.setCursor(6,1); lcd.print(val); lcd.print("V"); delay(200); >

Смотрите видео: Arduino в роли вольтметра. Вывод напряжения на LCD дисплей