AD7793 миллиомметр (Arduino)

AD7793 — малошумящий 24-разрядный сигма-дельта АЦП с тремя дифференциальными аналоговыми входами. АЦП AD7793 предназначен для высокоточного измерения постоянного напряжения, может применяться для измерения напряжения термопар и других датчиков с выходным напряжением в несколько единиц или десятков мВ.

Перед прочтением статьи рекомендую ознакомится с тремя первыми статьями про АЦП AD7793:

На базе AD7793 с использованием Arduino Nano можно собрать миллиомметр с диапазоном измерения от 0,0000 до 32,000 Ом.

Схема миллиомметра

Вход АЦП сконфигурирован как несимметричный вход, предусилитель АЦП имеет коэффициент усиления равный 1, частота опроса 4,17 Гц.

Для точного измерения необходимо иметь эталонное сопротивление 100 Ом (манганин) через которое подается ток на измеряемое сопротивление, от точности эталонного сопротивления зависит точность прибора. Если нет возможности очень точно изготовить (намотать из манганиновой проволоки) эталонное сопротивление, то откалибровать прибор можно при помощи другого эталонного сопротивления 1…30 Ом с классом точности не менее 0.02 %.

Для упрощения конструкции прибора напряжение на эталонное сопротивление 100 Ом подается от источника питания +5 В Arduino, которое также является аналоговым напряжением питания АЦП AD7793, а так как в АЦП имеется возможность контроля этого напряжения, то оно становится опорным, так как перед каждым замером сопротивления производится измерения аналогового напряжения питания АЦП которое также подается на эталонное сопротивление.

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>   // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей
 
// AD7793 DVDD = 5V | AVDD = 5V | R = 0...32 Om
#define SCLK   2
#define CS     3
#define DIN    4
#define DOUT   5
 
#define AVDD_MONITOR 0b111 // CONF
#define TEMP_SENSOR  0b110 // CONF
#define CH1          0b000 // CONF
#define CH2          0b001 // CONF
#define CH3          0b011 // CONF
#define BIPOLAR      0b00000000 // CONF
#define UNIPOLAR     0b00010000 // CONF
#define GAIN_1       0b000      // CONF
#define GAIN_2       0b001      // CONF
#define GAIN_4       0b010      // CONF
#define GAIN_8       0b011      // CONF
#define GAIN_16      0b100      // CONF
#define GAIN_32      0b101      // CONF
#define GAIN_64      0b110      // CONF
#define GAIN_128     0b111      // CONF
 
#define F_ADC_500    0b0001 // MODE 
#define F_ADC_250    0b0010 // MODE 
#define F_ADC_125    0b0011 // MODE 
#define F_ADC_62_5   0b0100 // MODE 
#define F_ADC_50_0   0b0101 // MODE 
#define F_ADC_39_2   0b0110 // MODE
#define F_ADC_33_3   0b0111 // MODE 
#define F_ADC_19_6   0b1000 // MODE 
#define F_ADC_16_7   0b1001 // MODE 
#define F_ADC_12_5   0b1011 // MODE 
#define F_ADC_10_0   0b1100 // MODE 
#define F_ADC_8_33   0b1101 // MODE 
#define F_ADC_6_25   0b1110 // MODE  
#define F_ADC_4_17   0b1111 // MODE   
 
#define R_100        99.969  
#define K_0          0.0015
#define K_AVDD       6.065
 
 byte v1[8] = {0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07};
 byte v2[8] = {0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00};      
 byte v3[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F};
 byte v4[8] = {0x1F,0x1F,0x00,0x00,0x00,0x00,0x1F,0x1F};
 byte v5[8] = {0x1C,0x1C,0x00,0x00,0x00,0x00,0x1C,0x1C};
 byte v6[8] = {0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C};
 byte v7[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07};
 byte v8[8] = {0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00};
 byte d1,d2,d3,d4,d5,d6,e1,e2,e3,a[6],x;
 
 
void setup(){ 
  Serial.begin(9600);
  pinMode(SCLK,OUTPUT);pinMode(CS,OUTPUT);pinMode(DIN,OUTPUT);pinMode(DOUT,INPUT);
  digitalWrite(SCLK,HIGH);digitalWrite(CS,HIGH);digitalWrite(DIN,HIGH);
  delay(100);
  reset();
  write_byte(0x08,(0x20<<8)|F_ADC_4_17, 16);// MODE REGISTER
  write_byte(0x10,((UNIPOLAR|GAIN_1)<<8)|0x90|AVDD_MONITOR, 16); // CONFIGURATION REGISTER 
  write_byte(0x08,(0xC0<<8)|0x0A, 16);delay(100);// MODE REGISTER System Zero-Scale Calibration
  write_byte(0x08,(0xE0<<8)|0x0A, 16);delay(100);// MODE REGISTER System Full-Scale Calibration
  Serial.print("Stat ");Serial.println(read_byte(0x40,8),BIN);// STATUS REGISTER
  Serial.print("ID   ");Serial.println(read_byte(0x60,8),BIN);// ID REGISTER 
  Serial.print("Ofst ");Serial.println(read_byte(0x70,24));//OFFSET REGISTER
  Serial.print("ful  ");Serial.println(read_byte(0x78,24));//OFULL-SCALE REGISTER 
  write_byte(0x28,0x00, 8);// IO REGISTER 
  lcd.init();lcd.backlight();
  lcd.createChar(1, v1);lcd.createChar(2, v2);lcd.createChar(3, v3);lcd.createChar(4, v4);
  lcd.createChar(5, v5);lcd.createChar(6, v6);lcd.createChar(7, v7);lcd.createChar(8, v8);
  lcd.setCursor(5, 0);lcd.print(F("AD7793"));
  delay(1000);lcd.clear();
}
 
void loop(){ 
// READ ADC //////////////////////////////////////////////////////////////////  
  write_byte(0x08,(0x20<<8)|F_ADC_4_17, 16);// MODE REGISTER
  write_byte(0x10,((UNIPOLAR|GAIN_1)<<8)|0x90|CH2, 16); // CONFIGURATION REGISTER 
  long adc = read_byte(0x58,24);
  float u = 1170.00/0xFFFFFF*adc/1;
  Serial.print("DATA:  ");Serial.println(adc);
  delay(1);
  write_byte(0x08,(0x20<<8)|F_ADC_4_17, 16);// MODE REGISTER
  write_byte(0x10,((UNIPOLAR|GAIN_1)<<8)|0x90|AVDD_MONITOR, 16); // CONFIGURATION REGISTER
  adc = read_byte(0x58,24);
  float u_100 = 1170.00/0xFFFFFF*adc*K_AVDD;
  delay(1);  
  float r = ((R_100*u)/(u_100-u))-K_0;
  long number = r*10000;
  Serial.print("R_NUM: ");Serial.println(number);
  Serial.print("AVDD:  ");Serial.println(u_100);
  Serial.println();
/// R < 10 
if(r<10){
     a[0]=number/10000;
     a[1]=number/1000%10;
     a[2]=number/100%10;
     a[3]=number/10%10;
     a[4]=number%10;
   for(x=0;x<5;x++){
    switch(x){
        case 0: e1=0;e2=1,e3=2;break;
        case 1: e1=4,e2=5,e3=6;break;
        case 2: e1=7,e2=8,e3=9;break;
        case 3: e1=10,e2=11,e3=12;break;
        case 4: e1=13,e2=14,e3=15;break;
   }digit();}
   lcd.setCursor(3,1);lcd.print(".");lcd.setCursor(3,0);lcd.print(" ");
}
/// R > 10 
if(r>=10){
  if(number>319999){number=319999;lcd.setCursor(6,0);lcd.print("*");}
  else{lcd.setCursor(6,0);lcd.print(" ");}
     a[0]=number/100000;
     a[1]=number/10000%10;
     a[2]=number/1000%10;
     a[3]=number/100%10;
     a[4]=number/10%10;
   for(x=0;x<5;x++){
    switch(x){
        case 0: e1=0;e2=1,e3=2;break;
        case 1: e1=3,e2=4,e3=5;break;
        case 2: e1=7,e2=8,e3=9;break;
        case 3: e1=10,e2=11,e3=12;break;
        case 4: e1=13,e2=14,e3=15;break;
   }digit();}
   lcd.setCursor(6,1);lcd.print(".");
}
}
 
void digit(){
  switch(a[x]){
    case 0: d1=1,d2=8,d3=6,d4=1,d5=3,d6=6;break;
    case 1: d1=32,d2=2,d3=6,d4=32,d5=32,d6=6;break;
    case 2: d1=2,d2=8,d3=6,d4=1,d5=4,d6=5;break;
    case 3: d1=2,d2=4,d3=6,d4=7,d5=3,d6=6;break;
    case 4: d1=1,d2=3,d3=6,d4=32,d5=32,d6=6;break;
    case 5: d1=1,d2=4,d3=5,d4=7,d5=3,d6=6;break;
    case 6: d1=1,d2=4,d3=5,d4=1,d5=3,d6=6;break;
    case 7: d1=1,d2=8,d3=6,d4=32,d5=32,d6=6;break;
    case 8: d1=1,d2=4,d3=6,d4=1,d5=3,d6=6;break;
    case 9: d1=1,d2=4,d3=6,d4=7,d5=3,d6=6;break;
    case 10:d1=150,d2=150,d3=150,d4=150,d5=150,d6=150;break;
    }
lcd.setCursor(e1,0);lcd.write((uint8_t)d1);
lcd.setCursor(e2,0);lcd.write((uint8_t)d2);lcd.setCursor(e3,0);lcd.write((uint8_t)d3);lcd.setCursor(e1,1);
lcd.write((uint8_t)d4);lcd.setCursor(e2,1);lcd.write((uint8_t)d5);lcd.setCursor(e3,1);lcd.write((uint8_t)d6);}
 
void write_byte(byte reg, long data, int bit_){
     digitalWrite(CS,LOW); 
  for(int i = 7; i >= 0; i--){
     digitalWrite(SCLK,LOW);
     digitalWrite(DIN, (reg >> i) & 1);
     digitalWrite(SCLK,HIGH);
     }
  for(int i = bit_-1; i >= 0; i--){
     digitalWrite(SCLK,LOW);
     digitalWrite(DIN, (data >> i) & 1);
     digitalWrite(SCLK,HIGH); 
     }
     digitalWrite(CS,HIGH);
     }
 
 
  long read_byte(byte reg, int bit_){
     digitalWrite(CS,LOW);
  while(digitalRead(DOUT)!=LOW); 
  for(int i = 7; i >= 0; i--){
     digitalWrite(SCLK,LOW); 
     digitalWrite(DIN, (reg >> i) & 1);
     digitalWrite(SCLK,HIGH);
     }
  while(digitalRead(DOUT)!=LOW); 
  long data_out=0;
  long dat;
  for(int i = bit_-1; i >= 0; i--){
     digitalWrite(SCLK,LOW);
     digitalWrite(SCLK,HIGH);
     dat = digitalRead(DOUT);
     data_out |= (dat<<i); 
     }
     digitalWrite(CS,HIGH);
     return data_out; 
  }
 
void reset(){
     digitalWrite(CS,LOW);   
  for(int i = 31; i >= 0; i--){
     digitalWrite(SCLK,LOW);
     digitalWrite(DIN, HIGH);
     digitalWrite(SCLK,HIGH);
     }
     digitalWrite(CS,HIGH);
  }

Для получения большой точности при измерении сопротивлений миллиомметр нуждается в калибровке:

#define R_100 99.969

#define K_0 0.0015

#define K_AVDD 6.065

K_AVDD — калибровочный коэффициент напряжения подаваемого на эталонное сопротивление, так как оно является аналоговым напряжением питания АЦП и имеется возможность его измерять, то необходимо очень точно произвести калибровку результата его измерения. Для этого измерьте напряжение подаваемое на эталонное сопротивление, откройте монитор порта и сравните его с измеренным значением.

AVDD — напряжением аналогового питания АЦП (выделено красным)

Измените K_AVDD таким образом, чтобы напряжение подаваемое на эталонное сопротивление соответствовало напряжению AVDD в мониторе порта.

R_100 — точное значение эталонного сопротивления.

K_0 — калибровка нуля. Замкните вход омметра, если показания не равны нулю, то укажите в K_0 погрешность нуля.

Результаты измерений

0 Ом

R0 магазина сопротивлений МСР-60М (0,02%), это значение необходимо вычитать в последующих измерениях

0,01 Ом (измеренное значение 0,009 Ом)

0,05 Ом (измеренное значение 0,0541 Ом)

0,1 Ом (измеренное значение 0,0997 Ом)

0,5 Ом (измеренное значение 0,5047 Ом)

1,0 Ом (измеренное значение 1,0001 Ом)

5,0 Ом (измеренное значение 4,9999 Ом)

10,0 Ом (измеренное значение 9,997 Ом)

15,0 Ом (измеренное значение 14,998 Ом)

20,0 Ом (измеренное значение 19,995 Ом)

25,0 Ом (измеренное значение 24,995 Ом)

30,0 Ом (измеренное значение 29,996 Ом)

Р310 катушка электрического сопротивления (мера) 0,001 Ом

Форум — http://forum.rcl-radio.ru/viewtopic.php?pid=6549#p6549

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

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