Реклама на сайте DatasheetsDatasheets

KAZUS.RUN - Электронный портал. Принципиальные схемы, Datasheets, Форум по электронике

Новости электроники Новости Литература, электронные книги Литература Документация, даташиты Документация Поиск даташитов (datasheets)Поиск PDF
  От производителей
Новости поставщиков
В мире электроники

  Сборник статей
Книги и журналы
FAQ по электронике

  Datasheets
Поиск SMD
Онлайн справочник

Принципиальные схемы Схемы Каталоги программ, сайтов Каталоги Общение, форум Общение Ваш аккаунтАккаунт
  Каталог схем
Схемы и проекты
Принципиальные схемы
  Программы
Каталог сайтов
Калькуляторы
  Форумы по электронике
Удаленная работа
Помощь проекту


Измерение переменного и постоянного тока на Arduino с датчиком Холла ACS758


15 000 000 даташитовпоиск по параметрам · аналоги · заводские PDFНайти даташит →

Измеритель тока на Arduino Uno и датчике Холла ACS758 считает истинное среднеквадратичное значение переменного тока и среднее значение постоянного, а предел измерения выбирает сам. В статье разобраны датчик, аналоговый тракт с программируемым усилением, питание и программа.

Датчик тока ACS758

ACS758 фирмы Allegro — это микросхема, сделанная специально для измерения тока частотой до 120 кГц. Она работает на эффекте Холла. Измеряемый ток идёт через встроенный проводник сопротивлением 100 мкОм, а микросхема выдаёт напряжение, пропорциональное этому току. Выход гальванически развязан с силовой цепью, поэтому мощная часть схемы всегда изолирована от слаботочной.

В семействе есть версии на 50, 100, 150 и 200 А, двунаправленные и однонаправленные. Двунаправленный датчик измеряет ток в обоих направлениях. Обычно его ставят с нагрузками переменного тока, но он подходит и для постоянного. Однонаправленный измеряет ток только в одном направлении и подходит для цепей постоянного тока.

В конструкции стоит двунаправленный ACS758ECB-200B. Он рассчитан на постоянный ток 200 А, типовая чувствительность 10 мВ/А. Двунаправленность позволяет мерить и переменный, и постоянный ток. Подойдут и другие версии ACS758, например ACS758ECB-50B с чувствительностью 40 мВ/А. Производитель советует вместо ACS758 брать более новую серию ACS770, её тоже можно поставить в эту схему.

Даташит определяет чувствительность как изменение выходного напряжения при изменении тока через первичный проводник на 1 А. При однополярном питании 5 В и нулевом токе на выходе получается 2,5 В, то есть VCC/2. Это напряжение покоя VIOUT(Q). При двуполярном питании ±2,5 В напряжение покоя относительно общего провода равно нулю. При питании 5 В, одно- или двуполярном, типовая чувствительность 10 мВ/А. Пример для однополярного питания: при токе 5 А на выходе будет VIOUT(Q) + 5 x 10 мВ = 2,5 + 0,05 = 2,550 В.

Схема и аналоговый тракт

Датчик U1 ставится в разрыв между источником и нагрузкой. Источник может давать переменный или постоянный ток, смотря какая нагрузка. Общий провод в схеме один, это GND платы Arduino Uno. На схеме плата обозначена как U8.

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

Arduino ACS758 AC/DC current measurement circuit ACS770
Нажмите для увеличения (6950x2620)

U1 питается от двуполярного напряжения ±2,5 В. Так выходной сигнал датчика проще усиливать или ослаблять операционным усилителем. При токе +200 А на выходе датчика +2 В, при -200 А -2 В, всегда относительно GND.

Дальше сигнал проходит через RC-фильтр R1C3, который срезает высокочастотные помехи, и попадает на OPA2191 (U2) от Texas Instruments. В одном корпусе OPA2191 два независимых ОУ. Первый включён повторителем напряжения и работает как буфер для выхода датчика.

Второй ОУ U2 собран инвертирующим усилителем. Его коэффициент усиления Arduino переключает программно: 10, 1 или 0,5. Усиление выбирается автоматически: на слабом сигнале 10, на сильном 0,5. Пороги переключения описаны в разделе о программе.

Цепь обратной связи переключает сдвоенный аналоговый ключ TS5A23166 (U6) от Texas Instruments. Сопротивление открытого ключа 0,9 Ом, на фоне резисторов 20 и 18 кОм им можно пренебречь. Первый ключ замыкается (NO1 соединяется с COM1), когда на IN1 логическая единица. Второй (NO2 с COM2) замыкается от единицы на IN2. Сигналы IN1 и IN2 идут с выводов 3 и 4 Arduino соответственно. Коэффициент усиления получается такой:

  • оба ключа разомкнуты: 180k / 18k = 10;
  • замкнут S1: (180k // 20k) / 18k = 18k / 18k = 1;
  • замкнуты оба: (180k // 20k // 18k) / 18k = 9k / 18k = 0,5.

Сдвиг уровня, фильтр и опорное напряжение АЦП

У переменного тока, а также у постоянного тока обратного направления часть сигнала уходит в минус. АЦП Arduino отрицательные напряжения не читает. Поэтому весь сигнал надо поднять в положительную область: добавить к нему постоянное смещение и при этом больше не менять усиление.

Для этого стоит каскад на втором OPA2191 (U7), в нём работает только один ОУ из двух. U7 питается 5 В от Arduino: вывод 8 идёт на вывод 5V платы, вывод 4 на любой из GND. Коэффициент усиления каскада равен 1. Каскад добавляет смещение 1,024 В и заодно работает как фильтр нижних частот, который убирает высшие гармоники и прочий шум. Частота среза считается так:

f = 1/(2 x пи x R x C) = 3,12 кГц, где R = R15 // R16 // R17 + R18 = 5,1 кОм, C = C16 = 10 нФ.

Входы свободного ОУ в U7 подключены: инвертирующий к GND, неинвертирующий к опорному напряжению 2,048 В. Так между рабочим и свободным усилителем не возникает перекрёстных наводок. OPA2191 выбран за малое напряжение смещения (±5 мкВ), низкий шум (15 нВ/sqrtГц на частоте 1 кГц) и малый дрейф смещения (±0,1 мкВ/°C).

Точные 2,048 В даёт буферизованный источник опорного напряжения MCP1501-20 (U9) от Microchip Technology. Он тоже питается от 5 В платы Arduino. Его выход проходит через фильтр и идёт на вывод AREF, так что 2,048 В становится верхней границей шкалы АЦП. Смещение 1,024 В приходится ровно на середину этой шкалы, поэтому сигнал может одинаково отклоняться в обе стороны.

Питание ±2,5 В

От двуполярного питания работают датчик U1, ОУ U2 и ключ U6. Плюсовое плечо даёт LDO-стабилизатор LT1761-SD (U5) от Analog Devices, на его вход идут 5 В с Arduino. Выход примерно +2,5 В задают резисторы на выводе ADJ: R13 = 15 кОм и R14 = 16 кОм. Формула выходного напряжения есть в даташите LT1761.

Минусовое плечо даёт отрицательный LDO-стабилизатор LT1964-SD (U4), тоже от Analog Devices. На выводе ADJ стоят R11 = 15 кОм и R12 = 16 кОм (расчёт по даташиту LT1964), на выходе примерно -2,5 В. На вход ему нужно -5 В. Их даёт изолированный DC/DC-преобразователь B0505S-2W (U3): и вход, и выход у него 5 В, и они гальванически развязаны. Если соединить плюсовой вывод выхода с GND схемы, на минусовом выводе будет -5 В относительно общего провода. Сам преобразователь питается от 5 В платы Arduino.

Индикатор, кнопка и режимы измерения

Ток через датчик, то есть ток нагрузки, показывает ЖК-индикатор 1602 (2 строки по 16 символов). Эти же значения Arduino передаёт на компьютер, их видно в мониторе последовательного порта. Индикатор подключается так:

  • RS на цифровой вывод 5 Arduino, E на 6, D4 на 7, D5 на 8, D6 на 9, D7 на 10;
  • VSS, RW, D0-D3 и K на GND;
  • VEE, регулировка контраста, на движок переменного резистора 10 кОм;
  • VDD на 5V Arduino, A на 5V через резистор 330 Ом (A и K — анод и катод светодиодной подсветки).

Кнопка на цифровом выводе 2 по кругу переключает три режима:

  • AC — истинное среднеквадратичное значение (TRMS) переменного тока, постоянная составляющая в результат не входит. В этом режиме прибор включается;
  • DC — среднее значение тока через датчик;
  • AC+DC — TRMS вместе с постоянной составляющей.

Программа

Код проверен на Arduino Uno. Среднее значение, оно же постоянная составляющая, в дискретном времени равно сумме всех отсчётов, делённой на их число:

mean value equation

Среднеквадратичное значение считается по формуле:

RMS value equation

АЦП микроконтроллера ATmega328P 10-разрядный. При опоре 2,048 В напряжению 2,048 В соответствует код 1023, а 0 В код 0, то есть 2 мВ на единицу. Чтобы поднять точность и разрешение, автор применил передискретизацию с децимацией (oversampling and decimation). Она добавляет к 10 битам АЦП ещё 2, и получаются полноценные 12-битные отсчёты. Для двух дополнительных бит на каждый отсчёт делается 16 измерений, и их сумма делится на 4. Здесь 16 = 4^2, 4 = 2^2, а показатель степени 2 равен числу добавляемых бит.

Отсчёты хранятся в массиве из 256 элементов (в листинге он называется _array). По ним потом считаются среднее значение и СКЗ. Массив заполняет функция get_smaples(), она подряд делает 16 x 256 = 4096 чтений АЦП. Там же исправляется полярность, которую переворачивает инвертирующий усилитель. При расчёте отклонения от смещения не больше 5 единиц в сумму не попадают, это простой фильтр шума.

Автокалибровка. При включении программа измеряет и запоминает смещение всей схемы. Оно складывается, например, из несимметрии питания ±2,5 В, смещения самого ACS758 и смещений ОУ. Значения для каждого из трёх усилений (10, 1 и 0,5) записываются в массив dc_offset[3]. Поэтому, когда подаёте питание на Arduino, ток через датчик идти не должен. Иначе результаты в режимах DC и AC+DC будут неточными. На режим AC калибровка не влияет: там постоянная составляющая заново считается по каждой пачке отсчётов, а DC и AC+DC вычитают смещение, сохранённое при калибровке.

Автовыбор предела. Усиление уменьшается, когда среднеквадратичное или среднее напряжение на аналоговом входе A0 превышает 500 мВ. Увеличивается оно, когда напряжение падает ниже 50 мВ при усилении 1 или ниже 250 мВ при усилении 0,5. После переключения измерение начинается заново. Напряжение на входе делится на текущий коэффициент усиления и на чувствительность датчика, так получается ток. Чувствительность задана константой ACS758_SENS = 10 мВ/А для версии -200B.

Функции программы:

  • void current_type_set() — обработчик прерывания от кнопки на выводе 2. Нажатие сразу вызывает прерывание, а переменную current_type увеличивает уже loop(). По этой переменной программа различает три режима;
  • void gain_set(uint8_t g) — выставляет коэффициент усиления по значению g;
  • void get_smaples() — заполняет массив 256 12-битными отсчётами;
  • bool debounce() — подавляет дребезг кнопки. Возвращает true, если нажатие подтвердилось, и false при ошибке.
/************************************************************************
 *
 * AC & DC Current measurement using Arduino and Allegro ACS758 current sensor.
 * Calculated current values are printed on 1602 LCD screen and serial monitor.
 * This is a free software with NO WARRANTY - Use it at your own risk!
 * https://simple-circuit.com/
 *
 ************************************************************************/

#include <LiquidCrystal.h>    // include Arduino LCD library

// LCD module connections (RS, E, D4, D5, D6, D7)
LiquidCrystal lcd(5, 6, 7, 8, 9, 10);

#define ANALOG_CHANNEL  A0    // define analog channel input
#define REF_VOLTAGE     2048  // +ive reference voltage for ADC, in millivolts
#define ACS758_SENS     10    // ACS758 sensitivity = 10mV/A (for ACS758-200B version)
#define CUR_SEL         2     // current type select pushbutton pin
// define autoranging control pins
#define CH0             3
#define CH1             4
// define current type
#define AC     0   // AC current
#define DC     1   // DC current
#define AC_DC  2   // AC+DC current (AC current with DC offset)

// variables
byte current_type = AC;   // current type according to previous 3 definitions
const uint16_t n = 256;   // number of samples
float _array[n];          // sample array with 'n' elements
const float gain_table[3] = {10.0, 1.0, 0.5};   // programmable gains
byte gain;                // gain variable, may be 0, 1 or 2
float dc_offset[3];       // auto-calibration dc offset array with 3 elements (according to gain)

void setup(void)
{
  Serial.begin(9600);
  pinMode(CUR_SEL, INPUT_PULLUP);
  pinMode(CH0, OUTPUT);
  pinMode(CH1, OUTPUT);

  lcd.begin(16, 2);      // set up the LCD's number of columns and rows
  lcd.setCursor(0, 0);   // move cursor to column 0, row 0 [position (0, 0)]
  lcd.print("ACS758 Current =");

  analogReference(EXTERNAL);   // set positive reference voltage to external

  // do auto-calibration to the circuit (no current should flow through the ACS758 sensor)
  for (byte i = 0; i < 3; i++)
  {
    float __offset = 0;
    gain_set(i);
    get_smaples();
    for (uint16_t j = 0; j < n; j++)
      __offset += _array[j];
    __offset /= n;
    dc_offset[i] = __offset;
  }

  gain = 0;
  gain_set(gain);

  attachInterrupt(digitalPinToInterrupt(CUR_SEL), current_type_set, FALLING);   // interrupt enable
}

volatile bool button = 0;   // variable for CUR_SEL button press
// set current type: AC, DC or AC+DC
void current_type_set()
{
  button = 1;
  detachInterrupt(digitalPinToInterrupt(CUR_SEL));   // interrupt disable
  loop();
}

// gain set function
void gain_set(uint8_t g)
{
  switch (g)
  {
    case 0:
      digitalWrite(CH0, LOW);
      digitalWrite(CH1, LOW);
      break;
    case 1:
      digitalWrite(CH0, HIGH);
      digitalWrite(CH1, LOW);
      break;
    case 2:
      digitalWrite(CH0, HIGH);
      digitalWrite(CH1, HIGH);
  }
}

// analog data acquisition function
void get_smaples()
{
  // clear sample array
  for (uint16_t i = 0; i < n; i++)
    _array[i] = 0.0;

  // fill samples array with 12-bit data (add another 2 bits using oversampling technique)
  for (uint16_t i = 0; i < n; i++)
  {
    for (uint16_t j = 0; j < 16; j++)
      _array[i] += analogRead(ANALOG_CHANNEL);
  }

  for (uint16_t i = 0; i < n; i++)
  {
    _array[i] /= 4;
    // reverse readings polarities caused by the inverting amplifier
    _array[i] = abs(_array[i] - 4096.0);
  }
}

// button debounce function
bool debounce()
{
  byte count = 0;
  for (byte i = 0; i < 5; i++)
  {
    if (!digitalRead(CUR_SEL))
      count++;
    delay(10);
  }

  if (count > 2)  return 1;
  else            return 0;
}

// main loop function
void loop()
{
  if (button)
  {  // if current type button is pressed
    button = 0;
    if (debounce())
    {
      current_type++;
      if (current_type > 2)
        current_type = 0;
    }
    attachInterrupt(digitalPinToInterrupt(CUR_SEL), current_type_set, FALLING);   // interrupt enable
  }

  // get samples from 'INPUT_CHANNEL' analog pin
  get_smaples();

  float ch_voltage = 0;   // Arduino analog channel voltage variable

  if (current_type == AC || current_type == AC_DC)
  {  // AC or AC+DC type
    float _offset = 0;
    if (current_type == AC)
    {  // AC signal
      for (uint16_t i = 0; i < n; i++)   // caculate signal average value (dc offset)
        _offset += _array[i];
      _offset = _offset / n;
    }
    else   // AC+DC signal
      _offset = dc_offset[gain];   // the dc offset is the pre-calibrated one

    // calculate signal RMS value (digital representation)
    for (uint16_t i = 0; i < n; i++)
    {
      if (abs(_array[i] - _offset) > 5)   // apply some filter
        ch_voltage += sq(_array[i] - _offset);
    }
    ch_voltage = ch_voltage / n;
    ch_voltage = sqrt(ch_voltage);
  }

  else
  {  // DC type
    for (uint16_t i = 0; i < n; i++)
    {
      if (abs(_array[i] - dc_offset[gain]) > 5)   // apply some filter
        ch_voltage += _array[i] - dc_offset[gain];   // remove the pre-calibrated DC offset
    }
    ch_voltage /= n;   // average value
  }

  // calculate Arduino analog channel input voltage in millivolts
  ch_voltage = ch_voltage * REF_VOLTAGE / 4096.0;   // 4096 is max digital value of 12-bit number (oversampled ADC)

  if (gain < 2 && abs(ch_voltage) > 500.0)
  {
    gain++;
    gain_set(gain);
    return;
  }

  else if ((abs(ch_voltage) < 50.0 && gain == 1) || (abs(ch_voltage) < 250.0 && gain == 2))
  {
    gain--;
    gain_set(gain);
    return;
  }

  // calculate ACS758 sensor output voltage
  float acs758_voltage = ch_voltage / gain_table[gain];
  // now we can calculate current passing through the ACS758 sensor (in amps)
  float acs758_current = acs758_voltage / ACS758_SENS;

  lcd.setCursor(0, 1);
  Serial.print("ACS758 Current = ");
  if (acs758_current < -0.01)
  {
    lcd.print('-');
    Serial.print('-');
  }
  acs758_current = abs(acs758_current);
  lcd.print(acs758_current);
  Serial.print(acs758_current);

  if (current_type == AC)
  {
    lcd.print("A AC ");
    Serial.println("A AC");
  }
  else if (current_type == DC)
  {
    lcd.print("A DC ");
    Serial.println("A DC");
  }
  else
  {
    lcd.print("A AC+DC ");
    Serial.println("A AC+DC");
  }

  Serial.println();

}

// end of code.

Детали и сборка

Кроме Arduino Uno или аналога вроде Arduino Nano, уже описанных микросхем, ЖК-индикатора и кнопки понадобятся детали из списка ниже. На схеме могут быть номиналы, которых в нём нет:

  • 4 диода 1N4184 (D1-D4);
  • резисторы: 3 x 20 кОм (R9, R16, R17), 2 x 18 кОм (R2, R10), 4 x 15 кОм (R3, R4, R11, R13), 4 x 10 кОм (R15, R19, R20, R21), 3 x 100 Ом (R1, R7, R18);
  • переменный резистор 10 кОм (R23);
  • конденсаторы: 5 x 10 мкФ (C5, C8, C9, C14, C15), 2 x 2,2 мкФ (C18, C19), 10 x 0,1 мкФ (C1, C2, C4, C6, C7, C10, C11, C12, C13, C17), 2 x 10 нФ (C3, C16).

Резисторы берите с допуском 1% или точнее: чем меньше допуск, тем точнее прибор.

Interfacing Arduino with ACS758 ACS770 AC/DC current sensor hardware circuit
Нажмите для увеличения (1280x720)

Точность своего экземпляра автор проверял токовыми клещами UNI-T UT219DS. Часть проводов между Arduino Uno и самодельной платой припаяна прямо к обратной стороне обеих плат. Так пропадают небольшие паразитные напряжения и шум, которые возникают из-за плохого контакта между проводами-перемычками и гнёздами разъёмов Arduino.

Похожие материалы на сайте

Форум радиолюбителейтысячи решённых схем, вопросов и советов — спроси и найдиНа форум →


Реклама на сайте

KAZUS.RUN — 15 000 000 даташитов, поиск по электронным компонентам




© 2003—2026 «KAZUS.RUN - Электронный портал»