Arduino с датчиком TDS (датчик качества воды)

В этом руководстве вы узнаете, как использовать TDS-метр (Total Dissolved Solids — общее количество растворённых твёрдых веществ) с платой Arduino. TDS-метр показывает общее количество растворённых твёрдых веществ, таких как соли, минералы и металлы, в растворе. Этот параметр можно использовать для оценки качества воды и сравнения воды из разных источников. Одно из основных применений TDS-метра — мониторинг качества воды в аквариуме.

Arduino с датчиком TDS - датчик качества воды Arduino IDE

Мы будем использовать TDS-метр от keystudio и покажем простой пример измерения TDS в единицах ppm с помощью Arduino IDE.

В этом руководстве мы рассмотрим следующие темы:

Знакомство с TDS-метром

TDS-метр измеряет количество общих растворённых твёрдых веществ, таких как соли, минералы и металлы, в воде. По мере увеличения количества растворённых веществ в воде возрастает её проводимость, что позволяет вычислить общее количество растворённых веществ в ppm (мг/л).

Датчик TDS (Total Dissolved Solids) от keystudio

Хотя это хороший индикатор для мониторинга качества воды, обратите внимание, что он не измеряет загрязняющие вещества в воде. Таким образом, вы не можете полагаться исключительно на этот индикатор для определения пригодности воды для употребления.

TDS-метр может быть полезен для мониторинга качества воды во многих приложениях, таких как бассейны, аквариумы, рыбные резервуары, гидропоника, водоочистители и т.д.

В этом руководстве мы будем использовать TDS-метр от keystudio, который поставляется с интерфейсным модулем и электродным зондом (см. изображение выше).

Для получения дополнительной информации о TDS-метре мы рекомендуем ознакомиться с официальной документацией.

Характеристики и спецификации

Данное руководство относится к TDS Meter V1.0 от keystudio. Вот параметры датчика:

TDS-метр:

  • Входное напряжение: DC 3.3 ~ 5.5 В

  • Выходное напряжение: 0 ~ 2.3 В

  • Рабочий ток: 3 ~ 6 мА

  • Диапазон измерения TDS: 0 ~ 1000 ppm

  • Точность измерения TDS: ± 10% F.S. (25 °C)

  • Интерфейс модуля: XH2.54-3P

  • Интерфейс электрода: XH2.54-2P

TDS зонд:

  • Количество игл: 2

  • Общая длина: 60 см

  • Интерфейс подключения: XH2.54-2P

  • Цвет: белый

  • Водонепроницаемый зонд

Где купить датчик TDS?

Вы можете найти датчик TDS по лучшей цене:

Подключение TDS-метра к Arduino

TDS-метр выдает аналоговый сигнал, который можно измерить с помощью аналоговых выводов Arduino (A0–A5).

Подключите датчик согласно следующей таблице:

Датчик TDS

Arduino

GND

GND

VCC

3.3V

Data

A0 (или любой другой аналоговый вывод Arduino)

Считывание TDS (качества воды) с Arduino – Код

Как мы упоминали ранее, датчик выдаёт аналоговый сигнал, который можно преобразовать в TDS в ppm. Мы используем код, предоставленный документацией датчика, с некоторыми модификациями.

Arduino с датчиком TDS для измерения качества воды

Для получения более точных результатов вам, вероятно, потребуется откалибровать датчик с помощью раствора с известным значением TDS. Однако это может не потребоваться, если вас интересует не конкретное значение, а качественная оценка TDS.

Загрузите следующий код на вашу плату Arduino.

// Original source code: https://wiki.keyestudio.com/KS0429_keyestudio_TDS_Meter_V1.0#Test_Code
// Project details: https://RandomNerdTutorials.com/arduino-tds-water-quality-sensor/

#define TdsSensorPin A0
#define VREF 5.0              // analog reference voltage(Volt) of the ADC
#define SCOUNT  30            // sum of sample point

int analogBuffer[SCOUNT];     // store the analog value in the array, read from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0;
int copyIndex = 0;

float averageVoltage = 0;
float tdsValue = 0;
float temperature = 16;       // current temperature for compensation

// median filtering algorithm
int getMedianNum(int bArray[], int iFilterLen){
  int bTab[iFilterLen];
  for (byte i = 0; i<iFilterLen; i++)
  bTab[i] = bArray[i];
  int i, j, bTemp;
  for (j = 0; j < iFilterLen - 1; j++) {
    for (i = 0; i < iFilterLen - j - 1; i++) {
      if (bTab[i] > bTab[i + 1]) {
        bTemp = bTab[i];
        bTab[i] = bTab[i + 1];
        bTab[i + 1] = bTemp;
      }
    }
  }
  if ((iFilterLen & 1) > 0){
    bTemp = bTab[(iFilterLen - 1) / 2];
  }
  else {
    bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
  }
  return bTemp;
}

void setup(){
  Serial.begin(115200);
  pinMode(TdsSensorPin,INPUT);
}

void loop(){
  static unsigned long analogSampleTimepoint = millis();
  if(millis()-analogSampleTimepoint > 40U){     //every 40 milliseconds,read the analog value from the ADC
    analogSampleTimepoint = millis();
    analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin);    //read the analog value and store into the buffer
    analogBufferIndex++;
    if(analogBufferIndex == SCOUNT){
      analogBufferIndex = 0;
    }
  }

  static unsigned long printTimepoint = millis();
  if(millis()-printTimepoint > 800U){
    printTimepoint = millis();
    for(copyIndex=0; copyIndex<SCOUNT; copyIndex++){
      analogBufferTemp[copyIndex] = analogBuffer[copyIndex];

      // read the analog value more stable by the median filtering algorithm, and convert to voltage value
      averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 1024.0;

      //temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
      float compensationCoefficient = 1.0+0.02*(temperature-25.0);
      //temperature compensation
      float compensationVoltage=averageVoltage/compensationCoefficient;

      //convert voltage value to tds value
      tdsValue=(133.42*compensationVoltage*compensationVoltage*compensationVoltage - 255.86*compensationVoltage*compensationVoltage + 857.39*compensationVoltage)*0.5;

      //Serial.print("voltage:");
      //Serial.print(averageVoltage,2);
      //Serial.print("V   ");
      Serial.print("TDS Value:");
      Serial.print(tdsValue,0);
      Serial.println("ppm");
    }
  }
}

Просмотреть исходный код

Как работает код

Давайте кратко рассмотрим код. Вы также можете сразу перейти к разделу Демонстрация.

Переменная TdsSensorPin сохраняет GPIO, с которого вы хотите получать показания. У ESP8266 есть только один аналоговый вывод — A0.

#define TdsSensorPin A0

Затем укажите аналоговое опорное напряжение для АЦП. Для Arduino это 5 В.

#define VREF 5.0            // analog reference voltage(Volt) of the ADC

Перед получением значения измерения мы применим алгоритм медианной фильтрации для получения более стабильного значения. Переменная SCOUNT указывает количество выборок, которые мы отфильтруем перед получением фактического значения.

#define SCOUNT  30            // sum of sample point

Затем нам нужны массивы для хранения показаний, а также индексные переменные, позволяющие перемещаться по массивам.

int analogBuffer[SCOUNT];     // store the analog value in the array, read from ADC
int analogBufferTemp[SCOUNT];
int analogBufferIndex = 0;
int copyIndex = 0;

Инициализируйте переменные averageVoltage и tdsValue как переменные с плавающей точкой.

float averageVoltage = 0;
float tdsValue = 0;

Переменная temperature сохраняет текущее значение температуры. Температура влияет на показания, поэтому существует алгоритм, компенсирующий колебания температуры. В этом примере эталонная температура составляет 25 °C, но вы можете изменить её в зависимости от вашей среды. Для более точных результатов вы можете добавить датчик температуры и получать фактическую температуру в момент считывания показаний датчика.

float temperature = 25;       // current temperature for compensation

Следующая функция будет использоваться для получения стабильного значения TDS из массива показаний.

// median filtering algorithm
int getMedianNum(int bArray[], int iFilterLen){
  int bTab[iFilterLen];
  for (byte i = 0; i<iFilterLen; i++)
  bTab[i] = bArray[i];
  int i, j, bTemp;
  for (j = 0; j < iFilterLen - 1; j++) {
    for (i = 0; i < iFilterLen - j - 1; i++) {
      if (bTab[i] > bTab[i + 1]) {
        bTemp = bTab[i];
        bTab[i] = bTab[i + 1];
        bTab[i + 1] = bTemp;
      }
    }
  }
  if ((iFilterLen & 1) > 0){
    bTemp = bTab[(iFilterLen - 1) / 2];
  }
  else {
    bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
  }
  return bTemp;
}

В setup() инициализируйте Serial Monitor на скорости 115200 бод.

Serial.begin(115200);

Установите вывод датчика TDS как вход.

pinMode(TdsSensorPin,INPUT);

В loop() получайте новые показания TDS каждые 40 миллисекунд и сохраняйте их в буфере:

static unsigned long analogSampleTimepoint = millis();
if(millis()-analogSampleTimepoint > 40U){     //every 40 milliseconds,read the analog value from the ADC
  analogSampleTimepoint = millis();
  analogBuffer[analogBufferIndex] = analogRead(TdsSensorPin);    //read the analog value and store into the buffer
  analogBufferIndex++;
  if(analogBufferIndex == SCOUNT){
    analogBufferIndex = 0;
  }
}

Затем каждые 800 миллисекунд он получает последние показания и вычисляет среднее напряжение, используя ранее созданный алгоритм фильтрации:

static unsigned long printTimepoint = millis();
if(millis()-printTimepoint > 800U){
  printTimepoint = millis();
  for(copyIndex=0; copyIndex<SCOUNT; copyIndex++){
    analogBufferTemp[copyIndex] = analogBuffer[copyIndex];

    // read the analog value more stable by the median filtering algorithm, and convert to voltage value
    averageVoltage = getMedianNum(analogBufferTemp,SCOUNT) * (float)VREF / 1024.0;

Затем он вычисляет коэффициент температурной компенсации и рассчитывает значение TDS с учётом этого значения:

//temperature compensation formula: fFinalResult(25^C) = fFinalResult(current)/(1.0+0.02*(fTP-25.0));
float compensationCoefficient = 1.0+0.02*(temperature-25.0);
//temperature compensation
float compensationVoltage=averageVoltage/compensationCoefficient;

//convert voltage value to tds value
tdsValue=(133.42*compensationVoltage*compensationVoltage*compensationVoltage- 255.86*compensationVoltage*compensationVoltage + 857.39*compensationVoltage)*0.5;

Наконец, он выводит значение TDS в ppm:

Serial.print("TDS Value:");
Serial.print(tdsValue,0);
Serial.println("ppm");

Демонстрация

После копирования кода в Arduino IDE загрузите его на вашу плату. Не забудьте выбрать правильную плату в Tools > Board и правильный COM-порт в Tools > Port.

После загрузки откройте Serial Monitor на скорости 115200 бод.

Тестирование TDS-метра с ESP32 ESP8266 Arduino

Если зонд не погружён в жидкость, будет отображаться значение приблизительно 0. Погрузите зонд в раствор, чтобы проверить его TDS. Вы можете попробовать с водопроводной водой и добавить немного соли, чтобы увидеть, как значения увеличиваются.

TDS датчик Arduino IDE Serial Monitor демонстрация

Я измерил значение TDS водопроводной воды в своём доме и получил значение около 100 ppm, что является хорошим показателем для питьевой воды.

Я также протестировал чай, и значение TDS увеличилось примерно до 230 ppm, что кажется разумным значением.

Наконец, я также измерил значение TDS бутилированной воды и получил значение около 25 ppm (такое же значение при использовании ESP8266).

Я также делюсь здесь результатами одного из наших читателей, чтобы вы могли сравнить:

  • водопроводная вода на ранчо: 125 ppm

  • пиво Corona: 384 ppm

  • уксус: 610 ppm

  • джин-тоник: 43 ppm

  • очищенная вода: 0 ppm

Заключение

TDS-метр может измерять общее количество растворённых твёрдых веществ в растворе. Он может использоваться как индикатор качества воды и позволяет характеризовать воду. Метр возвращает значение TDS в ppm (parts per million — миллионные доли, мг/л). Значение TDS имеет множество применений, но его нельзя использовать само по себе для определения, пригодна ли вода для питья или нет.

Отличное применение этого типа датчика — монитор качества воды в аквариуме. Вы можете использовать этот датчик вместе с водонепроницаемым датчиком температуры DS18B20 для мониторинга вашего аквариума, например.

У нас есть руководства по другим популярным датчикам для платы Arduino, которые могут вам понравиться: