TDS感應器與ESP32的連接方式和程式碼

TDS的全名是Total Dissolved Solids,指的是水中溶解的所有固體物質的總量。這些溶解固體包括無機鹽類(如鈉、鈣、鎂、鉀、碳酸氫鹽、硫酸鹽和氯化物)和有機物質。TDS 的測量可以用百萬分率(ppm)作為單位來描述水中的礦物質或污染物濃度,來評估水質的純淨度。1 ppm 表示每升水中含有 1 毫克的溶解固體物質,飲用水的 TDS 通常在 300 ppm 以下,而RO水的 TDS 值則通常低於 10 ppm。

我的看法是TDS可以拿來做魚缸水質的監控,不同的生物有不同的需求,並不是愈低愈好。但它可以是一個飼主行為的參考,比如說TDS突然從穩定的區間迅速攀升,那也許飼主可以進行換水的動作。

TDS有筆型的檢測器可以使用,但既然ESP32都玩上癮了,沒有道理不把它做成即時監控。需要的材料以下,成本大約在500元內

  • ESP32開發板一片(我買的是DOIT ESP32 Devkit V1開發板)
  • MicroUSB線一條
  • Keyestudio TDS感應器總成一組(含探棒與訊號處理電路板)

Keyestudio TDS感應器輸出腳位有三個

  • 紅色是VCC,接ESP32的3.3V腳位。
  • 黃色是DATA,接ESP32 ADC1所屬的GPIO較佳(GPIO32~GPIO39)。
  • 黑色是GND,接ESP32的GND腳位。

ESP32上的GPIO總共有二組ADC,其中ADC2與Wi-Fi模組共用,當Wi-Fi啟用時會有訊號的干擾。一開始我將TDS的DATA接到ADC2的GPIO腳位,發現不管怎樣TDS都是0ppm,不斷修改程式做debug後才發現跟Wi-Fi模組有關,後來換去ADC1的GPIO腳位就沒事了。

我手上的ESP32,從賣家提供的圖片上來看,ADC1 GPIO引腳有32~36/39總共6個,其中GPIO36也稱為VP,GPIO39也稱為VN。這些GPIO在Wi-Fi模組啟用時不會與Wi-Fi模組衝突。ESP32的ADC2 GPIO引腳有2/4/12~15/25~27總共9個,如果要啟用Wi-Fi模組的話就盡量避開。

TDS探頭的保護套記得拆掉,露出探針後即可丟入水中。

Keyestudio原廠文件裡有給Arduino開發板的程式碼,但我用的是ESP32,GPIO定義、輸入電壓與ADC分辨率不同,需要修改一下。

在void loop()中主要分二個部分,TDS取樣以每40毫秒取樣一次並將值記錄在analogBuffer[]裡的第analogBufferIndex,當analogBufferIndex等於取樣數30後會重置。這個意思是analogBuffer[]會記錄最新30筆的TDS讀值。在TDS計算的部分,每800毫秒計算一次,計算時會取當下analogBuffer[]裡的30個值做平均。這樣做是為了避免單次取樣異常。

#define TDS_SENSOR_PIN 36 // 定義GPIO腳位為GPIO36
#define VREF 3.3 // ESP32輸入電壓為3.3V
#define SCOUNT 30 // 取樣數
int analogBuffer[SCOUNT];
int analogBufferIndex = 0;
float averageVoltage = 0;
float TDSValue = 0;
float temperature = 25; // 因沒有溫度計讀值,設定固定溫度為25做溫度補償用。

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

float lastTDSValue = -1; // 定義最後的TDS值為無效(-1)

void loop()
{
  // TDS取樣
  static unsigned long analogSampleTimepoint = 0;
  if(millis() - analogSampleTimepoint > 40)
  {
    analogSampleTimepoint = millis();
    analogBuffer[analogBufferIndex] = analogRead(TDS_SENSOR_PIN);
    analogBufferIndex++;
    if(analogBufferIndex == SCOUNT)
    { 
      analogBufferIndex = 0;
    }
  }   
  
  // TDS計算
  static unsigned long printTimepoint = 0;
  if(millis() - printTimepoint > 800)
  {
    printTimepoint = millis();
    float sum = 0;
    for(int i = 0; i < SCOUNT; i++)
    {
      sum += analogBuffer[i];
    }
    averageVoltage = (sum / SCOUNT) * (float)VREF / 4095; // 轉換為電壓值,ESP32的ADC解析度是12位(4095)。
    
    float compensationCoefficient = 1.0 + 0.02 * (temperature - 25.0); // 溫度補償公式,溫度設定在25度即無補償。
    float compensationVoltage = averageVoltage / compensationCoefficient; // 溫度補償後的電壓值
    
    TDSValue = (133.42 * compensationVoltage * compensationVoltage * compensationVoltage - 255.86 * compensationVoltage * compensationVoltage + 857.39 * compensationVoltage) * 0.5; // 將電壓值轉換為TDS值
    TDSValue = (int)TDSValue;
    
    if (TDSValue != lastTDSValue) // 如果TDS數值有更新,才會將結果Print出來。
    {
      lastTDSValue = TDSValue;
      Serial.print("TDS Value: ");
      Serial.print(TDSValue, 0);
      Serial.println(" ppm");
    }
  }
}

從Arduino的Serial Monitor可以看到TDS的值

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端