Амперметр на ADS1110 (Arduino IDE | Atmega8L)

На АЦП 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 А, оцените погрешность измерения, после чего уточните калибровочный коэффициент.

 

Comments

    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

    1. Это просто множитель, для калибровки амперметра необходим эталонный источник тока (или точный измеритель тока)

      #define KALL_I 25887 — Калибровочный коэффициент для устранения погрешности измерения. Подайте на вход амперметра ток в от 8 до 9.5 А, оцените погрешность измерения, после чего уточните калибровочный коэффициент.

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

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