模拟电导率计V2

概述

技术指标

电极尺寸图

电导率计的使用(初级)

连接图

使用步骤

注意:

(1)将各个设备按照图示方式连接,即:电导率电极连接到EC Meter电路板的BNC接口,然后用模拟连接线,将EC Meter电路板连接到Arduino主控器的模拟口1。然后把防水型DS18B20温度传感器连接到可插拔传感器转接器的接线端子,然后用数字连接线,连接到Arduino主控器的数字口2。对Arduino主控器供电后,可以看到EC Meter电路板的蓝色指示灯变亮。

(2)对Arduino主控器烧写样例代码。

(3)打开Arduino IDE的串口监视器,此时能输出一些参数,如电压值、温度值,并且提示没有溶液。

<File:20140408120155.jpg>

(4)将电导率电极和温度传感器插入校准溶液中,可以测量该溶液的电导率值。搅拌溶液,待示数稳定。如果示数接近标准溶液瓶身所标的值,则可以投入使用。

以测试电导率为1413us/cm的电导率溶液为例:

<File:20140408120506.jpg>

样例代码

请先下载单总线库。下载样例代码后,打开Arduino IDE的串口监视器,即可看到结果。

    #include <OneWire.h>

    #define StartConvert 0
    #define ReadTemperature 1

    const byte numReadings = 20;     //the number of sample times
    byte ECsensorPin = A1;  //EC Meter analog output,pin on analog 1
    byte DS18B20_Pin = 2; //DS18B20 signal, pin on digital 2
    unsigned int AnalogSampleInterval=25,printInterval=700,tempSampleInterval=850;  //analog sample interval;serial print interval;temperature sample interval
    unsigned int readings[numReadings];      // the readings from the analog input
    byte index = 0;                  // the index of the current reading
    unsigned long AnalogValueTotal = 0;                  // the running total
    unsigned int AnalogAverage = 0,averageVoltage=0;                // the average
    unsigned long AnalogSampleTime,printTime,tempSampleTime;
    float temperature,ECcurrent;

    //Temperature chip i/o
    OneWire ds(DS18B20_Pin);  // on digital pin 2

    void setup() {
     // initialize serial communication with computer:
      Serial.begin(115200);
      // initialize all the readings to 0:
      for (byte thisReading = 0; thisReading < numReadings; thisReading++)
        readings[thisReading] = 0;
      TempProcess(StartConvert);   //let the DS18B20 start the convert
      AnalogSampleTime=millis();
      printTime=millis();
      tempSampleTime=millis();
    }

    void loop() {
      /*
       Every once in a while,sample the analog value and calculate the average.
      */
      if(millis()-AnalogSampleTime>=AnalogSampleInterval)
      {
        AnalogSampleTime=millis();
         // subtract the last reading:
        AnalogValueTotal = AnalogValueTotal - readings[index];
        // read from the sensor:
        readings[index] = analogRead(ECsensorPin);
        // add the reading to the total:
        AnalogValueTotal = AnalogValueTotal + readings[index];
        // advance to the next position in the array:
        index = index + 1;
        // if we're at the end of the array...
        if (index >= numReadings)
        // ...wrap around to the beginning:
        index = 0;
        // calculate the average:
        AnalogAverage = AnalogValueTotal / numReadings;
      }
      /*
       Every once in a while,MCU read the temperature from the DS18B20 and then let the DS18B20 start the convert.
       Attention:The interval between start the convert and read the temperature should be greater than 750 millisecond,or the temperature is not accurate!
      */
       if(millis()-tempSampleTime>=tempSampleInterval)
      {
        tempSampleTime=millis();
        temperature = TempProcess(ReadTemperature);  // read the current temperature from the  DS18B20
        TempProcess(StartConvert);                   //after the reading,start the convert for next reading
      }
       /*
       Every once in a while,print the information on the serial monitor.
      */
      if(millis()-printTime>=printInterval)
      {
        printTime=millis();
        averageVoltage=AnalogAverage*(float)5000/1024;
        Serial.print("Analog value:");
        Serial.print(AnalogAverage);   //analog average,from 0 to 1023
        Serial.print("    Voltage:");
        Serial.print(averageVoltage);  //millivolt average,from 0mv to 4995mV
        Serial.print("mV    ");
        Serial.print("temp:");
        Serial.print(temperature);    //current temperature
        Serial.print("^C     EC:");

        float TempCoefficient=1.0+0.0185*(temperature-25.0);    //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.0185*(fTP-25.0));
        float CoefficientVolatge=(float)averageVoltage/TempCoefficient;
        if(CoefficientVolatge<150)Serial.println("No solution!");   //25^C 1413us/cm<-->about 216mv  if the voltage(compensate)<150,that is <1ms/cm,out of the range
        else if(CoefficientVolatge>3300)Serial.println("Out of the range!");  //>20ms/cm,out of the range
        else
        {
          if(CoefficientVolatge<=448)ECcurrent=6.84*CoefficientVolatge-64.32;   //1ms/cm<EC<=3ms/cm
          else if(CoefficientVolatge<=1457)ECcurrent=6.98*CoefficientVolatge-127;  //3ms/cm<EC<=10ms/cm
          else ECcurrent=5.3*CoefficientVolatge+2278;                           //10ms/cm<EC<20ms/cm
          ECcurrent/=1000;    //convert us/cm to ms/cm
          Serial.print(ECcurrent,2);  //two decimal
          Serial.println("ms/cm");
        }
      }

    }
    /*
    ch=0,let the DS18B20 start the convert;ch=1,MCU read the current temperature from the DS18B20.
    */
    float TempProcess(bool ch)
    {
      //returns the temperature from one DS18B20 in DEG Celsius
      static byte data[12];
      static byte addr[8];
      static float TemperatureSum;
      if(!ch){
              if ( !ds.search(addr)) {
                  Serial.println("no more sensors on chain, reset search!");
                  ds.reset_search();
                  return 0;
              }
              if ( OneWire::crc8( addr, 7) != addr[7]) {
                  Serial.println("CRC is not valid!");
                  return 0;
              }
              if ( addr[0] != 0x10 && addr[0] != 0x28) {
                  Serial.print("Device is not recognized!");
                  return 0;
              }
              ds.reset();
              ds.select(addr);
              ds.write(0x44,1); // start conversion, with parasite power on at the end
      }
      else{
              byte present = ds.reset();
              ds.select(addr);
              ds.write(0xBE); // Read Scratchpad
              for (int i = 0; i < 9; i++) { // we need 9 bytes
                data[i] = ds.read();
              }
              ds.reset_search();
              byte MSB = data[1];
              byte LSB = data[0];
              float tempRead = ((MSB << 8) | LSB); //using two's compliment
              TemperatureSum = tempRead / 16;
        }
              return TemperatureSum;
    }

电导率计的使用(高级)

采用以上的步骤,你可以轻松测量范围在1ms/cm到20ms/cm之间的溶液电导率值了,但每个电极的电导池常数不一样,因此按照上面的方法获得的结果,精度不会很高。下面将介绍电路的工作原理和校准方案,提高测量精度。这也是仪器分析常用的方法之一。

测量原理

请首先打开原理图,找到U3B芯片。这是一个反相比例放大电路,传递函数为:Vo=R10/R*Vi,其中R10是反馈电阻,在图中,其阻值为820欧姆;R是电导电极的电阻,当电导电极插在溶液中,就会出现和溶液电导率相关的电阻值。R10/R称为放大倍数,当R改变时,放大倍数会改变,对输入的电压Vi进行放大输出的Vo会发生变化。反相比例放大电路后面是绝对值电路,传递函数为:Vo=|Vi|。ADOUT就是Arduino模拟采样引脚,因此,测量原理就是电导电极插进不同的溶液中会有不同的电阻值,不同的电阻值会让反相比例放大电路形成不同的放大倍数,然后通过Arduino采样电压值的大小,从而计算出该溶液的电导率值。 下面分析下校准原理。 电阻定义:

电阻定义.jpg

式中,ρ为电阻率;L为电阻体长度;A为电阻体截面。 在电导电极中,L表示的是两个导电片之间的间距,A为导电片的面积。 电导率的定义:

电导率定义.jpg

根据上面两个式子,可得:

关系式.jpg

式中,1/R称为电导G;L/A称为电导池常数Q。 测量电路的传递函数:

电路传递函数.jpg

式中,R为电导电极的电阻。 结合以上的式子,可得:

最终结果.jpg

式中,Q为电导池常数,是一个常量,每根电极的电极常数都不同。R10在电路中阻值为820欧姆。|Vin|也是一个常量,取决于信号发生电路,大概200mv左右。因此,电导率和输出电压Vout成线性关系。

校准方案

根据上述推导的线性关系,可以以电压值Vout为x轴,电导率为y轴,建立坐标系。使用校准液1413us/cm和12.88ms/cm,结合采样得到的电压值,建立直线的解析式。这条直线适合你当前所用的电极,根据这条直线的解析式,就可以得出1ms/cm到20ms/cm之间的电导率值。建议建立这条直线时,使校准液温度维持在25℃。 影响电导率的另一个重要因素是温度,因此需要温度补偿,把非25℃的电导率值换算到25℃的值。公式是:Gt = Gtcal{1 + α(T-Tcal)} 其中:Gt为某一温度(°C)下的电导率,Gtcal为标准温度(°C)下的电导率,Tcal为温度修正值,一般为25℃,α为溶液的温度系数,一般取0.0185。 由于我们按照建立直线的方法,电导率和输出电压成线性关系,因此可以把非25℃的电压值进行补偿,转换到25℃的电压值,再带入直线解析式求电导率值。 样例代码是按照这个思路来的,取1.414ms/cm、3ms/cm、10ms/cm、12.88ms/cm建立分段直线解析式,以获得更好的线性关系。 电导率电极使用一段时间后,电导池常数会发生变化。因此,可以按照以上方法重新建立新的直线解析式或者使用一点校准法:测得的电导率值除以标准溶液的电导率值得到修正因子,再把这个修正因子乘到原先的直线解析式中即可,相当于改变了直线的斜率。

注意事项

相关文档