//Библиотека для работы с монитором тока INA219. Для передачи данных по протоколу TWI(I2C) используется несколько простых функций. //Датчик использует 6 16-битных регистров, ко всем им можно получить доступ с помощью функции: INA219_Get_Data (адрес устройства в сети I2C, тип данных, режим работы) //0x40 - адрес модуля по умолчанию. // ----- Тип данных ------- // 0 - Напряжение шины // 1 - Напряжение шунта // 2 - Мощность // 3 - Ток // 4 - Калибровочный регистр. // 5 - Конфигурационный регистр. // -------Режимы-------------------------------------------------------------------------------- // Во всех режимах: Напряжение 32В. // 0 - (Нормальный режим) Постоянное измерение напряжения шунта и шины. Данные пишутся в регистры датчика постоянно. // Время обновления значения 532мксек. Читаются данные которые записаны в регистры датчика на момент обращения. // 1 - (Быстрый режим) Постоянное измерение напряжения шунта и шины. Данные пишутся в регистры датчика постоянно. // Время обновления значения 84мксек. Данные в регистрах датчика будут обновляться примерно за тоже время, // которое потребуется для чтения одного регистра на скорости SCL 400кГц (1 такт = 2.5мксек) // 1 байт = 9 тактов (8 бит данных + подтв.)= 22.5мксек. // Получение данных: 1 байт адрес устройства, 1 байт адрес регистра, чтнение 2х байт = 90мксек. // 2 - (Энергосберегающий режим) Данные по запросу, ожидание 532мксек. // Содержимое регистра тока расчитывается самим датчиком по формуле: Падение напряжения на шунте * Калибровочный регистр / 4096 // Из формулы очевидно, что значение калибровочного регистра 4096 является нулевой отметкой, при которой ток равен падению напряжения на шунте. // При тех округлениях что приводятся в даташите, для сопротивления 0.1 и 0.5 Ом значение Cal получается 4096. Тем не менее, возможно вручную откалибровать // получаемое значение силы тока, по показаниям мультиметра. Значения ниже 4096 будут увеличивать показания, значения выше 4096, уменьшать. //Внести изменение в калибровочный регистр можно с помощью функции INA219_Set_Callibration (uint8_t адрес устройства, int16_t калибровочное значение) //Автор Nord_Air 01.20.2023. Библиотека распространяется свободно, по 3-й версии лицензии GNU. int INA219_Get_Data ( uint8_t adres, uint8_t data_type, uint8_t mode ); void INA219_Set_Callibration (uint8_t adres, int16_t data); //-Сокращения для работы с регистрами TWI (I2C) //-----(Two-Wire serial Interface)----------- //-------Управляющий регистр TWCR ----------- #define TWI_CONTROL_REGISTR TWCR #define TWI_Int TWINT //1 #define TWI_Enable_Ack TWEA //2 #define TWI_Start TWSTA //3 #define TWI_Stop TWSTO //4 #define TWI_Wrong_Write TWWC //5 #define TWI_Enable TWEN //6 #define TWI_Enable_Interrupt TWIE //7 //-----Регистр статуса TWSR------------------ #define TWI_STATUS_REGISTR TWSR //-----Регистр адреса/данных----------------- #define TWI_DATA_REGISTR TWDR void TWI_Sensor_Write (uint8_t adres, uint8_t *data); void TWI_Sensor_Byte_Write (uint8_t adres, uint8_t data, uint8_t t); uint16_t TWI_Sensor_Read (uint8_t adres, uint8_t X_bit); uint8_t TWI_Delay (); void setup() { Serial.begin(9600); //Запись в калибровочный регистр INA219 "нулевого" калибровочного значения для расчета тока и мощности INA219_Set_Callibration (0x40, 4096); } void loop() { //Функция опроса регистров возвращает их 16-битное значение, чтобы компилятор Arduino IDE не ругался, //на приведение типов, лучше их привести самостоятельно. (float) float voltage = ((float)(INA219_Get_Data ( 0x40, 0, 0 )) / 1000); //Значение шины в Вольтах. float shunt_voltage = ((float)(INA219_Get_Data ( 0x40, 1, 0 )) *0.01) ; //Падение напряжения на шунте в миливольтах float current = ((float)(INA219_Get_Data ( 0x40, 3, 0 )) * 0.1); int power = INA219_Get_Data (0x40, 2, 0); Serial.println ("-------------------"); Serial.print ("Voltage: "); Serial.print (voltage ); Serial.println (" V"); Serial.print ("Sunt_Voltage: "); Serial.print (shunt_voltage ); Serial.println (" mV"); Serial.print ("Current: "); Serial.print (current ); Serial.println (" mA"); Serial.print ("Power: "); Serial.println (power ); delay (5000); } void INA219_Set_Callibration (uint8_t adres, int16_t data) { int temp = data; uint8_t temp_array[4]= {4, 0x05, 0,0}; temp_array[2] = temp >> 8; temp_array[3] = data & 0xFF; TWI_Sensor_Write (adres, temp_array); } int INA219_Get_Data ( uint8_t adres, uint8_t data_type, uint8_t mode ) { // ------data type------ // 0 - Напряжение шины // 1 - Напряжение шунта // 2 - Мощность // 3 - Ток // 4 - Калибровочный регистр. // 5 - Конфигурационный регистр. int16_t returned_data; //возвращаемые функцией данные. uint8_t temp_array[4]={4, 0x00, 0, 0}; static uint8_t mode_z = 5; if ( mode_z != mode) { // Блок смены режима работы. Будет запускаться при условии что значение режима требует изменения, // после прошлого запуска. // -------Режимы-------------------------------------------------------------------------------- // Во всех режимах: Напряжение 32В. // 0 - (Нормальный режим) Постоянное измерение напряжения шунта и шины. Данные пишутся в регистры датчика постоянно. // Время обновления значения 532мксек. Читаются данные которые записаны в регистры датчика на момент обращения. // 1 - (Быстрый режим) Постоянное измерение напряжения шунта и шины. Данные пишутся в регистры датчика постоянно. // Время обновления значения 84мксек. Данные в регистрах датчика будут обновляться примерно за тоже время, // которое потребуется для чтения одного регистра на скорости SCL 400кГц (1 такт = 2.5мксек) // 1 байт = 9 тактов (8 бит данных + подтв.)= 22.5мксек. // Получение данных: 1 байт адрес устройства, 1 байт адрес регистра, чтнение 2х байт = 90мксек. // 2 - (Энергосберегающий режим) Данные по запросу, ожидание 532мксек. const uint8_t a = 0b00111001; //1-й байт для нормального и энергосберегающего режима. const uint8_t b = 0b00111000; //1-й байт для быстрого режима. const uint8_t c = 0b10011111; //Нормальный режим (0) const uint8_t d = 0b10011000; //Энергосберегающий режим (2) const uint8_t e = 0b00000111; //Быстрый режим (1) switch (mode) { //Заполнение массива для передачи данных в конфигурационный регистр датчика //Нулевой элемент массива хранит размер массива. //Нормальный режим case 0: temp_array[2] = a; temp_array[3] = c; break; //Быстрый режим case 1: temp_array[2] = b; temp_array[3] = e; break; //Энергосберегающий режим case 2: temp_array[2] = a; temp_array[3] = d; break; } //Отправка заполненого массива в конфигурационный регистр TWI_Sensor_Write (adres, temp_array); } switch (data_type) { //Заполнение массива для передачи запроса на чтение данных //Нулевой элемент массива хранит размер массива. // Наряжение шины case 0: TWI_Sensor_Byte_Write (adres, 0x02, 0); break; // Напряжение шунта case 1: TWI_Sensor_Byte_Write (adres, 0x01, 0); break; //Мощность case 2: TWI_Sensor_Byte_Write (adres, 0x03, 0); break; //Ток case 3: TWI_Sensor_Byte_Write (adres, 0x04, 0); break; //Калибровочный регистр case 4: TWI_Sensor_Byte_Write (adres, 0x05, 0); break; //Конфигурационный регистр case 5: TWI_Sensor_Byte_Write (adres, 0x00, 0); break; } if (mode =! 2) //Для энергосберегающего режима нужно дождаться преобразований данных внутри датчика, псле запроса. //Для остальных режимов, производим чтение тех данных что уже есть в регистрах. { returned_data = TWI_Sensor_Read (adres, 16); } else { delayMicroseconds (540); returned_data = TWI_Sensor_Read (adres, 16); } mode_z = mode; // "Цена деления" одного бита в регистре напряжения шины - 4мВ. // 2 младших бита отвечают за флаг переполнения регистра и флаг отвечающий за готовность преобразованных данных // 3й зарезервирован. Все три необходимо сдвинуть. returned_data = data_type == 0? (returned_data >> 3) * 4 : returned_data >> 0; //Для режима чтения напряжения шунта и шины необходимо провести проверку знака. //Если первый бит "1" все значения необходимо инвертировать. returned_data = ((data_type == 1) && (returned_data & 0x8000)) ? (~returned_data) * -1 : returned_data * 1; return (returned_data); } //Чтение 1 или 2х байт регистра, которые последуют после отправки запроса на чтение. (X_bit - 8) - 1 байтовый регистр, (X_bit - 16) - 2х байтовый. uint16_t TWI_Sensor_Read (uint8_t adres, uint8_t X_bit) { uint16_t temp; // Регистр скорости TWBR = 8; // 0 - 500 кГц | 4 - 166 кГц Примечание из datasheet – значение TWBR должено быть не менее 10, если TWI работает в // 1 - 333 кГц | 6 - 125 кГц ведущем режиме. Если значение TWBR меньше 10, то ведущий может генерировать не- // 2 - 250 кГц | 7 - 111 кГц корректное состояние на линиях SDA и SCL. Проблема возникает при работе в ведущем // 3 - 200 кГц | 8 - 100 кГц режиме при передаче условий СТАРТ+ВЕДОМЫЙ_АДР+ ЧТЕНИЕ/ЗАПИСЬ ведомому. //ATmega 328 с барометром BMP180, и монитором тока INA219 отлично работает и на скорости 500кГц, то есть со значением TWBR = 0; //1. Условие старта. TWI_CONTROL_REGISTR = (1 << TWI_Start) | (1 << TWI_Int) | (1< timer) && ( (current_timer - timer) < timer ) ) { return (0); } } //Раскомментировать для контроля выхлопа регистра статуса, после каждого действия с аппаратным модулем TWI //Значения кодов см. в оригинальном datasheet на контроллер. // Serial.print ("Status registr "); // Serial.println(TWI_STATUS_REGISTR, HEX); }