Датчик тока и напряжения INA3221 (Arduino)

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

Диапазон измеряемого напряжения находится в диапазоне от 0 до 26 В, а максимальный измеряемый ток составляет около 1,6 А, на канал. Но ограничение в 1,6 А это ограничение установленного шунта, который имеет сопротивление 0,1 Ом, при желании сопротивление шунта можно уменьшить для увеличения  диапазона измеряемого тока.

Характеристики:

  • Измерение напряжения от 0 до 26 В
  • Три независимых канала для измерений
  • Собственное потребление 350 мкА
  • Питание от 2,7 до 5,5 В
  • Интерфейсы SMBus и I2C.
  • Четыре программируемых адреса
  • Программируемое усреднение значений
  • Работает в интервале температур от -40 до +125 °C
  • Контроль напряжений питающей шины и трех токовых шунтов
  • Офсетное напряжение максимум ± 80 мкВ
  • Разрешение АЦП 12 бит
  • С предустановленным шунтом в 0,1 ома максимальный измеряемый ток 1,6 ампера на канал
  • Диапазон измерителя шунта  от -160,84 до +160,8 мВ

Назначение контактов:

  • VS — питание модуля 2,7 до 5,5 В
  • GND — питание модуля, земля
  • SCL — последовательные данные шины I2C (serial data)
  • SDA — последовательное тактирование шины данных I2C (serial clock)
  • PV — цифровой выход сигнала превышения напряжения, программируется, если вышел за указанные пределы, установится в единицу
  • CRI — цифровой выход о критической ситуации, такие ошибки как переполюсовка или короткой замыкание, установится в единицу
  • WAR — предупреждение об ошибке измерения
  • ТС — контроль таймингов, цифровой. Меняет свое состояние если пробит один из шунтов, установится в единицу
  • CH1, CH2, CH3 — вывод, для подключения нагрузки
  • VPU — вывод мониторинга допустимой мощности. Подтянут к контакту PV через резистор 10 кОм
  • POW — плюс питания (основное силовое питание от 0 до 26 В)
  • GND — минус от источника POW

Адресные перемычки позволяют изменить I2C адрес модуля.

  • GND — 0x40
  • SCL — 0x41
  • SDA — 0x42
  • VS — 0x43

Назначение светодиодов

  • LED1 — индикатор наличия питания
  • LED2 — указывает на то что питание находится в запрограммированном диапазоне
  • LED3 — указатель критической проблемы такой как неверная полярность или короткое замыкание
  • LED4 — ошибка измерения
  • LED5 — обрыв линии питания одного из трех выводов

Для использования модуля INA3221 в среде программирования Arduino IDE существует несколько библиотек, одна из них это  — https://github.com/Tinyu-Zhao/INA3221.git. Она достаточно проста в использовании, при измерении всю полученную информацию выводит в монитор порта.

Скетч (I2C адрес 0х40):

#include <Wire.h>
#include <INA3221.h>

#define SERIAL_SPEED     9600  // serial baud rate
#define PRINT_DEC_POINTS 3       // decimal points to print

// Set I2C address to 0x41 (A0 pin -> VCC)
INA3221 ina3221(INA3221_ADDR40_GND);

void setup() {
    Serial.begin(SERIAL_SPEED);

    while (!Serial) {
        delay(1);
    }

    ina3221.begin();
    ina3221.reset();

    // Set shunt resistors to 10 mOhm for all channels
    ina3221.setShuntRes(100, 100, 100);

    // Set series filter resistors to 10 Ohm for all channels.
    // Series filter resistors introduce error to the current measurement.
    // The error can be estimated and depends on the resitor values and the bus
    // voltage.
    ina3221.setFilterRes(100, 100, 100);
}

void loop() {
    float current[3];
    float current_compensated[3];
    float voltage[3];

    current[0]             = ina3221.getCurrent(INA3221_CH1);
    current_compensated[0] = ina3221.getCurrentCompensated(INA3221_CH1);
    voltage[0]             = ina3221.getVoltage(INA3221_CH1);

    current[1]             = ina3221.getCurrent(INA3221_CH2);
    current_compensated[1] = ina3221.getCurrentCompensated(INA3221_CH2);
    voltage[1]             = ina3221.getVoltage(INA3221_CH2);

    current[2]             = ina3221.getCurrent(INA3221_CH3);
    current_compensated[2] = ina3221.getCurrentCompensated(INA3221_CH3);
    voltage[2]             = ina3221.getVoltage(INA3221_CH3);

    Serial.print("Channel 1: \n Current: ");
    Serial.print(current[0], PRINT_DEC_POINTS);
    Serial.print("A\n Compensated current: ");
    Serial.print(current_compensated[0], PRINT_DEC_POINTS);
    Serial.print("\n Voltage: ");
    Serial.print(voltage[0], PRINT_DEC_POINTS);
    Serial.println("V");

    Serial.print("Channel 2: \n Current: ");
    Serial.print(current[1], PRINT_DEC_POINTS);
    Serial.print("A\n Compensated current: ");
    Serial.print(current_compensated[1], PRINT_DEC_POINTS);
    Serial.print("\n Voltage: ");
    Serial.print(voltage[1], PRINT_DEC_POINTS);
    Serial.println("V");

    Serial.print("Channel 3: \n Current: ");
    Serial.print(current[2], PRINT_DEC_POINTS);
    Serial.print("A\n Compensated current: ");
    Serial.print(current_compensated[2], PRINT_DEC_POINTS);
    Serial.print("\n Voltage: ");
    Serial.print(voltage[2], PRINT_DEC_POINTS);
    Serial.println("V\n");

    delay(1000);
}

Вывод монитора порта:

Как видно на скриншоте в монитор порта выводятся все три канала, проводится измерение тока, напряжение падения на шунте и напряжение на выходе (измерение напряжения на выходе производится после шунта).

Далее рассмотрим подробней работу ИМС INA3221, запустим модуль без использования библиотеки, рассмотрим работу регистров.

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

Таблица регистров:

Далее рассмотрим подробнее несколько основных регистров. Все регистры длиной 16 бит.

Configuration Register 0х00

Этот регистр содержит основные первоначальные настройки INA3221

Биты:

  • RST — установка 1 вызовет перезагрузку ИМС
  • CH1en — CH3en включает измерительные каналы
  • AVG2-0 — биты для усреднения результата измерения:
    • 000 = 1 (default)
    • 001 = 4
    • 010 = 16
    • 011 = 64
    • 100 = 128
    • 101 = 256
    • 110 = 512
    • 111 = 1024
  • VBUSCT2-0 — устанавливает время преобразования для измерителя напряжения, чем больше, тем более точные измерения:
    • 000 = 140 μs
    • 001 = 204 μs
    • 010 = 332 μs
    • 011 = 588 μs
    • 100 = 1.1 ms (default)
    • 101 = 2.116 ms
    • 110 = 4.156 ms
    • 111 = 8.244 ms
  • VSHCT2-0 — устанавливают время преобразования для измерителя шунта, биты аналогичны VBUSCT2-0
  • MODE3-1 — режим работы

Далее идут шесть регистров для чтения которые содержат информацию об измерении напряжения и напряжения шунта для всех каналов:

Channel-1 Shunt-Voltage Register

Channel-2 Shunt-Voltage Register

Channel-3 Shunt-Voltage Register

Channel-1 Bus-Voltage Register

Channel-2 Bus-Voltage Register

Channel-3 Bus-Voltage Register

Как видно измерение 12 бит, плюс еще один бит (SING) который содержит полярность измеренного значения.

Для регистров Shunt-Voltage Register разрешение младшего бита 40 мкВ, для Bus-Voltage Register 8 мВ.

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

Для одиночного измерения служат регистры:

  • Channel-1 Critical Alert Limit
  • Channel-2 Critical Alert Limit
  • Channel-3 Critical Alert Limit

Для усредненного измерения служат регистры:

  • Channel-1 Warning Alert Limit
  • Channel-2 Warning Alert Limit
  • Channel-3 Warning Alert Limit

Теперь как это работает, при проведении измерения регистр Channel-1 Bus Voltage (регистр измеренного напряжения канал 1) постоянно сравнивает свое значение с регистром контроля первого канала Channel-1 Critical Alert Limit, если значение регистра измерения больше значения регистра контроля, то в зависимости от настроек регистра Mask/Enable (см. дальше), может изменится состояние выхода CRI, загорится светодиод на плате модуля, изменится один из битов (флаг) регистра Mask/Enable.

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

Далее следуют регистр Shunt-Voltage Sum, этот регистр содержит в себе сумму падений напряжений всех шунтов, то есть по сути сумму всех токов выходов CH1, CH2 и CH3:

За ним следует регистр контроля Shunt-Voltage Sum Limit для суммы всех токов, который может содержать максимально допустимое значение тока потребления модуля:

Если значение регистра Shunt-Voltage Sum превысит значение регистра Shunt-Voltage Sum Limit , то в зависимости от настроек регистра Mask/Enable (см. дальше), так же произойдет изменение состояния выхода CRI или битов регистра Mask/Enable.

Регистр Mask/Enable

Содержит биты настроек регистров контроля и флаги состояний регистров контроля.

Основные биты регистра Mask/Enable:

  • SCC1-3 — управление каналом суммирования падений напряжений шунтов. Включает каналы для сравнения результата измерения с регистром контроля.
  • WEN — включение предупреждающего сигнала.
  • CEN — активирование критического оповещения.
  • CF1-3 —  флаги критического оповещения при превышении регистров контроля напряжения при одиночном измерении
  • SF —  флаг предупреждения о превышении регистра суммы падений напряжений шунтов.
  • WF1-3 — флаги критического оповещения при превышении регистров контроля напряжения при усредненном измерении
  • PVF — флаг предупреждения о допустимой мощности.

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

#define ADDR 0x40 // I2C address
#define UR   0.1    // R (Om)
#define AVG  0B100
#define VBUS 0B111
#define CH   0B111
#define VSH  0B111
#define MODE 0B111

#include <Wire.h>

void setup() {
    Wire.begin();
    Serial.begin(9600);
    delay(100);
    I2C_write(0x00, 0x00|(CH<<12)|(AVG<<9)|(VBUS<<6)|(VSH<<3)|MODE); // Configuration Register
    Serial.print("Manufacturer ID ");Serial.println(I2C_read(0xFE),HEX);
    Serial.print("Die ID ");Serial.println(I2C_read(0xFF),HEX);
}

void loop() {
    int ur1=(I2C_read(0x01)>>3);
    int u1=(I2C_read(0x02)>>3);
    int ur2=(I2C_read(0x03)>>3);
    int u2=(I2C_read(0x04)>>3);
    int ur3=(I2C_read(0x05)>>3);
    int u3=(I2C_read(0x06)>>3);
    
    Serial.print("Ur_1 ");Serial.print(ur1*0.04,3);Serial.println(" mV");
    Serial.print("I_1 ");Serial.print(ur1*0.04/UR,1);Serial.println(" mA");
    Serial.print("U_1 ");Serial.print(u1*0.008);Serial.println(" V");
    Serial.println();
    Serial.print("Ur_2 ");Serial.print(ur2*0.04,3);Serial.println(" mV");
    Serial.print("I_2 ");Serial.print(ur2*0.04/UR,1);Serial.println(" mA");
    Serial.print("U_2 ");Serial.print(u2*0.008);Serial.println(" V");
    Serial.println();
    Serial.print("Ur_3 ");Serial.print(ur3*0.04,3);Serial.println(" mV");
    Serial.print("I_3 ");Serial.print(ur3*0.04/UR,1);Serial.println(" mA");
    Serial.print("U_3 ");Serial.print(u3*0.008);Serial.println(" V");
    Serial.println();
    delay(2000);
}


unsigned int I2C_read(byte reg){
  Wire.beginTransmission(ADDR);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(ADDR,2);
  while(Wire.available()<1);
  unsigned int value = (Wire.read()<<8) | Wire.read();
  return value;
  } 

void I2C_write(byte reg, unsigned int data){  
  Wire.beginTransmission(ADDR);
  Wire.write(reg);
  Wire.write((data&0xFF00)>>8);
  Wire.write(data&0x00FF);
  Wire.endTransmission();
  }  

Все полученные данные выводятся в монитор порта:

В скетче для поддержки шины I2C используется библиотека Wire (входит в состав Arduino IDE), при помощи двух функций осуществляется запись и чтение регистров датчика:

unsigned int I2C_read(byte reg){
  Wire.beginTransmission(ADDR);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(ADDR,2);
  while(Wire.available()<1);
  unsigned int value = (Wire.read()<<8) | Wire.read();
  return value;
  } 

void I2C_write(byte reg, unsigned int data){  
  Wire.beginTransmission(ADDR);
  Wire.write(reg);
  Wire.write((data&0xFF00)>>8);
  Wire.write(data&0x00FF);
  Wire.endTransmission();
  }  

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

I2C_write(0x00, 0x00|(CH<<12)|(AVG<<9)|(VBUS<<6)|(VSH<<3)|MODE); // Configuration Register

Считываем данные регистров напряжений и падений напряжений шунтов:

    int ur1=(I2C_read(0x01)>>3);
    int u1=(I2C_read(0x02)>>3);
    int ur2=(I2C_read(0x03)>>3);
    int u2=(I2C_read(0x04)>>3);
    int ur3=(I2C_read(0x05)>>3);
    int u3=(I2C_read(0x06)>>3);

А далее просто все выводим в монитор порта, попутно делая расчет тока:

    Serial.print("Ur_1 ");Serial.print(ur1*0.04,3);Serial.println(" mV");
    Serial.print("I_1 ");Serial.print(ur1*0.04/UR,1);Serial.println(" mA");
    Serial.print("U_1 ");Serial.print(u1*0.008);Serial.println(" V");
    Serial.println();
    Serial.print("Ur_2 ");Serial.print(ur2*0.04,3);Serial.println(" mV");
    Serial.print("I_2 ");Serial.print(ur2*0.04/UR,1);Serial.println(" mA");
    Serial.print("U_2 ");Serial.print(u2*0.008);Serial.println(" V");
    Serial.println();
    Serial.print("Ur_3 ");Serial.print(ur3*0.04,3);Serial.println(" mV");
    Serial.print("I_3 ");Serial.print(ur3*0.04/UR,1);Serial.println(" mA");
    Serial.print("U_3 ");Serial.print(u3*0.008);Serial.println(" V");

Далее для примера соберем простую схему состоящую из датчика INA3221 и дисплея OLED 1.3″ 128X64 на базе контроллера SH1106.

Суть скетча простая, на дисплей выводятся показания тока и напряжения для трех каналов, а так же выводится суммарный ток (считанный с регистра Shunt-Voltage Sum Register), зададим ограничение по суммарному току в размере 600 мА, укажем это ограничение в регистре контроля Shunt-Voltage Sum-Limit Register.

При превышении значения ограничения суммарного тока на дисплей выводится надпись «ERROR» и меняется логическое состояние выхода CRI.

#define ADDR 0x40 // I2C address
#define UR   0.1    // R (Om)
#define AVG  0B001
#define VBUS 0B111
#define CH   0B111
#define VSH  0B111
#define MODE 0B111

#define I_ogr 0.6 // A

#include <Wire.h>
#include <U8glib.h>            // https://github.com/olikraus/u8glib/

U8GLIB_SH1106_128X64 u8g(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST);

int ogr_i;

void setup() {
    Wire.begin();
    Serial.begin(9600);
    delay(100);
    I2C_write(0x00, 0x00|(CH<<12)|(AVG<<9)|(VBUS<<6)|(VSH<<3)|MODE); // Configuration Register
    I2C_write(0x0F, 0b111<<12);
    ogr_i = (int)(I_ogr/0.0004)<<1;
    I2C_write(0x0E, ogr_i); // CRI | REG 0X0F BIT 6 | LED3
    Serial.print("Manufacturer ID ");Serial.println(I2C_read(0xFE),HEX);
    Serial.print("Die ID ");Serial.println(I2C_read(0xFF),HEX);
}

void loop() {
    int ur1=(I2C_read(0x01)>>3);
    int u1=(I2C_read(0x02)>>3);
    int ur2=(I2C_read(0x03)>>3);
    int u2=(I2C_read(0x04)>>3);
    int ur3=(I2C_read(0x05)>>3);
    int u3=(I2C_read(0x06)>>3);
    int ur_s=(I2C_read(0x0D)>>1);
    bool err = (I2C_read(0x0f)>>6)&1;
  
    Serial.print("Ur_1 ");Serial.print(ur1,BIN);Serial.println(" mV");
    Serial.print("I_1 ");Serial.print(ur1*0.04/UR,1);Serial.println(" mA");
    Serial.print("U_1 ");Serial.print(u1*0.008);Serial.println(" V");
    Serial.println();
    Serial.print("Ur_2 ");Serial.print(ur2*0.04,3);Serial.println(" mV");
    Serial.print("I_2 ");Serial.print(ur2*0.04/UR,1);Serial.println(" mA");
    Serial.print("U_2 ");Serial.print(u2*0.008);Serial.println(" V");
    Serial.println();
    Serial.print("Ur_3 ");Serial.print(ur3*0.04,3);Serial.println(" mV");
    Serial.print("I_3 ");Serial.print(ur3*0.04/UR,1);Serial.println(" mA");
    Serial.print("U_3 ");Serial.print(u3*0.008);Serial.println(" V");
    
    u8g.firstPage();  
    do {
    u8g.setFont(u8g_font_profont15r);
    u8g.drawLine(0, 52, 128, 52);
    u8g.setPrintPos(0, 12);u8g.print(u1*0.008);u8g.drawStr(45,12,"V");
    u8g.setPrintPos(70, 12);u8g.print(ur1*0.00004/UR,3);u8g.drawStr(115,12,"A");

    u8g.setPrintPos(0, 30);u8g.print(u2*0.008);u8g.drawStr(45,30,"V");
    u8g.setPrintPos(70, 30);u8g.print(ur2*0.00004/UR,3);u8g.drawStr(115,30,"A");

    u8g.setPrintPos(0, 48);u8g.print(u3*0.008);u8g.drawStr(45,48,"V");
    u8g.setPrintPos(70, 48);u8g.print(ur3*0.00004/UR,3);u8g.drawStr(115,48,"A");

    u8g.setPrintPos(70, 64);u8g.print(ur_s*0.00004/UR,3);u8g.drawStr(115,64,"A");
    if(err==1){u8g.drawStr(0,64,"ERROR");}
    } while( u8g.nextPage() );
    delay(1000);
}


unsigned int I2C_read(byte reg){
  Wire.beginTransmission(ADDR);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(ADDR,2);
  while(Wire.available()<1);
  unsigned int value = (Wire.read()<<8) | Wire.read();
  return value;
  } 

void I2C_write(byte reg, unsigned int data){  
  Wire.beginTransmission(ADDR);
  Wire.write(reg);
  Wire.write((data&0xFF00)>>8);
  Wire.write(data&0x00FF);
  Wire.endTransmission();
  }  

Ограничение по току:

  • #define I_ogr 0.6 // A

Считываем флаг редупреждения о превышении регистра суммы падений напряжений шунтов:

  • bool err = (I2C_read(0x0f)>>6)&1;

Расчет значения ограничения тока для регистра контроля суммы токов:

  • ogr_i = (int)(I_ogr/0.0004)<<1;
  • I2C_write(0x0E, ogr_i);

Даташит — ina3221.pdf

Форум — http://forum.rcl-radio.ru/viewtopic.php?id=674

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

Войти с помощью: