На АЦП ADS1110 можно собрать простой и точный амперметр постоянного тока. Диапазон измерения амперметра от 5 мА до 9.999 А с разрешением 1 мА. В качестве датчика тока используется манганиновая проволока диаметром не менее 2 мм с сопротивлением 0.01 Ом.
ADS1110 (более подробно) это прецизионный аналого-цифровой (A/D) преобразователь с дифференциальным входом и разрешением до 16 бит. Встроенный ИОН 2,048 В обеспечивает входной диапазон ±2,048 В. ADS1110 использует I2C интерфейс для связи с микроконтроллером. ADS1110 выполняет измерения со скоростью 15, 30, 60 или 240 выборок в секунду, содержит встроенный усилитель напряжения с коэффициентом 1, 2, 4, 8.
Падение напряжения на шунте при токе 10 А составляет 100 мВ, это напряжение подается на вход АЦП, диапазон измерения входа АЦП при множителе 8 от 0 до 256 мВ, поэтому теоретически амперметр может иметь предел измерения до 25 А.
Показания тока выводятся на четырех разрядный семисегментный индикатор TM1637.
В амперметре используется микроконтроллер Atmega8L с частотой кварцевого резонатора 4 МГц, но скетч программно совместим с Atmega168, Atmega328 (Arduino Nano).
Загрузка скетча в Atmega8L через Arduino IDE — http://rcl-radio.ru/?p=82486
#define ADDR 0x48 #define CPU_F 4000000 // Clock Speed // 16000000 >>> Arduino Nano #define SCL_F 50000 // // I2C Speed #define CLK 2// PD2 #define DIO 3// PD3 #define KALL_0 18 #define KALL_I 25887//(25600) long dig_sum,dig,u; void setup() { TWBR = (((CPU_F)/(SCL_F)-16 )/2) ; TWSR = 0; } void loop() { for(int i=0;i<10;i++){ dig_sum = dig_sum+read_u(ADDR,0b10001111);delay(20);} dig = dig_sum/10;dig_sum=0; u = dig*KALL_I/0x7FFF-KALL_0; if(u<5){u=0;} print_time(u,3,7); } int read_u(byte i2c_addr, byte i2c_reg){ TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // START while (!(TWCR & (1<<TWINT))); TWDR = i2c_addr << 1; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWDR = i2c_reg; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); // START while (!(TWCR & (1<<TWINT))); TWDR = (i2c_addr << 1) | 1; TWCR = (1<<TWINT) | (1<<TWEN); while (!(TWCR & (1<<TWINT))); TWCR=(1<<TWINT)|(1<<TWEN)|(1<<TWEA); while(~TWCR&(1<<TWINT)); int i2c_data0 = TWDR; TWCR = (1<<TWINT) | (1<<TWEN); while(~TWCR&(1<<TWINT)); int i2c_data1 = TWDR; TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWSTO); // СТОП int i2c_data = (i2c_data0<<8)+i2c_data1; return i2c_data; } void tm_dec(byte dig){ for(int i = 0; i < 8; i++) { DDRD |= (1 << CLK);del(); if (dig & 0x01) DDRD &= ~(1 << DIO); else DDRD |= (1 << DIO);del(); DDRD &= ~(1 << CLK);del(); dig = dig >> 1; } DDRD |= (1 << CLK); DDRD &= ~(1 << DIO);del(); DDRD &= ~(1 << CLK);del(); if (((PIND >> DIO) & 1) == 0) DDRD |= (1 << DIO);del(); DDRD |= (1 << CLK);del(); } void tm_stop(){ DDRD |= (1 << DIO);del(); DDRD &= ~(1 << CLK);del(); DDRD &= ~(1 << DIO);del(); } void tm_start(){ DDRD |= (1 << DIO);del(); } void print_time(int t, byte pd_t, int br){ tm_start();tm_dec(0b10001000 + br);//tm_stop();tm_start(); tm_dec(0x40);tm_stop();tm_start(); int data0 = t / 1000 % 10; int data1 = t / 100 % 10; int data2 = t / 10 % 10; int data3 = t % 10; for(byte n = 0; n < 4; n++){ int data; switch(n){ case 0: data = data0;break; case 1: data = data1;break; case 2: data = data2;break; case 3: data = data3;break; } switch(data){ // XGFEDCBA case 0: data = 0b00111111;break; // 0 case 1: data = 0b00000110;break; // 1 case 2: data = 0b01011011;break; // 2 case 3: data = 0b01001111;break; // 3 case 4: data = 0b01100110;break; // 4 case 5: data = 0b01101101;break; // 5 case 6: data = 0b01111101;break; // 6 case 7: data = 0b00000111;break; // 7 case 8: data = 0b01111111;break; // 8 case 9: data = 0b01101111;break; // 9 case 10: data = 0b00000000;break; // пусто case 11: data = 0b01000000;break; // - } if(n == 0){data0 = data;} if(n == 1){data1 = data;} if(n == 2){data2 = data;} if(n == 3){data3 = data;} } switch(pd_t){ case 1 : data2 = data2+0b10000000;break; case 2 : data1 = data1+0b10000000;break; case 3 : data0 = data0+0b10000000;break; } tm_dec(0xC0);tm_dec(data0);tm_dec(data1);tm_dec(data2);tm_dec(data3);tm_stop(); } void del(){delayMicroseconds(200);}
Амперметр нуждается в калибровке:
#define KALL_0 18 — При токе 0, на дисплее будут показания погрешности нуля, укажите это значение в переменной KALL_0.
#define KALL_I 25887 — Калибровочный коэффициент для устранения погрешности измерения. Подайте на вход амперметра ток в от 8 до 9.5 А, оцените погрешность измерения, после чего уточните калибровочный коэффициент.
Что нужно изменить в скетче, чтоб
Применить шунт 0.1 ом.
Сейчас множитель х8, нужно поменять множитель, так как падение на шунте 0,01 Ом при токе 10А будет 100 мВ, а на шунте 0,1 при 10 А 1 В, такой шунт применять не желательно, так при большом токе будет проседать выходное напряжение.
Но если есть желание, то измените строчку:
dig_sum = dig_sum+read_u(ADDR,0b10001111);delay(20);}
где последние два бита в байте 0b10001111 определяют множитель АЦП:
00 = 1
01 = 2
10 = 4
11 = 8
Изменять калибровочные значения KALL…?
Это просто множитель, для калибровки амперметра необходим эталонный источник тока (или точный измеритель тока)
#define KALL_I 25887 — Калибровочный коэффициент для устранения погрешности измерения. Подайте на вход амперметра ток в от 8 до 9.5 А, оцените погрешность измерения, после чего уточните калибровочный коэффициент.
Как изменить скетч под ардуино?
Ни как, он совместим с ардуино.
At_8 Arduino
PD2 = D2
PD3 = D3
PC4 = A4
PC5 = A5