Измерение напряжения на ардуино

Аналоговые выводы

На плате UNO есть шесть выводов, которые подписаны от A0 до A5 (у других плат может быть другое число выводов). Они работают с напряжением от 0 до 5V. Благодаря встроенному АЦП (аналого-цифровой преобразователь), данные входы могут считывать напряжение подаваемое на них. Микроконтроллеры Atmega328, используемые в Arduino UNO, содержат шестиканальный АЦП, разрешение которого составляет 10 бит. Это позволяет на выходе получать значения от 0 до 1023 (всего 1024 градации).

Для чтения показания напряжения есть встроенный метод analogRead(), возвращающий значение от 0 до 1023. Значение 0 относится к 0V, а 1023 к 5V. Таким образом, если мы хотим конвертировать значение от 0 до 5, то нужно произвести деление 1023/5 = 204.6

Имеется также функция analogReference(type)​. Она задаёт опорное напряжение, относительно которого происходят аналоговые измерения. В проектах для новичков она не используется, поэтому не будем обращать на неё внимания.

Кроме того, аналоговые выходы могут работать как цифровые и обозначаются как 14, 15, 16, 17, 18, 19 вместо A0..A5.

И, наоборот, цифровые порты с символом тильды ~ (3, 5, 6, 9, 10, 11) могут работать как аналоговые выходы, используя ШИМ.

Аналоговые выводы, в отличие от цифровых, не нужно объявлять как вход или выход в начале программы.

Изучим простой пример с одним проводом и аналоговым выводом. Соединим проводом порты A0 и 3.3V. Напишем скетч.

 int analogPin = A0; void setup() < Serial.begin(9600); >void loop() < int rawReading = analogRead(analogPin); float volts = rawReading / 204.6; Serial.println(volts); delay(1000); >

Откройте окно Serial Monitor и наблюдайте за показаниями. Должны выводиться числа, близкие к значению 3.3: 3.1, 3.2, 3.3. Если, не закрывая программу, вытащить конец провода из порта 3.3V и вставить в порт 5V, то показания изменятся, а на экране появятся числа 5.0. Если перекинуть конец провода на GND, то увидим значения 0.

Таким образом мы видим, что можем получать значения напряжения из аналоговых портов.

Вольтметр

Если мы можем снимать значения из аналоговых портов, то можем использовать микроконтроллер как вольтметр. Достаточно вставить провода в выводы GND и A0 и соединить их с контактами на батарее (минус и плюс соответственно). Вообще такой способ не является суперточным. Хотя он и показывал правдоподобные результаты на пальчиковой батарее 1.5 В и «Кроне» на 9 В, но также показывал результаты, когда провода вообще ни к чему не были присоединены. Но для общего развития оставлю.

 /* The simplest voltmeter */ const int analogIn = A0; int raw = 0; float voltage = 0; void setup() < pinMode(analogIn, INPUT); Serial.begin(9600); >void loop() < raw = analogRead(analogIn); voltage = (raw * 5.0 ) / 1024.0; Serial.print("Raw Value = " ); Serial.print(raw); Serial.print("\t Voltage text-info" >01.Basics | AnalogReadSerial (Чтение аналоговых выводов через потенциометр) 

С помощью потенциометра мы можем менять напряжение и считывать данные с выводов.

Продолжим изучение работы с аналоговыми выводами через пример AnalogReadSerial из меню File | Examples | 01.Basics. Цель урока - плавно изменять напряжение и подавать его на аналоговый вывод, чтобы получить с него текущее значение напряжения.

Нам понадобятся плата Arduino, потенциометр и несколько проводов (или перемычек). Соединяем парные ножки с выводами на плате 5V и GND. Среднюю ножку необходимо соединить с аналоговым выводом на плате, помеченную как A0.

Макет

Не важно, какая из крайних ножек потенциометра будет подключена к 5V, а какая к GND, поменяется только направление, в котором нужно крутить ручку для изменения напряжения. Сам сигнал считывается со средней ножки, которая связана с аналоговым портом. Для считывания аналогового сигнала, принимающего широкий спектр значений, а не просто 0 или 1, подходят только порты, помеченные на плате как ANALOG IN. Они все пронумерованы с префиксом A (A0-A5).

Схема готова. Вращая регулятором потенциометра, мы можем менять сопротивление от 5 Вольт до 0. Arduino позволяет считывать текущее напряжение, которое подаётся на среднюю ножку при помощи аналогового вывода. Результаты могут колебаться от 0 до 1023.

Код

 void setup() < // инициализируем соединение на скорости 9600 бит в секунду: Serial.begin(9600); >void loop() < // Считываем данные с аналогового вывода A0 int sensorValue = analogRead(A0); // получаем текущее значение Serial.println(sensorValue); // выводим результат на монитор delay(1); // небольшая задержка для стабильности вывода результатов >

Код очень простой. При инициализации устанавливаем нужную скорость связи: Serial.begin(9600);. Далее в цикле мы постоянно считываем данные, поступающие с потенциометра при помощи метода analogRead(). Так как значения будут находиться в диапазоне от 0 до 1023, мы можем использовать тип int для переменной sensorValue.

Полученный результат будем выводить в окно последовательного монитора.

Проверка (Serial Monitor)

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

Пример интересен своей универсальностью. Потенциометр является ручным делителем напряжения. Существуют другие детали, которые выполняют такую же работу. Например, фоторезистор меняет напряжение в зависимости от освещённости. Также напряжение может меняться от нажатия, от температуры и т.д. При этом нам не нужно менять программу, просто одну деталь меняем на другую и код будет выполняться. Единственное различие будет в выводимых результатах - каждый делитель напряжения имеет свои характеристики и, соответственно, будет давать свои показания.

Проверка (Serial Plotter)

Начиная с версии Arduino IDE 1.6.6, в настройках появился новый инструмент Plotter (Tools | Serial Plotter), позволяющий выводить простенький график. Обратите внимание, что он не может работать одновременно с последовательным монитором, который следует закрыть.

Вращая ручку потенциометра, можем наблюдать изменение графика.

Serial Plotter

01.Basics | ReadAnalogVoltage (Напряжение аналоговых выводов через потенциометр)

Рассмотрим урок ReadAnalogVoltage из меню File | Examples | 01.Basics. Он практически идентичен примеру AnalogReadSerial, только мы будем конвертировать значения от аналогового вывода (0. 1023) в значения напряжения (0. 5). Для примера нам понадобится потенциометр. Цель урока - плавно изменять напряжение и подавать его на аналоговый вывод, чтобы получить текущее значение напряжения.

Схема прежняя, ничего не меняем. Соединяем парные ножки с выводами на плате 5V и GND. Среднюю ножку необходимо соединить с аналоговым выводом на плате, помеченную как A0.

Макет

Схема готова. Вращая регулятором потенциометра, мы можем менять сопротивление от 5 Вольт до 0. Arduino позволяет считывать текущее напряжение, которое подаётся на среднюю ножку при помощи аналогового вывода. Результаты могут колебаться от 0 до 1023.

Код

 void setup() < Serial.begin(9600); >void loop() < // читаем данные с вывода A0: int sensorValue = analogRead(A0); // Конвертируем данные от 0 до 1023) в значения напряжения (0 - 5V): float voltage = sensorValue * (5.0 / 1023.0); // Выводим результат Serial.println(voltage); >

Если сравнить два примера, то разница в одной строке float voltage = sensorValue * (5.0 / 1023.0);. В цикле считываем данные, поступающие с потенциометра при помощи метода analogRead(). Так как значения будут находиться в диапазоне от 0 до 1023, мы можем использовать тип int для переменной sensorValue. Используем элементарную математику и делим результат на коэффициент.

Полученный результат будем выводить в окно последовательного монитора.

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

Светодиод с плавной регулировкой

Усложним конструкцию, добавив светодиод. Первую часть схему можно было не трогать. Но для экономии в предыдущем примере я соединил ножку потенциометра сразу с портом GND. На этот раз сделаем соединение из двух проводов. Это необходимо, чтобы светодиод тоже мог соединиться с заземлением. Поэтому финальный макет будет следующим.

Макет

Принципиальная схема

 int potPin = A0; int ledPin = 9; void setup() < // порт для светодиода на выход pinMode(ledPin, OUTPUT); // пин с потенциометром - вход // мы хотим считывать напряжение, // выдаваемое им pinMode(potPin, INPUT); Serial.begin(9600); >void loop() < // значение напряжения с потенциометра int rotation; // значение яркости int brightness; // считываем напряжение с потенциометра от 0 до 1023 // пропорциональное углу поворота ручки rotation = analogRead(potPin); // в brightness записываем полученное ранее значение rotation // делённое на 4. Дробная часть от деления будет отброшена. // В итоге мы получим целое число от 0 до 255 brightness = rotation / 4; // выдаём результат на светодиод analogWrite(ledPin, brightness); // выводим результат в Serial Monitor Serial.println(brightness); delay(1); // задержка для стабильности >

Практически все инструкции вам знакомы. Тут нужно уяснить момент, что яркость светодиода управляется нашим кодом, а не подачей напряжения через потенциометр. Мы считываем показания потенциометра, как в первом варианте и переводим получаемые значения в диапазон от 0 до 255. Затем воспроизводим старый пример с плавной регулировкой светодиода и подаём ему нужные значения. Теперь при вращении ручки потенциометра мы одновременно управляем степенью накала светодиода. Напомню, что светодиод следует подключить к портам с тильдой, например, ~9

03.Analog: AnalogInput

Небольшая модификация примера с миганием светодиода. Частота мигания будет зависеть от показаний потенциометра. Можно использовать встроенный светодиод или установить свой. Общая схема остаётся как у первого примера.

 int sensorPin = A0; // аналоговый вывод A0 для потенциометра int ledPin = 13; // вывод для светодиода int sensorValue = 0; // значение, поступаемое от потенциометра void setup() < // устанавливаем режим для светодиода pinMode(ledPin, OUTPUT); >void loop() < // считываем показание с потенциометра sensorValue = analogRead(sensorPin); // включаем светодиод digitalWrite(ledPin, HIGH); // делаем задержку на значение от потенциометра в мсек delay(sensorValue); // выключаем светодиод digitalWrite(ledPin, LOW); // делаем задержку на значение от потенциометра в мсек delay(sensorValue); >

Получая показания от потенциометра в интервале 0-1023 мы регулируем задержку между миганием светодиода в интервале от 0 до 1.023 секунд.

03.Analog: AnalogInOutSerial

Считываем данные с потенциометра и распределяем их в интервале от 0 до 255 с помощью функции map(). Данный интервал удобно использовать для выводов с PWM (ШИМ). Применим получаемые значения для управления яркостью светодиода, а также будем выводить информацию в Serial Monitor.

Analog

 const int analogInPin = A0; // потенциометр к A0 const int analogOutPin = 9; // светодиод на выводе 9 int sensorValue = 0; // значения от потенциометра int outputValue = 0; // значения для PWM void setup() < Serial.begin(9600); >void loop() < // считываем данные из потенциометра sensorValue = analogRead(analogInPin); // распределяем данные из интервала 0-1023 в интервал 0-255 outputValue = map(sensorValue, 0, 1023, 0, 255); // подаём сигнал на светодиод: analogWrite(analogOutPin, outputValue); // печатаем результаты в Serial Monitor Serial.print("sensor = "); Serial.print(sensorValue); Serial.print("\t output img/analog2.png" alt="Analog">

03.Analog: Smoothing

Если показания аналогового датчика "прыгают", то имеет смысл вычислить среднее значение за определённый промежуток времени и результат выдавать на экран. Таким образом мы получим более плавные значения.

Для демонстрации можно использовать потенциометр, хотя он выдаёт обычно нормальные данные, но нам важно узнать принцип.

Схема обычная, берём из примеров выше.

Потенциометр

 // число показаний для получения среднего значения (подбирается индивидуально) const int numReadings = 10; int readings[numReadings]; // массив данных от аналогового вывода int readIndex = 0; // текущий индекс int total = 0; // общее значение int average = 0; // среднее значение int inputPin = A0; // Аналоговый вывод А0 void setup() < Serial.begin(9600); // заполняем массив из 10 элементов нулями for (int thisReading = 0; thisReading < numReadings; thisReading++) < readings[thisReading] = 0; >> void loop() < // вычитаем значение total = total - readings[readIndex]; // считываем с датчика readings[readIndex] = analogRead(inputPin); // добавляем полученное значение total = total + readings[readIndex]; // переходим на следующую позицию в массиве readIndex = readIndex + 1; // если достигли конца массива. if (readIndex >= numReadings) < // . возвращаемся в начало: readIndex = 0; >// подсчитываем среднее значение average = total / numReadings; // посылаем данные на компьютер Serial.println(average); delay(1); // небольшая задержка для стабильности > 

05.Control: IfStatementConditional

В примере File | Examples | 05.Control | IfStatementConditional рассматривается случай, когда показания достигают определённой величины. При достижении заданного порога включается светодиод. Урок знакомит новичка с оператором условия if (Если).

Схема без изменений (см. рисунки выше). Среднюю ножку потенциометра соединяем с аналоговым выводом A0, остальные две ножки соединяем с питанием 5В и землёй. При желании установите внешний светодиод на цифровой вывод 13 (можно обойтись встроенным светодиодом).

 const int analogPin = A0; // аналоговый вывод для потенциометра const int ledPin = 13; // цифровой вывод для светодиода const int threshold = 400; // произвольный порог для показаний потенциометра void setup() < pinMode(ledPin, OUTPUT); Serial.begin(9600); >void loop() < // считываем данные с потенциометра int analogValue = analogRead(analogPin); // Если показания выше чем заданный порог, то включаем светодиод if (analogValue >threshold) < digitalWrite(ledPin, HIGH); >else < digitalWrite(ledPin, LOW); // иначе держим светодиод выключенным >// выводим показания на Serial monitor Serial.println(analogValue); delay(1); // задержка для стабильности > 

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 дисплей

Как подключить датчик тока к Arduino

Print Friendly, PDF & Email

Как подключить датчик тока к Arduino

Подключаем к Arduino несколько датчиков тока: аналоговый ACS712 и цифровые INA219 и INA3221, и разбираемся, как с ними работать.

Для проекта нам понадобятся:

  • аналоговый датчик тока ACS712;
  • цифровой датчик тока INA219;
  • трёхканальный цифровой датчик тока INA3221;
  • Arduino UNO или иная совместимая плата;
  • какая-либо нагрузка, например, двигатель постоянного тока;
  • соединительные провода (например, такой набор проводов);
  • макетная плата;
  • персональный компьютер со средой разработки Arduino IDE.

Датчики тока, как следует из их названия, служат для измерения силы тока. Существуют датчики, которые основаны на различных физических эффектах и имеют различные особенности. В частности, рассматриваемый датчик ACS712 основан на эффекте Холла, датчик INA219 имеет в своём составе аналого-цифровой преобразователь ( АЦП ), а датчик INA3221 – трёхканальный. Рассмотрим их по порядку.

Содержание:

  • Описание датчика тока ACS712
  • Подключение датчика тока ACS712 к Arduino
  • Чтение показаний датчика тока ACS712 с помощью Arduino
  • Описание датчика тока, напряжения и мощности INA219
  • Подключение датчика тока и напряжения INA219 к Arduino
  • Как читать данные с датчика тока и напряжения INA219
  • Подключение трёхканального датчика тока и напряжения INA3221 к Arduino

1 Описание датчикатока ACS712

Датчик тока ACS712 – это датчик, который основан на эффекте Холла. Эффект Холла заключается в том, что когда через проводник, помещённый в магнитное поле, протекает электрический ток, в проводнике возникает напряжение. Это напряжение и служит индикатором силы тока: оно линейно зависит от силы тока. Ещё оно имеет небольшую зависимость от температуры окружающей среды и поддаётся влиянию внешних магнитных полей. Так, например, на графике ниже показана зависимость напряжения на выходе датчика ACS712 от силы протекающего тока (для одной из разновидностей датчика, об этом чуть ниже) при различных температурах:

Зависимость напряжения на выходе датчика ACS712 от силы тока

Модуль с датчиком ACS712 может выглядеть, например, так:

Модуль с датчиком тока ACS712 и схема подключения

Датчик ACS712 имеет следующие характеристики:

  • работает с постоянным и переменным током;
  • ток потребления – до 13 мА;
  • температура эксплуатации -40…+85 °C.

Существуют несколько разновидностей датчика ACS712, которые отличаются величиной измеряемого тока. Так, существуют разновидности с максимально измеряемым током 5, 20 и 30 А. Широкий диапазон измеряемых значений тока можно отнести к существенным преимуществам датчика ACS712. Перечисленные модификации имеют чувствительность 185, 100 и 66 мВ/А соответственно.

2 Подключение датчика тока ACS712 к Arduino

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

Вывод датчика ACS712 Назначение
VCC Питание, 5 В
GND Земля
OUT Аналоговый выход датчика, напряжение на котором линейно зависит от протекающего через датчик тока
IP+ Вывод 1 для подачи измеряемого тока
IP- Вывод 2 для подачи измеряемого тока

Выводы IP+ и IP- как раз и есть тот разрыв цепи, через который нужно пропустить интересующий ток. Если перепутать полярность, то измерения будут с обратным знаком.

Кстати, эта особенность – измерять ток как с положительным, так и отрицательным знаком, позволяет использовать датчик ACS712 для измерений переменного тока.

Таким образом, для подключения датчика ACS712 к плате Arduino используются 3 провода:

Схема подключения датчика тока ACS712 к Arduino

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

Модуль с датчиком тока ACS712 подключён Arduino, нагрузка – двигатель постоянного тока

Либо вместо нагрузки можно использовать мощную лампу накаливания. Либо любую другую нагрузку.

Модуль с датчиком тока ACS712 подключён Arduino, нагрузка – 10 Вт лампа накаливания

Питать нагрузку будем от лабораторного источника тока, на котором можно менять напряжение и ток.

3 Чтение показаний датчика тока ACS712с помощью Arduino

В скетче будем постоянно читать значение с порта A0 и выводить в монитор последовательных данных. Напомню, АЦП у разных плат Arduino имеет различную разрядность, обычно 10 или 12 бит. Подробнее здесь. Это означает, что с аналогового порта могут приходить значения от 0 до 2 10 = 1024 для 10-разрядного АЦП . Будем считать, что у нас датчик тока, диапазон измерений которого от -5 А до +5 А, а чувствительность 185 мВ/А.

Если на 1 А приходится 185 мВ, это соответствует примерно 38 единицам измерения АЦП : 185·1024/5000 = 37.888, (1) где 5000 – это максимальное значение напряжения, которое способен измерить АЦП Arduino, в милливольтах.

На выходе OUT датчика ACS712 при отсутствии измеряемого тока должна быть половина напряжения питания, т.е. 2.5 В. Так как вся шкала АЦП лежит в диапазоне от 0 до 1024, то при отсутствии измеряемого тока мы должны считывать с аналогового порта Arduino число 512. Это начало шкалы отсчёта. Обозначим его value_zero. Отклонение тока value_adc от нулевого уровня в большую или меньшую сторону и будет показывать силу тока. Следовательно, чтобы посчитать в амперах значение тока с датчика ACS712, необходимо разницу нулевого уровня и измеренного значения с аналогового порта A0 поделить на 38. А чтобы получить ток в миллиамперах, следует умножить это значение на 1000: I(mA) = (value_zero − value_adc) / 38·1000 (2)

Пояснение принципа вычисления силы тока

На практике значение на аналоговом выводе A0 не будет равняться точно 512. Поэтому, чтобы определить начало отсчёта, добавим в скетч примитивную калибровку. Калибровка будет заключаться в том, что некоторое количество раз прочитаем значение с аналогового порта A0 при отсутствии тока на датчике ACS712, и усредним его. Естественно, нагрузка на время калибровки должна быть выключена, чтобы ток не протекал через датчик.

Скетч для измерения постоянного тока датчиком ACS712 (разворачивается)

const int acs712_pin = A0; int zero; // уровень нуля, относительно которого измеряется ток, обычно VCC/2 void setup() Serial.begin(9600); calibrate(); > // определим нуль шкалы (до включения нагрузки) void calibrate() zero = 0; int repeats = 10; for (int i=0; i zero /= repeats; // берём среднее арифметическое Serial.print("Zero = "); int c = getCurrent(sensorValue); // преобразуем в значение тока и выводим в монитор Serial.print(c); Serial.println(" mA"); delay(100); > // рассчитывает ток в мА по значению с АЦП int getCurrent(int adc) int delta = zero - adc; // отклонение от нуля шкалы float scale = 37.888; // сколько единиц АЦП приходится на 1 ампер, по формуле (1) int current = (int)delta*1000/scale; // считаем ток в мА и округляем до целых, по формуле (2) return current; >

Загрузим скетч и плавно начнём поднимать напряжение и ток на нагрузке. Какое-то время подождём, а затем начнём уменьшать ток. В результате получим примерно такую картинку:

Вывод тока датчика ACS712 в монитор последовательного порта и его график

Как видно, аналоговый сигнал постоянно «прыгает». Чтобы этого избежать, следует добавить в скетч сглаживание. Для этого будем проводить подряд несколько измерений, а затем брать среднее арифметическое от них в качестве действительного значения. Заодно совместим начальную калибровку, т.к. она выполняется точно так же. Вот как изменится в результате скетч:

Скетч для измерения постоянного тока датчиком ACS712 со сглаживанием

const int acs712_pin = A0; int zero; // уровень нуля, относительно которого измеряется ток, обычно VCC/2 void setup() Serial.begin(9600); zero = getSmoothedValue(); // определим нуль шкалы (до включения нагрузки) Serial.print("Zero = "); int c = getCurrent(sensorValue); // преобразуем в значение тока и выводим в монитор Serial.print(c); Serial.println(" mA"); delay(100); > // рассчитывает ток в мА по значению с АЦП int getCurrent(int adc) int delta = zero - adc; // отклонение от нуля шкалы float scale = 37.888; // сколько единиц АЦП приходится на 1 ампер int current = (int)delta*1000/scale; // считаем ток в мА return current; >

Кстати, желательно вынести чувствительность датичка ACS712 в константу в начале скетча, чтобы можно было быстро изменить скетч для модификации датчика с другим диапазоном измерений.

В результате выполнения данного скетча картинка получается гораздо более приятная:

Сглаженный график тока, измеренного датчиком ACS712

Тот же самый принцип заложен в библиотеки для Arduino, которые оперируют с датчиком тока ACS712. Например, вот эта библиотека Troyka Current.

По результату эксперимента получается, что датчик ACS712 очень простой, но при этом довольно не точный. Гораздо точнее датчик тока, который мы рассмотрим в следующем разделе.

4 Описание датчика тока,напряжения и мощности INA219

Датчик INA219 – цифровой датчик тока, напряжения и мощности. Он позволяет измерять напряжения от 0 до 26 вольт и ток от 0 до 3,2 ампер. Питается датчик напряжением от 3 до 5,5 В. Существуют модули, полностью готовые к подключению к Arduino. Один из таких модулей GY-219:

Модуль GY-219 с датчиком тока INA219: назначение выводов и частей

Датчик INA219 выполняется в двух разновидностях: A и B. Последняя отличается повышенной точностью и меньшей погрешностью. На фото ниже как раз модификация INA219B.

Модуль GY-219 с датчиком тока INA219

Датчик INA219 имеет 12-разрядный АЦП , соответственно при максимуме измерений ±3,2 А получается разрешающая способность 0,8 мА. Однако можно настроить датчик таким образом, чтобы уменьшить диапазон измеряемой силы тока до ±400 мА; при этом разрешающая способность датчика увеличится до 0,1 мА. При этом можно откалибровать датчик, записав калибровачные данные в специальный регистр. Измеренные данные силы тока, напряжения и можности хранятся в трёх соответствующих регистрах. Кстати, датчик INA219 позволяет осуществлять аппаратную фильтрацию по 128 отсчётам, если измеряемый ток имеет сильные наводки.

Для конфигурирования датчика INA219 и для считывания показаний с него используется последовательный интерфейс I2C. Причём адрес на шине можно задать с помощью перемычек A0 и A1 на модуле. Допустимые адреса:

  • 0x40 (без перемычек);
  • 0x41 (с перемычкой A0);
  • 0x44 (с перемычкой A1);
  • 0x45 (установлены обе перемычки).

Соответственно, на одной шине IIC можно иметь до 4-х таких датчиков, подключённых одновременно.

5 Подключение датчика тока и напряжения INA219 к Arduino

Для начала пойдём простым путём: скачаем готовую библиотеку, загрузим в Arduino и посмотрим на результат. Существует несколько библиотек для работы с нашим датчиком. Предлагаю воспользоваться вот этой популярной библиотекой для INA219 от Adafruit. Скачаем её, установим стандартным образом и загрузим в Arduino скетч из примеров getcurrent.

Если скетч не компилируется, а в сообщениях об ошибках присутствуют какие-то недостающие компоненты (например, Adafruit_I2CDevice.h или Adafruit_BusIO_Register.h, то необходимо доустановить их. Проще всего это сделать так. Для этого способа требуется подключение к интернету на компьютере, где запущена среда разработки. Открыть в среде Arduino IDE менеджер библиотек: в меню Tools Manage Libraries…. Откроется окно Library Manager. В поле поиска следует ввести adafruit busio. Когда библиотека будет обнаружена и покажется в списке, нажать кнопку Install.

Установка недостающих библиотек через менеджер библиотек Arduino IDE

Подключим модуль GY-219 к Arduino по следующей схеме. SDA и SCL датчика можно подключить как к аналоговым входам A4 и A5 Arduino, так и к специально выделенным портам SDA и SCL (если они есть на вашей плате).

Схема подключения датчика INA219 к Arduino

В качестве нагрузки может быть любой источник, например, электромотор, лампа или просто мощный резистор. У меня это 5 соединённых параллельно 5-ваттных 16-омных резисторов. В качестве источника питания также может выступать любой из имеющихся у вас источников. Я буду использовать лабораторный источник питания.

Датчик INA219 подключён к Arduino

В результате выполнения скетча получится следующий вывод:

Результат работы скетча

Отлично! Всё работает! Как говорится, бери – и пользуйся.

Данная библиотека позволяет также проводить калибровку датчика INA219 при необходимости. Подробности – в описании библиотеки и в самих исходниках (в файле Adafruit_INA219.cpp библиотеки даётся большое число пояснений).

6 Как читать данные сдатчика тока и напряжения INA219

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

Осциллограмма чтения регистров датчика INA219

Чтобы понять, что здесь происходит, необходимо познакомиться с картой регистров датчика INA219. Датчик содержит всего 6 регистров. Все регистры 16-разрядные.

Карта регистров датчика тока и напряжения INA219

Адрес регистра Название регистра Назначение регистра Тип
0x00 Configuration Сброс всех регистров, настройка диапазона измерений, усиления PGA , разрешения АЦП и фильтрации. Чтение/Запись
0x01 Shunt voltage Хранит измеренное значение напряжения на шунтирующем резисторе 0,1 Ом. Чтение
0x02 Bus voltage Хранит измеренное значение напряжения шины. Чтение
0x03 Power Хранит измеренное значение мощности. Чтение
0x04 Current Содержит значение силы тока, протекающего через шунтирующий резистор. Чтение
0x05 Calibration Калибровочный регистр. Задаёт диапазон измерений и позволяет осуществлять калибровку системы. Чтение/Запись

Для обмена с модулем воспользуемся отладочной платой с микросхемой FT2232H и программой SPI via FTDI. Это будет проще, чем использовать Arduino, т.к. для внесения изменений в целях эксперимента не придётся каждый раз перепрограммировать ПЗУ , а можно будет вносить изменения в передаваемые команды «на лету». Подключим датчик к питанию 3,3 В и к земле, взятых от Arduino. А ножки SCL и SDA подключим к выводам ADBUS0 и ADBUS1+ADBUS2 платы с микросхемой FTDI, соответственно.

Чтение регистров датчика тока INA219 с помощью FT2232H

Запустим программу SPI via FTDI, выберем в меню «Устройство» интерфейс I2C. Подключимся к порту A. Просканируем устройства на шине I2C. Программа найдёт устройство по адресу 64 (0x40), если конечно вы не меняли адрес перемычками A0 и A1. Выберем это устройство. В разделе «Чтение» зададим размер буфера 2 байта, напишем команду 00 и нажмём кнопку «Прочитать». Прочитанные данные будут в таблице, которая открывается по нажатию на кнопку с пиктограммой таблицы. Вот что мы увидим.

Чтение регистров датчика тока INA219 с помощью FT2232H и программы

Как вы уже наверное догадались, команда "0" означает адрес регистра, из которого мы хотим прочитать данные. А число 0x399F – это данные в нулевом регистре (регистр конфигурации). И это соответствует документации, т.к. после включения и загрузки микросхема INA219 имеет именно такую конфигурацию по умолчанию. Вот какую структуру имеет регистр конфигурации.

Структура конфигурационного регистра датчика тока INA219

В регистре конфигурации датчика INA219 присутствуют следующие части:

  • RST (reset) – сброс;
  • BRNG (bus voltage range) – диапазон измерения шины;
  • BADC (bus ADC resolution/averaging) – разрешающая способность АЦП шины;
  • SADC (shunt ADC resolution/averaging) – разрешающая способность АЦП шунта;
  • MODE – режим;
  • PG – усиление и диапазон PGA .

0x399F в двоичном виде это "001_11_0011_0011_111". Следовательно, значения по умолчанию после включения такие.

  • BRNG равен "1", что означает диапазон измерений 32 вольта FSR ;
  • PG равно "11": задаёт диапазон ±320 мВ и коэффициент усиления 8;
  • BADC, SADC равны "0011": максимальная разрешающая способность АЦП – 12 бит;
  • MODE, равное "111", означает непрерывный режим работы, включены и шунт, и шина.

Для чтения других регистров необходимо сначала так же записать их адрес в поле «Чтение» «Команда», а затем прочитать 2 байта. Или можно записать номер регистра в поле «Запись» «Команда», а затем просто читать (не указывая адрес регистра в команде чтения).

К сожалению, последовательного чтения всех регистров микросхемы INA219 «за один проход» не предусмотрено.

Вернёмся к нашей осциллограмме. Мы видим на ней 6 циклов чтения (каждый начинается с зелёной точки ● и заканчивается тёмно-красной ● ). Сначала читаем регистр с напряжением шунта Vшунт. (адрес 0x01), который хранит значение 0x1957. Далее читаем значение регистра напряжения шины Vшины (0x02), в котором значение 0x19BA. Далее читаем регистр калибровки Cal (0x05) со значением 0x1000. Потом регистр тока шунта Iшунт. (0x04), в котором значение 0x1959. Потом снова читаем регистр калибровки Cal (0x05). И наконец читаем регистр мощности Pwr (0x03), в котором находится значение 0x042B. При этом монитор последовательного порта показывает следующее:

Вывод монитора порта в момент снятия осциллограммы с датчика INA219

Рассмотрим, как привести данные в регистрах «в человеческий вид». Нам интересны не все значения, а только напряжения и ток. Плюс регистр калибровки, который играет роль поправочного коэффициента.

Регистр Shunt Voltage (адрес 0x01) датчика INA219

Напряжение на шунте равняется тому значению, которое записано в регистре, поделённое на 100: Uшунта = Shunt_voltage/100 = 0x1957/100 = 64.87 (мВ) Для случаев, когда напряжение отрицательное, расчёт несколько сложнее. Это можно посмотреть в техническом описании (datasheet).

Регистр Bus Voltage (адрес 0x02) датчика INA219

Начнём с регистра, в котором записано напряжение шины, т.к. он самый простой. В текущий момент данные в нём это 0x19BA. Согласно всё тому же техническому описанию (datasheet на INA219), для преобразования значения в милливольты необходимо сделать следующее: Uшины = (0x19BA >> 3) × 32000 (мВ) / 8000 = 3292 (мВ).

Здесь 0x19BA это значение в регистре. Его нужно сдвинуть на 3 разряда вправо, т.к. данные о напряжении хранятся, начиная с 3-го разряда. 32000 (мВ) – это предел шкалы измерения (он указан в регистре конфигурации). А 8000 – это предел шкалы измерения в отсчётах. Получается 3292 (мВ) или 3.29 вольта, что мы и видим в выводе скетча в мониторе порта Arduino.‬

Регистр Current Register (адрес 0x04) датчика INA219

Значение тока рассчитывается тоже просто: I = 0x1959 × 0x1000 / 4096 = 6489.

Значение в регистре напряжения шунта 0x1959 умножается на значение регистра калибровки, который в нашем случае равен 0x1000. А затем результат делится на 4096 (что, кстати, то же самое, что 0x1000). То есть ток получается равным 6489. Но в каких единицах? Чтобы ответить на этот вопрос, необходимо определить параметр Current_LSB: Current_LSB = 0.04096 / 0x1000 / 0.1 (Ом) = 0.0001 Здесь 0x1000 – значение регистра калибровки, 0.1 (Ом) – сопротивление шунта, а 0.04096 – просто коэффициент. Теперь посчитанный ток нужно умножить на число Current_LSB, и получим 0.6489 (А) или 648,90 (мА). Такой ток мы видим и в мониторе.

Регистр Power (адрес 0x03) датчика INA219

Мощность рассчитывается как произведение напряжения на шине и тока: P = Uшины × I = 3292 (мВ) × 648.9 (мА) = 2136 (мВт)

Небольшое расхождение с выводом монитора Arduino связано с ошибкой округления. А именно, если посмотреть на вывод монитора порта, мы увидим, что значение напряжения на шине принято равным 3.29 В, в то время как в регистре записано 3.292 В. Из-за этого рассчитанное значение на 2 милливатта больше, чем показанное в выводе скетча.

7 Подключение трёхканального датчика тока и напряжения INA3221 к Arduino

Датчик тока INA3221 практически идентичен датчику INA219. Основное отличие состоит в том, что он имеет 3 измерительных канала вместо одного. Показания с них можно снимать независимо друг от друга. Будем использовать вот такую небольшую плату с датчиком:

Плата с датчиком INA3221

Подключается данный модуль к Arduino всего 4-мя проводами: два для питания, и ещё два – шина I2C.

Вывод модуля INA3221 Вывод Arduino Назначение
SDA A4 Данные шины I2C
SCL A5 Импульсы синхронизации шины I2C
VS +3.3V Питание
GND GND Общий

Подключение датчика INA3221 к Arduino Nano

Назначение остальных выводов модуля показано на приведённом рисунке и в таблице ниже.

Вывод модуля INA3221 Назначение
TC Цифровой выход оповещения о сбое таймингов (timing control alert).
WAR Цифровой выход оповещения о сбоях измерений (warning).
CRI Цифровой выход оповещения о критических сбоях (critical).
PV Цифровой выход оповещения о валидности питающего напряжения (power valid).
VPU Аналоговый вход подтягивающего напряжения для смещения выходных цепей определения валидности питания.
POW Аналоговый вход питания измеряемой нагрузки.
CH1, CH2, CH3 Порты для подключения измеряемых цепей.

Используем библиотеку для работы с датчиком INA3221. Поместим файлы с расширениями *.cpp и *.h в одну директорию, в ней же создадим файл с расширением *.ino и следующим содержимым:

Скетч для чтения показаний датчика INA3221

#include "Wire.h" #include "SDL_Arduino_INA3221.h" SDL_Arduino_INA3221 ina3221; // создаём экземпляр класса датчика // Три канала измерения датчика INA3221 #define CHANNEL_1 1 #define CHANNEL_2 2 #define CHANNEL_3 3 void setup(void) < Serial.begin(115200); Serial.println("Arduino INA3221 test"); ina3221.begin(); Serial.print("ID=0x"); int Serial.println(id, HEX); Serial.println("Measuring voltage and current with ina3221 . "); >void loop(void) < Serial.println("---------------------------------------------"); Serial.println("Channel:\t\t(1)\t(2)\t(3)\t"); // "\t" - это символ табуляции // Вывод напряжений по трём каналам: Serial.print("Bus voltage, V: \t"); float busvoltage1 = ina3221.getBusVoltage_V(CHANNEL_1); float busvoltage2 = ina3221.getBusVoltage_V(CHANNEL_2); float busvoltage3 = ina3221.getBusVoltage_V(CHANNEL_3); Serial.print(busvoltage1); Serial.print("\t"); Serial.print(busvoltage2); Serial.print("\t"); Serial.print(busvoltage3); Serial.println("\t"); // Вывод напряжений на шунте по трём каналам: Serial.print("Shunt voltage, mV: \t"); float shuntvoltage1 = ina3221.getShuntVoltage_mV(CHANNEL_1); float shuntvoltage2 = ina3221.getShuntVoltage_mV(CHANNEL_2); float shuntvoltage3 = ina3221.getShuntVoltage_mV(CHANNEL_3); Serial.print(shuntvoltage1); Serial.print("\t"); Serial.print(shuntvoltage2); Serial.print("\t"); Serial.print(shuntvoltage3); Serial.println("\t"); // Вывод напряжений нагрузки по трём каналам: Serial.print("Load voltage, V: \t"); float loadvoltage1 = busvoltage1 + (shuntvoltage1 / 1000); float loadvoltage2 = busvoltage2 + (shuntvoltage2 / 1000); float loadvoltage3 = busvoltage3 + (shuntvoltage3 / 1000); Serial.print(loadvoltage1); Serial.print("\t"); Serial.print(loadvoltage2); Serial.print("\t"); Serial.print(loadvoltage3); Serial.println("\t"); // Вывод тока по трём каналам: Serial.print("Current, mA: \t\t"); float current_mA1 = ina3221.getCurrent_mA(CHANNEL_1); float current_mA2 = ina3221.getCurrent_mA(CHANNEL_2); float current_mA3 = ina3221.getCurrent_mA(CHANNEL_3); Serial.print(current_mA1); Serial.print("\t"); Serial.print(current_mA2); Serial.print("\t"); Serial.print(current_mA3); Serial.println("\t"); delay(2000); >

Загрузим данный скетч в память Arduino. Перед тем как подключать нагрузку, необходимо подать с источника питания напряжение на контакты POW и GND, расположенные с одного из краёв модуля. Это напряжение будет подаваться на нагрузку и оно в данном модуле общее для всех трёх измерительных каналов. Допустимый диапазон напряжений от 0 до 26 вольт. Я сейчас подам 5 В.

Удобно в места подключения нагрузки и питания впаять клеммники для быстрого монтажа.

Теперь можно подключать нагрузку. Давайте нагрузим выходы модуля и посмотрим, что будет выводиться в монитор последовательного порта. Я подключу на канал 1 два параллельных резистора номиналом 4,3 кОм, что в сумме даст сопротивление 2,15 кОм. А на канал 3 – один резистор 4,3 кОм.

Датчик тока INA3221 с нагрузкой

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

Показания датчика тока INA3221 в мониторе COM-порта

Если мы подключим в измеряемую цепь амперметр, то убедимся, что показания цифрового датчика INA3221 довольно точно совпадают с показаниями амперметра.

Показания датчика тока INA3221 в сравнении с амперметром

Скачать вложения:

  • Скачать datasheet на монитор тока и напряжения INA219 (518 Скачиваний)
  • Скачать datasheet на датчик тока ACS712 (540 Скачиваний)
  • Скачать datasheet на монитор тока и напряжения INA3221 (785 Скачиваний)