在ESP32上實作XKC-Y25-V非接觸式液體偵測器

XKC-Y25-V是由深圳信可成科技有限公司生產的非接觸式液體偵測器,適用於液位偵測。它採用電容感應技術,能透過容器檢測液體,而不直接接觸液體,適合各種密封容器或不能接觸液體的場合,如強酸、強鹼、醫療和食品領域。

只需將偵測器本體貼在容器外側即可偵測液位。XKC-Y25-V上有紅色指示燈,亮起時表示偵測到液體,反之則否。

在水族應用上,尤其是海水缸中,接觸式金屬偵測器並不適用,原因是金屬會因海水腐蝕而影響耐用性,並且金屬離子(例如銅)釋放到水中會對海水缸中的無脊椎動物和珊瑚造成傷害。因此,我在之前的海水缸中使用塑料浮球開關進行水位偵測,類似像這種。

    或是這種,這種浮球開關外有個罩子,水面波動造成的影響會比較小。不過好像沒在台灣看過,我是從國外買回來的,有需要的話拿個一寸管跟管帽土砲一下也不是難事。

    這次我看到了XKC-Y25-V非接觸式液體偵測器,正好也在使用ESP32,就買了幾個來試玩。

    XKC-Y25-V的工作原理是透過電容感應技術,當液體接近時,由於液體的介電係數比空氣高,會改變電場分布,進而影響電容值。當偵測器偵測到電場變化時,便能判斷液體是否到達指定位置。

    我買的是PNP型XKC-Y25-V一共有四個腳位,棕線是5-24V的輸入電源、藍線是接地、黃線是OUT而黑線是M。

    因不清楚OUT和M的定義,所以先拿三用電錶量一下各個腳位。這裡讓ESP32單純做供電,XKC-Y25-V的棕線接上ESP32的VIN,藍線接上GND,因為ESP32的VIN腳位會提供未經調整,從USB提供的輸入電壓,這個通常是 5V 電源,所以我量得VIN對GND的電壓是4.96V是沒有問題的。那再來看一下M對GND與OUT對GND的訊號

    • 若有偵測到液體,XKC-Y25-V本體紅燈亮起,M對GND的電壓大約是4.1V,OUT對GND的電壓大約是4.95V,等同輸入電壓。
    • 若沒有偵測到液體,XKC-Y25-V本體紅燈熄滅,M對GND的電壓還是4.1V,OUT對GND的電壓則降到0.3V左右。

    這樣看不出來M腳位的功用是什麼,但確定需要接上ESP32上的GPIO會是OUT腳位。

    所以這裡總結一下,當PNP型XKC-Y25-V偵測到液體會回報高電位,接近輸入電壓,當沒有偵測到液體會回報低電位,接近0電壓。另一種NPN型則相反,偵測到液體會回報低電位,而沒有偵測到液體會回報高電位。撰寫ESP32的程式時就可以依照這個邏輯去寫。

    在接上ESP32的GPIO準備寫程式碼前發現,XKC-Y25-V的工作電壓是5-24V,而ESP32上個ADC最高只到3.3V,這時若OUT腳位輸出超過3.3V的電壓給ESP32的GPIO會有燒毀的可能。但後來發現,XKC-Y25-V如果接3.3V輸入電壓好像也能正常用,且OUT腳位在偵測到液體時輸出的電壓會從5V掉到3.3V,這樣就可以給ESP32正常使用。

    把XKC-Y25-V的棕線接上3.3V、藍線接上GND和黃線接上GPIO15,透過Arduino上傳以下程式碼到ESP32上做測試。

    #define DATA 15
    
    void setup() {
      Serial.begin(115200);
      pinMode(DATA, INPUT);
    }
    
    void loop() {
      int result = digitalRead(DATA);
      Serial.println(result);
      delay(1000);
    }
    

    因為是使用digitalRead來讀取GPIO腳位電壓值,且ESP32輸入電壓為3.3V,所以偵測到液體時電壓接近3.3V,超過2.3V(3.3V的70%)就會被判斷為1,反之沒偵測到液體時電壓接近0V,低於0.99V(3.3V的30%)就會判定為0。Serial Monitor視窗輸出為

    16:33:23.809 -> 0
    16:33:24.766 -> 0
    16:33:25.805 -> 0
    16:33:26.806 -> 1 開始偵測到液體
    16:33:27.800 -> 1
    16:33:28.766 -> 1
    

    也可以使用analogRead來讀取電壓值,然後自行設定一個閥值(Threshold)和一個判斷式來輸出最後結果。因ESP32使用12位元ADC來進行模擬訊號的轉換,因此其數值範圍是0到4095(2^12-1),0代表0V而4095代表3.3V。

    #define DATA 15
    int threshold = 2000;
    
    void setup() {
      Serial.begin(115200);
      pinMode(DATA, INPUT);
    }
    
    void loop() {
      int analogValue = analogRead(DATA);
      int result = (analogValue > threshold) ? 1 : 0;
    
      Serial.print("Analog Value: ");
      Serial.print(analogValue);
      Serial.print(" / Result: ");
      Serial.println(result);
      
      delay(1000);
    }
    

    Serial Monitor視窗輸出為

    16:36:00.744 -> Analog Value: 378 / Result: 0
    16:36:01.710 -> Analog Value: 304 / Result: 0
    16:36:02.735 -> Analog Value: 207 / Result: 0
    16:36:03.710 -> Analog Value: 106 / Result: 0
    16:36:04.751 -> Analog Value: 4095 / Result: 1 開始偵測到液體
    16:36:05.710 -> Analog Value: 4095 / Result: 1
    16:36:06.753 -> Analog Value: 4095 / Result: 1
    16:36:07.733 -> Analog Value: 4095 / Result: 1
    

    實際裝在魚缸上測試後,卻發現沒有這麼好用,主要有二個問題

    • 水面的擾動與缸壁殘留的水會影響XKC-Y25-V對液位的判斷。本來要裝在濾材格、馬達格與補水桶的三個XKC-Y25-V,後來只留了補水桶(已經很難拆下),其他都用傳統的塑料浮球開關取代。
    • XKC-Y25-V在沒有偵測到液體時,透過ESP32做digitalRead()會在0跟1之間跳動,改成analogRead()後發現OUT對GND的電壓跳來跳去,偶爾還會跳到4095,也就是3.3V,如下圖所示。而在有偵測到液體時則很穩定。

    關於第二個問題,原因不是很清楚,拿三用電錶去量是量不到3.3V的,當然,也有可能是因為取樣數的問題。又或者是我給的工作電壓是3.3V,但我也不能換成5V去測試,不然GPIO如前述會燒掉。

    既然這樣,那就用程式去解決,方法是用多個取樣點確認,比如說讀取到三次連續的4095,才判斷為有液體存在,只要出現一個非4095的值,則判斷為液體不存在。這裡用analogRead()來寫

    #define DATA 15
    int threshold = 2000;
    int count = 0;
    int result = -1;
    
    void setup() {
      Serial.begin(115200);
      pinMode(DATA, INPUT);
    }
    
    void loop() {
      int analogValue = analogRead(DATA);
    
      //每讀取到一次4095時計數器就+1,反之歸0。
      if (analogValue == 4095)
        {
          count++;
        }
      else
        {
          count = 0;
        }
    
      //讀取到三次連續的4095,才判斷為有液體存在。
      if (count >= 3)
        {
          result = 1;
        }
      else
        {
          result = 0;
        }
      
      Serial.print(count);
      Serial.print(" / Analog reading: ");
      Serial.print(analogValue);
      Serial.print(" / Result: ");
      Serial.println(result);
      
      delay(1000);
    }
    

    Serial Monitor視窗輸出為

    16:26:42.082 -> 0 / Analog reading: 439 / Result: 0
    16:26:43.096 -> 0 / Analog reading: 499 / Result: 0
    16:26:44.120 -> 0 / Analog reading: 471 / Result: 0
    16:26:45.082 -> 0 / Analog reading: 535 / Result: 0
    16:26:46.124 -> 0 / Analog reading: 555 / Result: 0
    16:26:47.100 -> 0 / Analog reading: 528 / Result: 0
    16:26:48.123 -> 1 / Analog reading: 4095 / Result: 0
    16:26:49.106 -> 2 / Analog reading: 4095 / Result: 0
    16:26:50.120 -> 3 / Analog reading: 4095 / Result: 1 連續三次4095後才算有偵測到液體
    16:26:51.083 -> 4 / Analog reading: 4095 / Result: 1
    16:26:52.126 -> 5 / Analog reading: 4095 / Result: 1
    16:26:53.123 -> 6 / Analog reading: 4095 / Result: 1
    16:26:54.127 -> 0 / Analog reading: 224 / Result: 0
    16:26:55.120 -> 0 / Analog reading: 80 / Result: 0
    

    這段程式可以解決液體偵測不穩定的問題,確保只有連續三次讀取到正確數值時才進行判斷。

    發佈留言

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

    返回頂端