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


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

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

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

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

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

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

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

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

Делитель напряжения для вольтметра на Arduino

В нашем примере резисторы 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= "); // выводим значение напряжения в окно монитора последовательной связи
Serial.println(input_volt);
lcd.setCursor(0, 1);
lcd.print("Voltage= "); // выводим значение напряжения на экран ЖК дисплея
lcd.print(input_voltage);

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

#include <LiquidCrystal.h> // библиотека для работы с ЖК дисплеем
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= "); // выводим значение напряжения в окно монитора последовательной связи
Serial.println(input_volt);
lcd.setCursor(0, 1);
lcd.print("Voltage= "); // выводим значение напряжения на экран ЖК дисплея
lcd.print(input_volt);
delay(300);
}

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

(3 голосов, оценка: 3,67 из 5)
Загрузка...
39 423 просмотров

Комментарии

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

    • Сможет, а почему нет. Только если вы хотите измерять маленькие напряжения, то тогда нужно исключить из схемы делитель напряжения и непосредственно подавать измеряемое напряжение на аналоговый вход платы. Если у нас опорное напряжение равно 5 В, а на выходе АЦП может быть 1024 различных значений, получаем что минимальное напряжение которое мы можем измерить равно 5/1024 = 0,0049 В

      • Я ещё заметил в видео, что пока оператор не подал напряжение на вход, то он показывал 0.30v, мне надо измерить блуждающие токи в земле которые меньше 0.30v, подскажите, от этого можно как то избавиться?

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

  1. Vout = Vin (R2/R1+R2) формула на картинке и в тексте разная, надо бы исправить, на картинек правильно скобки расставлены. Надо Vout = Vin * (R2/(R1+R2))

    • Хорошо, спасибо что заметили опечатку. Исправил формулу в тексте статьи

  2. Прикладывау свои вариант. Адаптирован под управление по усб. Добавлена коррекция показании.
    Исползуетса в автоматике.
    Принт 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;
    }
    }

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

    проверяйте перед опубликованием!!!

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

      От админа: исправил

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

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

          • Добрый день. Можно ли этот делитель использовать для снятия показаний с плазмотрона, там напряжение 200 вольт?

            • Доброе утро. Да, можно, только номиналы резисторов в делителе напряжения нужно подобрать таким образом, чтобы напряжение с делителя, подаваемое на контакт платы Ардуино, не превышало 5 В.

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

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

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

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

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

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

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

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

    • Любой амперметр это вольтметр+шунт. Т.е. вольтметр меряет падение напряжения на шунте.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *