第7章 ESP32 Touch Sensor 教學:touchRead、電容觸控、Threshold 與 RGB LED

發布日期: |更新日期:
文章主圖:第7章 ESP32 Touch Sensor 教學:touchRead、電容觸控、Threshold 與 RGB LED

前言:不用按鍵,也能讓 ESP32 感應手指

前面的 ESP32 GPIO Input 教學中,如果要讓使用者操作 ESP32,我們通常需要一顆:

Push Button

接到 GPIO:

GPIO
 │
Button
 │
GND

然後使用:

digitalRead();

判斷按鍵是否按下。

但 ESP32 有一項很值得單獨學習的硬體特色:

Capacitive Touch Sensor

也就是:

電容式觸控感應

使用者甚至不需要真正的機械按鍵,只要準備:

銅箔
金屬片
PCB Touch Pad
導電貼片
金屬螺絲

連接到 ESP32 支援 Touch 的 GPIO,就可以讓手指觸摸產生輸入。

Espressif 官方說明,Touch Sensor 會利用 GPIO Touch Pad 的充放電行為量測等效電容變化;手指接近或碰觸 Pad 時會改變電容,進而改變充放電計數結果。

因此可以做:

觸控式檯燈
觸控式電源開關
Touch Button
RGB Touch Controller
電容式選單
Touch Slider
Touch Wheel
智慧家電面板
隱藏式控制面板

這是傳統 Arduino UNO 本身沒有內建專用 Touch Peripheral 的功能,也因此非常值得作為 ESP32 的獨立一章。

本章將完成:

Capacitive Touch
↓
Touch GPIO
↓
touchRead()
↓
Baseline
↓
Threshold
↓
Touch Detection
↓
抗干擾
↓
短按 / 長按
↓
觸控燈光開關
↓
三鍵 Touch
↓
RGB LED

最後完成兩個專題:

ESP32 觸控式燈光開關

以及進階:

三鍵觸控控制 RGB LED

一、什麼是 Capacitive Touch?

Capacitive Touch:

Capacitive Touch Sensing

中文就是:

電容式觸控感應

它不是像普通按鍵一樣利用:

接點導通

判斷使用者是否按下。

它偵測的是:

電容量改變

基本概念:

Touch Pad
↓
原本具有一定電容
↓
手指接近
↓
人體增加等效電容
↓
充放電特性改變
↓
ESP32 偵測變化
↓
判斷 Touch

Espressif 官方說明,Touch Channel 在量測期間會反覆充電與放電;手指靠近或觸摸時,Touch Channel 的等效電容增加,使充放電行為發生變化。

二、ESP32 Touch Sensor 怎麼知道手指碰到了?

ESP32 Touch Sensor 內部具有振盪與電容量測電路。

簡化理解:

ESP32
↓
Touch Pad 充電
↓
放電
↓
再充電
↓
再放電
↓
計算固定時間內的週期數

Arduino-ESP32 官方說明,touchRead() 所讀取的就是一定量測時間內的 Touch 充放電 Cycle Count;手指造成等效電容變化後,這個數值就會改變。

因此程式並不是單純得到:

HIGH
LOW

而是得到一個:

Touch Value

例如:

未觸摸:
72
74
73
71
74

觸摸:
31
28
26
30

然後程式自己決定:

低於多少
=
Touch

這個判斷值就是:

Touch Threshold

三、ESP32 Touch 和 digitalRead() 有什麼不同?

普通按鍵:

digitalRead(BUTTON_PIN);

通常得到:

HIGH
LOW

Touch:

touchRead(TOUCH_PIN);

取得的是一個量測值。

因此架構不同:

普通按鍵

GPIO
↓
HIGH / LOW
↓
直接判斷

Touch Sensor

Touch GPIO
↓
touchRead()
↓
Touch Value
↓
Threshold
↓
Touched / Released

所以使用 Touch Sensor 最重要的不是只有學會:

touchRead();

而是學會:

如何建立可靠的 Threshold。

四、ESP32 有哪些 Touch GPIO?

本章主要以:

原始 ESP32

例如常見:

ESP32-WROOM-32
ESP32 DevKit

為例。

原始 ESP32 提供 10 個 Capacitive Touch Channel。Espressif 最新 ESP-IDF 文件列出的對應如下:

原始 ESP32 Touch Channel 與 GPIO 對照表
Touch Channel GPIO
T0 / CH0 GPIO4
T1 / CH1 GPIO0
T2 / CH2 GPIO2
T3 / CH3 GPIO15
T4 / CH4 GPIO13
T5 / CH5 GPIO12
T6 / CH6 GPIO14
T7 / CH7 GPIO27
T8 / CH8 GPIO33
T9 / CH9 GPIO32

也就是:

GPIO4
GPIO0
GPIO2
GPIO15
GPIO13
GPIO12
GPIO14
GPIO27
GPIO33
GPIO32

都具有原始 ESP32 的 Touch Sensor 功能。

五、不要把所有 ESP32 型號當成一樣

ESP32 現在已經是一整個系列:

ESP32
ESP32-S2
ESP32-S3
ESP32-C3
ESP32-C6
ESP32-H2
ESP32-P4
...

它們的 Touch Peripheral 並不完全相同。

Arduino-ESP32 官方文件特別提醒:

Touch Peripheral 並不是存在於每一種 ESP32 SoC。

所以在使用:

touchRead();

之前,應先確認自己使用的:

ESP32 Chip
+
Development Board

是否具有 Touch 功能。

本章正式實驗以:

原始 ESP32 / ESP32-WROOM-32

為主要平台。

六、ESP32、ESP32-S2、ESP32-S3 的 Touch Value 方向不同

這是非常重要的一點。

Espressif 官方最新 Touch Sensor 文件明確區分:

原始 ESP32:Touch V1

未觸摸
→ 數值較高

觸摸
→ 數值下降

ESP32-S2 / ESP32-S3:Touch V2

未觸摸
→ 數值較低

觸摸
→ 數值上升

所以本章如果看到:

if (touchValue < threshold)

這是針對:

原始 ESP32(補充說明)

的邏輯。

不要直接把完全相同的 Threshold 判斷套到 ESP32-S2 / S3。

七、ESP32 touchRead()

Arduino-ESP32 最基本的 Touch API:

touchRead();

格式:

touch_value_t value =
  touchRead(pin);

例如:

touch_value_t touchValue =
  touchRead(27);

Arduino-ESP32 官方定義:

touch_value_t touchRead(
  uint8_t pin
);

而原始 ESP32 的 Touch Value 使用 16-bit 類型;ESP32-S2 / S3 則使用較大的 32-bit Touch Value。

八、第一個 ESP32 Touch 程式

本章第一個實驗使用:

GPIO27

也就是原始 ESP32:

T7

程式:

const uint8_t TOUCH_PIN = 27;

void setup()
{
  Serial.begin(115200);

  delay(1000);

  Serial.println();
  Serial.println(
    "ESP32 Touch Test"
  );
}

void loop()
{
  touch_value_t touchValue =
    touchRead(
      TOUCH_PIN
    );

  Serial.print(
    "Touch Value = "
  );

  Serial.println(
    touchValue
  );

  delay(100);
}

打開:

Serial Monitor

設定:

115200 baud

先不要碰 GPIO27 Touch Pad。

記錄數值。

接著用手指觸摸。

九、觀察 Touch Value

例如可能看到:

沒有觸摸

72
73
71
74
72
73

手指觸摸

35
31
27
29
33

這只是示意。

你的實際數字可能完全不同。

原因包括:

ESP32 個體
Touch Pad 大小
導線長度
手指面積
PCB
桌面材質
電源
USB
環境濕度
外殼
接地
附近電子設備

都可能影響 Touch Reading。

因此:

不要直接複製別人的 Threshold。

十、什麼是 Touch Threshold?

假設:

沒有 Touch ≈ 70

而:

Touch ≈ 30

可以設定:

const int TOUCH_THRESHOLD = 50;

然後:

if (
  touchRead(TOUCH_PIN)
  < TOUCH_THRESHOLD
)
{
  // Touched
}

對原始 ESP32 而言,因為 Touch 時數值下降,因此:

touchValue < threshold

可以視為觸摸。

Arduino-ESP32 官方的 Touch Interrupt API 也是以 Threshold 判斷;官方特別建議先利用 touchRead() 找出 Touched 與 Untouched 的讀值,再建立合適的 Threshold。

十一、Threshold 應該怎麼決定?

不要猜。

比較正確的流程是:

ESP32 開機
↓
先不碰 Touch Pad
↓
讀取 Baseline
↓
用手觸摸
↓
觀察 Touch Value
↓
找出安全分界
↓
設定 Threshold

例如:

Baseline = 75

Touch =
25~40

可以設定:

Threshold = 50

留下一段安全距離。

十二、使用百分比 Threshold 更方便

與其固定:

const int TOUCH_THRESHOLD = 50;

可以根據 Baseline 計算。

例如:

Threshold
=
Baseline × 70%

如果:

Baseline = 80

則:

Threshold =
80 × 0.70
=
56

程式:

touch_value_t threshold =
  baseline * 0.70;

對不同硬體會比較容易調整。

但是 70% 只是:

教材中的起始值。

實際產品仍需校準。

十三、自動建立 Touch Baseline

可以在 ESP32 開機時:

讀取 50 次
↓
取平均
↓
建立 Baseline

例如:

touch_value_t getTouchBaseline(
  uint8_t pin
)
{
  uint32_t total = 0;

  const int samples = 50;

  for (
    int i = 0;
    i < samples;
    i++
  )
  {
    total += touchRead(pin);

    delay(10);
  }

  return total / samples;
}

然後:

baseline =
  getTouchBaseline(
    TOUCH_PIN
  );

十四、Touch Baseline 完整測試程式

const uint8_t TOUCH_PIN = 27;

touch_value_t baseline;
touch_value_t threshold;

touch_value_t readBaseline(
  uint8_t pin
)
{
  uint32_t total = 0;

  const int samples = 50;

  for (
    int i = 0;
    i < samples;
    i++
  )
  {
    total += touchRead(pin);

    delay(10);
  }

  return total / samples;
}

void setup()
{
  Serial.begin(115200);

  delay(1000);

  Serial.println();
  Serial.println(
    "Do not touch the sensor..."
  );

  baseline =
    readBaseline(
      TOUCH_PIN
    );

  threshold =
    baseline * 70 / 100;

  Serial.print(
    "Baseline = "
  );

  Serial.println(
    baseline
  );

  Serial.print(
    "Threshold = "
  );

  Serial.println(
    threshold
  );
}

void loop()
{
  touch_value_t value =
    touchRead(
      TOUCH_PIN
    );

  Serial.print(
    "Touch = "
  );

  Serial.print(
    value
  );

  if (
    value < threshold
  )
  {
    Serial.println(
      "  TOUCHED"
    );
  }
  else
  {
    Serial.println(
      "  RELEASED"
    );
  }

  delay(100);
}

這個版本已經比:

if (touchRead(27) < 40)

更適合作為實際教材。

十五、為什麼開機時不要碰 Touch Pad?

因為:

Baseline

代表:

沒有觸摸時的正常值。

如果開機校準時手正好放在 Touch Pad:

Touch 狀態
↓
被當成 Baseline

後面的 Threshold 就會錯。

因此可以在開機時顯示:

Touch Calibration
Do Not Touch

延遲約 1 秒後再量測。

十六、Touch Sensor 要接什麼?

最簡單的測試甚至可以:

GPIO27
 │
杜邦線
 │
金屬片

金屬片可以使用:

銅箔膠帶
鋁箔
銅片
PCB Pad
金屬螺絲
導電片

使用者:

手指
↓
Touch Pad

即可改變電容量。

ESP32 Touch Sensor 可以與不同形狀的 Electrode 結合,Espressif 官方也指出多個 Touch Pad 可以組成按鍵、矩陣或 Slider 等不同形式。

十七、Touch Pad 為什麼可以隔著塑膠?

因為 Capacitive Touch 並不是靠:

金屬直接導通

工作。

而是偵測:

Capacitance Change

因此適當設計時,可以把 Electrode 放在:

塑膠板
壓克力
玻璃
外殼
面板

後面。

使用者觸摸表面時仍可能造成足夠的電容量變化。

這也是 Capacitive Touch 很適合:

封閉式外殼
防塵面板
智慧家電
平面控制器

的重要原因。

實際可感應厚度與可靠度仍然取決於 Touch Pad、材料、厚度與完整電極設計。

十八、實作一:ESP32 觸控式燈光開關

現在開始第一個正式專題。

功能:

第一次 Touch
↓
LED ON

第二次 Touch
↓
LED OFF

第三次 Touch
↓
LED ON

相當於:

Touch Toggle Switch

硬體:

Touch Pad → GPIO27
LED       → GPIO18

十九、ESP32 觸控燈接線

Touch:

GPIO27
 │
 │
Copper Pad

LED:

GPIO18
 │
220Ω
 │
LED +
 │
LED -
 │
GND

接線表:

ESP32 觸控式燈光開關接線表
ESP32 元件
GPIO27 Touch Pad / 銅箔
GPIO18 220Ω~330Ω → LED
GND LED 負極

Touch Electrode 不需要像傳統按鍵那樣:

Touch Pad → GND

Touch GPIO 本身就是感應端。

二十、不能只用「目前正在 Touch」切換 LED

下面這種寫法有問題:

if (
  touchRead(TOUCH_PIN)
  < threshold
)
{
  ledState =
    !ledState;
}

因為人的手指一次可能停留:

100 ms
300 ms
500 ms

而 loop() 每秒可能跑很多次。

結果:

Touch
↓
LED ON
↓
LED OFF
↓
LED ON
↓
LED OFF
...

所以我們需要偵測:

Touch Edge

也就是:

Released
↓
第一次變成 Touched

時才執行一次。

二十一、Touch State Detection

先建立:

bool wasTouched = false;

目前:

bool isTouched =
  touchValue < threshold;

只有:

isTouched == true
&&
wasTouched == false

代表:

新的一次 Touch

也就是:

Released
↓
Touch Down

這時才切換 LED。

最後:

wasTouched =
  isTouched;

更新狀態。

二十二、ESP32 觸控式燈光開關完整程式

/*
  第 7 章
  ESP32 Touch Sensor

  實作:
  觸控式燈光開關

  Touch:
  GPIO27

  LED:
  GPIO18

  適用:
  原始 ESP32 / ESP32-WROOM-32
*/

const uint8_t TOUCH_PIN = 27;
const uint8_t LED_PIN = 18;

touch_value_t touchBaseline;
touch_value_t touchThreshold;

bool wasTouched = false;
bool ledState = false;


// -----------------------------
// Baseline Calibration
// -----------------------------
touch_value_t calibrateTouch(
  uint8_t pin
)
{
  uint32_t total = 0;

  const uint8_t samples = 50;

  for (
    uint8_t i = 0;
    i < samples;
    i++
  )
  {
    total += touchRead(pin);

    delay(10);
  }

  return total / samples;
}


// -----------------------------
// setup()
// -----------------------------
void setup()
{
  Serial.begin(115200);

  pinMode(
    LED_PIN,
    OUTPUT
  );

  digitalWrite(
    LED_PIN,
    LOW
  );

  delay(1000);

  Serial.println();
  Serial.println(
    "ESP32 Touch Light"
  );

  Serial.println(
    "Do not touch the sensor"
  );


  touchBaseline =
    calibrateTouch(
      TOUCH_PIN
    );


  // 70% of baseline
  touchThreshold =
    touchBaseline
    * 70
    / 100;


  Serial.print(
    "Baseline = "
  );

  Serial.println(
    touchBaseline
  );


  Serial.print(
    "Threshold = "
  );

  Serial.println(
    touchThreshold
  );


  Serial.println(
    "Touch Ready"
  );
}


// -----------------------------
// loop()
// -----------------------------
void loop()
{
  touch_value_t touchValue =
    touchRead(
      TOUCH_PIN
    );


  bool isTouched =
    touchValue
    < touchThreshold;


  // New Touch
  if (
    isTouched
    &&
    !wasTouched
  )
  {
    ledState =
      !ledState;


    digitalWrite(
      LED_PIN,
      ledState
    );


    Serial.print(
      "Touch -> LED "
    );


    Serial.println(
      ledState
      ? "ON"
      : "OFF"
    );
  }


  wasTouched =
    isTouched;


  delay(20);
}

本程式使用原始 ESP32 的 Touch V1 行為,也就是 Touch 時數值下降;官方 Arduino Touch API 也建議利用 touchRead() 取得 Touched / Untouched 數值後決定 Threshold。

二十三、為什麼 Touch Sensor 也會誤觸?

Touch 並不是完美的:

Touch / No Touch

數位開關。

它本身是一種:

Analog-like Measurement

所以讀值可能變成:

Baseline = 70

69
71
68
72
66
70
65

如果 Threshold 設得太接近 Baseline:

Threshold = 68

就很容易:

Noise
↓
誤判 Touch

因此 Threshold 必須留下安全 Margin。

二十四、Touch Sensor 會受到哪些因素影響?

實際 Touch 系統可能受到:

電源雜訊
USB 電源
Wi-Fi / RF
Touch Pad 尺寸
Touch Pad 走線
附近金屬
人體接地狀況
外殼材料
濕度
溫度
水滴
PCB Layout
附近訊號線

影響。

Espressif 官方 Touch 文件建議,在設定 Touch Threshold 前實際量測 Touched 與 Released 狀態;如果量測有 Noise,應使用 Filtering,並在實際應用環境中測試溫度與供電電壓變化的影響。

二十五、ESP32 Touch 抗干擾第一招:平均取樣

最簡單的方法就是不要只讀:

touchRead();

一次。

而是讀:

5 次

取平均。

touch_value_t readTouchAverage(
  uint8_t pin
)
{
  uint32_t total = 0;

  const uint8_t samples = 5;

  for (
    uint8_t i = 0;
    i < samples;
    i++
  )
  {
    total += touchRead(pin);
  }

  return total / samples;
}

然後:

touch_value_t value =
  readTouchAverage(
    TOUCH_PIN
  );

這樣可以降低單次異常值對判斷的影響。

Espressif 的底層 Touch Driver 本身也提供 Filtering 機制,並建議當 Touch Reading Noise 較大時進行濾波。

二十六、第二招:不要把 Threshold 設太敏感

例如:

Baseline = 80
Touch = 30

比較合理的 Threshold 可以放在:

50~60

而不是:

78

Threshold 太靠近 Baseline:

Baseline
80
│
78 Threshold
│
Noise
↓
False Touch

而留出 Margin:

Baseline
80
│
│
55 Threshold
│
│
Touch
30

會可靠很多。

二十七、第三招:使用 Hysteresis

這是 Touch 系統非常實用的技巧。

假設:

Touch Threshold = 55

不要 Touch 和 Release 都用同一個數值。

可以設定:

Touch Threshold   = 55
Release Threshold = 65

變成:

Value < 55
→ Touch

Value > 65
→ Release

中間:

55~65

保持原本狀態。

這稱為:

Hysteresis

也就是遲滯。

它可以避免:

54
56
55
57
54

在 Threshold 附近來回切換狀態。

二十八、Touch Hysteresis 範例

const int TOUCH_THRESHOLD =
  50;

const int RELEASE_THRESHOLD =
  60;

bool touched = false;

void loop()
{
  int value =
    touchRead(
      TOUCH_PIN
    );

  if (!touched)
  {
    if (
      value <
      TOUCH_THRESHOLD
    )
    {
      touched = true;

      Serial.println(
        "Touch"
      );
    }
  }
  else
  {
    if (
      value >
      RELEASE_THRESHOLD
    )
    {
      touched = false;

      Serial.println(
        "Release"
      );
    }
  }
}

這種設計會比單純:

value < threshold

更適合實際 Touch Button。

二十九、第四招:Touch Debounce

Touch Sensor 雖然不像機械按鍵有真正金屬 Contact Bounce,但感應值仍可能在臨界點附近波動。

因此也可以加入:

20~50 ms

的穩定確認時間。

例如:

Touch Value 低於 Threshold
↓
持續 30 ms
↓
才判定真正 Touch

這能進一步降低:

瞬間 Noise
↓
False Trigger

三十、第五招:定期更新 Baseline

實際環境可能慢慢變化:

溫度
濕度
電源
外殼
人體環境

如果開機 Baseline:

80

幾小時後自然變成:

70

固定 Threshold 可能開始變得不合理。

進階產品可以:

沒有 Touch 時
↓
緩慢更新 Baseline
↓
Threshold 跟著調整

例如:

baseline =
  baseline * 0.99
  +
  current * 0.01;

但是:

Touch 狀態時不要快速更新 Baseline。

否則手指可能被系統慢慢當成新的「正常狀態」。

三十一、touchSetCycles()

Arduino-ESP32 還提供:

touchSetCycles();

可以設定 Touch Sensor 的量測時間與兩次量測之間的等待時間。

官方說明指出,這些設定會影響:

touchRead()
Threshold
Detection Accuracy

而 Arduino-ESP32 預設的 Touch Reading 大約需要 0.5 ms。

API:

touchSetCycles(
  measure,
  sleep
);

一般入門實驗不需要修改,

但它代表:

ESP32 Touch Sensor 並不是一個只有 touchRead() 的黑盒子,量測行為本身也可以調整。

三十二、如何判斷短按與長按?

Touch Button 很適合做:

Short Touch
Long Touch

例如:

短按
→ LED ON / OFF

長按
→ 切換模式

基本流程:

Touch Down
↓
記錄開始時間
↓
手指持續 Touch
↓
Release
↓
計算 Touch Duration

程式使用:

millis();

即可。

三十三、短按 / 長按的時間定義

例如:

const unsigned long
LONG_PRESS_TIME = 1000;

代表:

小於 1000 ms
→ Short Touch

大於等於 1000 ms
→ Long Touch

也就是:

Touch Down
↓
0 ms
↓
500 ms
↓
Release
↓
SHORT

Touch Down
↓
0 ms
↓
1000 ms
↓
1500 ms
↓
Release
↓
LONG

三十四、ESP32 Touch 長按 / 短按完整程式

const uint8_t TOUCH_PIN = 27;

touch_value_t baseline;
touch_value_t threshold;

bool wasTouched = false;

unsigned long touchStartTime = 0;

const unsigned long
LONG_PRESS_TIME = 1000;


touch_value_t calibrateTouch()
{
  uint32_t total = 0;

  for (
    int i = 0;
    i < 50;
    i++
  )
  {
    total +=
      touchRead(
        TOUCH_PIN
      );

    delay(10);
  }

  return total / 50;
}


void setup()
{
  Serial.begin(115200);

  delay(1000);

  Serial.println(
    "Do not touch..."
  );

  baseline =
    calibrateTouch();

  threshold =
    baseline * 70 / 100;


  Serial.print(
    "Baseline = "
  );

  Serial.println(
    baseline
  );


  Serial.print(
    "Threshold = "
  );

  Serial.println(
    threshold
  );
}


void loop()
{
  touch_value_t value =
    touchRead(
      TOUCH_PIN
    );


  bool isTouched =
    value < threshold;


  // Touch Down
  if (
    isTouched
    &&
    !wasTouched
  )
  {
    touchStartTime =
      millis();
  }


  // Touch Release
  if (
    !isTouched
    &&
    wasTouched
  )
  {
    unsigned long
    duration =
      millis()
      - touchStartTime;


    if (
      duration
      >= LONG_PRESS_TIME
    )
    {
      Serial.println(
        "LONG TOUCH"
      );
    }
    else
    {
      Serial.println(
        "SHORT TOUCH"
      );
    }


    Serial.print(
      "Duration = "
    );

    Serial.print(
      duration
    );

    Serial.println(
      " ms"
    );
  }


  wasTouched =
    isTouched;


  delay(20);
}

三十五、長按可以拿來做什麼?

例如設計智慧燈:

短按
↓
LED ON / OFF

長按:

LED Brightness
↓
25%
50%
75%
100%

或者:

短按
→ 下一個 RGB 顏色

長按
→ 關閉燈光

因此 Touch Sensor 不只可以取代普通 Button,

還可以建立:

User Interface

三十六、Touch Sensor + PWM

前面已經學過:

第 5 章
ESP32 PWM

因此現在可以組合:

Touch
↓
User Input
↓
ESP32
↓
LEDC PWM
↓
LED Brightness

例如:

Short Touch
→ ON / OFF

Long Touch
→ Brightness

這就是一個真正的:

Touch Dimmer

架構。

三十七、進階實作:三鍵 Touch 控制 RGB LED

接下來做本章第二個重點實作。

使用三個 Touch Sensor:

Touch 1
Touch 2
Touch 3

控制:

Red
Green
Blue

例如:

Touch 1
→ Red ON / OFF

Touch 2
→ Green ON / OFF

Touch 3
→ Blue ON / OFF

三個顏色還可以混合。

例如:

Red + Green
→ Yellow

Green + Blue
→ Cyan

Red + Blue
→ Magenta

Red + Green + Blue
→ White

這樣可以一次練習:

Touch
+
Multiple Input
+
LEDC
+
RGB LED

三十八、三鍵 Touch GPIO 規劃

使用:

Touch Red
GPIO32

Touch Green
GPIO33

Touch Blue
GPIO27

這三個 GPIO 都是原始 ESP32 Touch Channel:

GPIO32 → CH9
GPIO33 → CH8
GPIO27 → CH7

RGB LED:

Red
→ GPIO18

Green
→ GPIO19

Blue
→ GPIO21

三十九、完整接線表

Touch

ESP32 三鍵 Touch GPIO 規劃表
功能 ESP32
Red Touch GPIO32
Green Touch GPIO33
Blue Touch GPIO27

每一個 Touch GPIO:

GPIO
 │
銅箔 / 金屬片

RGB LED

本例使用:

Common Cathode RGB LED

ESP32 Common Cathode RGB LED 接線表
RGB ESP32
Red GPIO18 → 電阻
Green GPIO19 → 電阻
Blue GPIO21 → 電阻
Common Cathode GND

每個 RGB LED Channel 建議各自使用限流電阻。

四十、RGB LED PWM 初始化

使用 Arduino-ESP32 3.x:

ledcAttach(
  RED_PIN,
  5000,
  8
);

ledcAttach(
  GREEN_PIN,
  5000,
  8
);

ledcAttach(
  BLUE_PIN,
  5000,
  8
);

然後:

ledcWrite(
  RED_PIN,
  red
);

控制亮度。

目前 Arduino-ESP32 LEDC API 的 ledcAttach() 會自動配置 Channel,而且 LEDC 可提供多個獨立 PWM Channel,適合 RGB LED 控制。

四十一、每個 Touch Key 都需要自己的 Baseline

不能假設:

GPIO32 Baseline
=
GPIO33 Baseline
=
GPIO27 Baseline

因為:

Pad 大小
線長
附近導體
GPIO

可能不同。

所以必須分別校準:

Red Baseline
Green Baseline
Blue Baseline

然後各自建立:

Red Threshold
Green Threshold
Blue Threshold

四十二、建立 TouchKey 結構

為了讓程式更整齊,可以建立:

struct TouchKey
{
  uint8_t pin;

  touch_value_t baseline;

  touch_value_t threshold;

  bool previousState;
};

建立:

TouchKey redKey;
TouchKey greenKey;
TouchKey blueKey;

這樣未來增加更多 Touch Key 也比較容易管理。

四十三、三鍵 Touch RGB 完整正式版

/*
  第 7 章
  ESP32 Touch Sensor

  進階實作:
  三鍵 Touch 控制 RGB LED

  適用:
  原始 ESP32 / ESP32-WROOM-32

  Touch:
  Red   -> GPIO32
  Green -> GPIO33
  Blue  -> GPIO27

  RGB LED:
  Red   -> GPIO18
  Green -> GPIO19
  Blue  -> GPIO21

  RGB Type:
  Common Cathode

  Arduino-ESP32:
  3.x LEDC API
*/


// =====================================
// Touch Key Structure
// =====================================
struct TouchKey
{
  uint8_t pin;

  touch_value_t baseline;

  touch_value_t threshold;

  bool previousState;
};


// =====================================
// Touch GPIO
// =====================================
TouchKey redKey =
{
  32,
  0,
  0,
  false
};

TouchKey greenKey =
{
  33,
  0,
  0,
  false
};

TouchKey blueKey =
{
  27,
  0,
  0,
  false
};


// =====================================
// RGB GPIO
// =====================================
const uint8_t RED_PIN = 18;

const uint8_t GREEN_PIN = 19;

const uint8_t BLUE_PIN = 21;


// =====================================
// PWM
// =====================================
const uint32_t PWM_FREQ =
  5000;

const uint8_t PWM_RESOLUTION =
  8;

const uint8_t PWM_MAX =
  255;


// =====================================
// RGB State
// =====================================
bool redState = false;

bool greenState = false;

bool blueState = false;


// =====================================
// Touch Parameters
// =====================================
const uint8_t
THRESHOLD_PERCENT =
  70;

const uint8_t
CALIBRATION_SAMPLES =
  50;


// =====================================
// Read Touch Average
// =====================================
touch_value_t readTouchAverage(
  uint8_t pin,
  uint8_t samples = 5
)
{
  uint32_t total = 0;


  for (
    uint8_t i = 0;
    i < samples;
    i++
  )
  {
    total +=
      touchRead(
        pin
      );
  }


  return
    total / samples;
}


// =====================================
// Calibrate One Touch Key
// =====================================
void calibrateKey(
  TouchKey &key
)
{
  uint32_t total = 0;


  for (
    uint8_t i = 0;
    i < CALIBRATION_SAMPLES;
    i++
  )
  {
    total +=
      touchRead(
        key.pin
      );


    delay(10);
  }


  key.baseline =
    total
    / CALIBRATION_SAMPLES;


  key.threshold =
    key.baseline
    * THRESHOLD_PERCENT
    / 100;


  key.previousState =
    false;
}


// =====================================
// Detect New Touch
// =====================================
bool newTouch(
  TouchKey &key
)
{
  touch_value_t value =
    readTouchAverage(
      key.pin
    );


  bool currentState =
    value
    < key.threshold;


  bool pressed =
    currentState
    &&
    !key.previousState;


  key.previousState =
    currentState;


  return pressed;
}


// =====================================
// Update RGB
// =====================================
void updateRGB()
{
  ledcWrite(
    RED_PIN,
    redState
    ? PWM_MAX
    : 0
  );


  ledcWrite(
    GREEN_PIN,
    greenState
    ? PWM_MAX
    : 0
  );


  ledcWrite(
    BLUE_PIN,
    blueState
    ? PWM_MAX
    : 0
  );
}


// =====================================
// Print RGB State
// =====================================
void printRGBState()
{
  Serial.print(
    "RGB = "
  );


  Serial.print(
    redState
    ? "R"
    : "-"
  );


  Serial.print(
    greenState
    ? "G"
    : "-"
  );


  Serial.println(
    blueState
    ? "B"
    : "-"
  );
}


// =====================================
// setup()
// =====================================
void setup()
{
  Serial.begin(
    115200
  );


  delay(
    1000
  );


  Serial.println();
  Serial.println(
    "ESP32 3-Key Touch RGB"
  );


  Serial.println(
    "Do NOT touch the pads"
  );


  // -----------------------------
  // RGB PWM
  // -----------------------------
  if (!ledcAttach(
        RED_PIN,
        PWM_FREQ,
        PWM_RESOLUTION))
  {
    Serial.println(
      "RED LEDC failed"
    );
  }


  if (!ledcAttach(
        GREEN_PIN,
        PWM_FREQ,
        PWM_RESOLUTION))
  {
    Serial.println(
      "GREEN LEDC failed"
    );
  }


  if (!ledcAttach(
        BLUE_PIN,
        PWM_FREQ,
        PWM_RESOLUTION))
  {
    Serial.println(
      "BLUE LEDC failed"
    );
  }


  updateRGB();


  // -----------------------------
  // Touch Calibration
  // -----------------------------
  calibrateKey(
    redKey
  );


  calibrateKey(
    greenKey
  );


  calibrateKey(
    blueKey
  );


  // -----------------------------
  // Display Calibration
  // -----------------------------
  Serial.print(
    "RED Baseline = "
  );

  Serial.print(
    redKey.baseline
  );

  Serial.print(
    "  Threshold = "
  );

  Serial.println(
    redKey.threshold
  );


  Serial.print(
    "GREEN Baseline = "
  );

  Serial.print(
    greenKey.baseline
  );

  Serial.print(
    "  Threshold = "
  );

  Serial.println(
    greenKey.threshold
  );


  Serial.print(
    "BLUE Baseline = "
  );

  Serial.print(
    blueKey.baseline
  );

  Serial.print(
    "  Threshold = "
  );

  Serial.println(
    blueKey.threshold
  );


  Serial.println(
    "Touch Ready"
  );
}


// =====================================
// loop()
// =====================================
void loop()
{
  // -----------------------------
  // RED Touch
  // -----------------------------
  if (
    newTouch(
      redKey
    )
  )
  {
    redState =
      !redState;


    updateRGB();


    Serial.println(
      "RED Touch"
    );


    printRGBState();
  }


  // -----------------------------
  // GREEN Touch
  // -----------------------------
  if (
    newTouch(
      greenKey
    )
  )
  {
    greenState =
      !greenState;


    updateRGB();


    Serial.println(
      "GREEN Touch"
    );


    printRGBState();
  }


  // -----------------------------
  // BLUE Touch
  // -----------------------------
  if (
    newTouch(
      blueKey
    )
  )
  {
    blueState =
      !blueState;


    updateRGB();


    Serial.println(
      "BLUE Touch"
    );


    printRGBState();
  }


  delay(
    20
  );
}

四十四、這支 RGB Touch 程式可以產生哪些顏色?

初始:

R = OFF
G = OFF
B = OFF

→ OFF

按 Red:

R = ON
G = OFF
B = OFF

→ RED

再按 Green:

R = ON
G = ON
B = OFF

→ YELLOW

再按 Blue:

R = ON
G = ON
B = ON

→ WHITE

把 Red 關掉:

R = OFF
G = ON
B = ON

→ CYAN

因此三個 Touch Button 可以產生:

OFF
RED
GREEN
BLUE
YELLOW
CYAN
MAGENTA
WHITE

八種組合。

四十五、進階:短按開關、長按調光

三鍵版本還可以再進一步設計:

Touch Red 短按
→ Red ON / OFF

Touch Red 長按
→ Red Brightness 增加

例如:

0
↓
64
↓
128
↓
192
↓
255
↓
0

也就是:

0%
25%
50%
75%
100%

這樣一顆 Touch Button 就同時具有:

Switch
+
Dimmer

功能。

四十六、進階:RGB Touch 控制器的人機介面設計

可以定義:

Touch 1
短按 → 下一種顏色
長按 → Red 調整

Touch 2
短按 → Brightness
長按 → Auto Fade

Touch 3
短按 → ON / OFF
長按 → Rainbow Mode

這樣三顆 Touch Button 就能建立完整:

RGB Lighting HMI

不需要:

機械按鍵
Keypad
旋鈕

四十七、ESP32 Touch Interrupt

除了不斷:

touchRead();

Arduino-ESP32 還提供:

touchAttachInterrupt();

格式:

touchAttachInterrupt(
  pin,
  userFunc,
  threshold
);

當 Touch Reading 符合設定 Threshold 條件時,可以呼叫指定函式。

對原始 ESP32,預設是數值下降低於 Threshold 時觸發;ESP32-S2 / S3 則是 Touch Value 上升超過 Threshold。

四十八、touchAttachInterrupt() 範例

例如:

const uint8_t TOUCH_PIN =
  27;

volatile bool
touchEvent =
  false;


void ARDUINO_ISR_ATTR
onTouch()
{
  touchEvent =
    true;
}


void setup()
{
  Serial.begin(
    115200
  );


  touchAttachInterrupt(
    TOUCH_PIN,
    onTouch,
    40
  );
}


void loop()
{
  if (
    touchEvent
  )
  {
    touchEvent =
      false;


    Serial.println(
      "Touch Interrupt"
    );
  }
}

這裡同樣建議:

Touch ISR
↓
只設定 Event Flag
↓
loop()
↓
完成真正工作

不要把大量:

Serial
Wi-Fi
LCD
RGB Animation

全部塞進 ISR。

四十九、Touch Interrupt 的 Threshold 更需要校準

不建議看到別人的:

touchAttachInterrupt(
  27,
  onTouch,
  40
);

就直接把:

40

當標準值。

正確流程:

touchRead()
↓
量測 Released
↓
量測 Touched
↓
決定 Threshold
↓
再設定 Interrupt

Arduino-ESP32 官方 Touch API 本身也明確建議利用 touchRead() 找到 Touched 與 Untouched 之間適合的 Threshold。

五十、touchAttachInterruptArg()

Arduino-ESP32 另外提供:

touchAttachInterruptArg();

格式:

touchAttachInterruptArg(
  pin,
  userFunc,
  arg,
  threshold
);

它與普通:

touchAttachInterrupt();

最大的不同是:

可以傳入自訂 Argument。

這對:

多顆 Touch Button

特別方便。

五十一、Touch Sensor 還可以喚醒 ESP32

Arduino-ESP32 目前還提供:

touchSleepWakeUpEnable();

可以設定 Touch Pad 作為 Sleep Wake-up Source。

也就是:

ESP32 Deep Sleep
↓
低功耗等待
↓
使用者 Touch
↓
ESP32 Wake Up

這對:

電池裝置
無線遙控器
智慧家電
Touch Panel
低功耗 IoT

非常有價值。

Arduino-ESP32 官方 Touch API 目前也特別指出,ESP32-S2 / S3 的 Touch Sleep Wake-up 支援限制與原始 ESP32 不完全相同。

五十二、Touch Sensor 適合做 Slider 嗎?

可以。

Espressif 官方說明,多個 Touch Sensing Pad 可以排列成:

Matrix
Slider

等不同形式。

例如:

T1  T2  T3  T4  T5

[ ] [ ] [ ] [ ] [ ]

手指由左向右移動:

T1
↓
T2
↓
T3
↓
T4
↓
T5

就能估算:

Finger Position

進一步做:

Volume Slider
Brightness Slider
Color Slider
Menu Slider
Motor Speed

五十三、Touch Sensor 和 TTP223 有什麼差別?

如果以前使用 Arduino UNO,可能接觸過:

TTP223

這是一顆外部 Capacitive Touch Sensor IC / Module。

它通常把 Touch 事件轉成:

HIGH
LOW

所以 Arduino 只需要:

digitalRead();

ESP32 原生 Touch 則是:

Touch Electrode
↓
ESP32 Touch Peripheral
↓
touchRead()

因此不一定需要額外 TTP223。

簡化比較:

ESP32 Native Touch 與 TTP223 比較
功能 ESP32 Native Touch TTP223
外部 Touch IC 不需要 需要
ESP32 原生支援 是 當一般數位輸入模組
讀值 Touch Value 通常 HIGH / LOW
Threshold 控制 軟體可自行設計 多由模組處理
多點設計 ESP32 可使用多個 Touch Channel 通常一模組一鍵
Arduino UNO 無內建同等 Touch Peripheral 可使用

所以對 ESP32 而言:

原生 Touch Sensor 是一項非常值得利用的特色周邊。

五十四、為什麼某些 Touch GPIO 數值特別不穩?

原因可能包括:

導線太長
Pad 太大
附近有 AC 電源
旁邊有高速數位訊號
USB 電源品質差
Wi-Fi / RF
PCB Layout 不理想
Threshold 太敏感

因此開發時不要只測:

桌上裸板

還應測試最終:

PCB
外殼
供電方式
Wi-Fi 開啟
實際使用者觸摸

環境。

Espressif 官方同樣建議 Threshold 應在實際應用條件下評估 Noise、電源與環境變化。

五十五、抗干擾的實用設計原則

對 Arduino-ESP32 入門專案,可以先採取:

1. Touch Pad 不要過度巨大

2. Touch 線不要不必要地拉很長

3. Touch 線避免貼著高頻訊號

4. 開機建立 Baseline

5. 多次取樣平均

6. Threshold 保留 Margin

7. 使用 Hysteresis

8. 加入 Touch Debounce

9. 實際外殼中重新校準

10. Wi-Fi 開啟狀態也要測試

如果進一步做到商用品質,

則應研究 Espressif 的:

Touch Sensor Driver
Filtering
Denoise
Shield
Waterproof
PCB Layout

等硬體與底層功能。

例如 ESP32-S2 / S3 的新一代 Touch Peripheral 提供更進階的 Filter、Denoise 與防水相關能力。

五十六、常見問題:touchRead() 完全沒反應

第一個要確認:

你的 ESP32 型號有沒有 Touch Peripheral?

Arduino-ESP32 官方明確提醒:

Touch Peripheral 並不存在於所有 ESP32 SoC。

第二個確認:

使用的 GPIO

是不是該 SoC 真正的 Touch GPIO。

不要拿任意 GPIO:

touchRead(18);

就期待一定可以工作。

五十七、常見問題:ESP32 Touch 時數值為什麼變小?

如果使用:

原始 ESP32(補充說明 2)

這是正常的。

官方 Touch Sensor Version 表顯示:

ESP32 Touch V1
↓
Touched
↓
Channel Value Decreases

所以:

value < threshold

代表 Touch。

五十八、常見問題:ESP32-S3 為什麼 Touch 時數值反而變大?

ESP32-S2 / ESP32-S3 使用:

Touch V2

官方說明:

Touch
↓
Channel Value Increases

所以判斷方向與原始 ESP32 相反。

因此:

value < threshold

這種原始 ESP32 程式不能不修改就直接套到 S3。

五十九、常見問題:Threshold 到底應該設定多少?

沒有通用數字。

不要認為:

Threshold = 30

或:

Threshold = 40

適合所有 ESP32。

正確方法:

量 Baseline
↓
量 Touch Value
↓
觀察 Noise
↓
設定安全 Threshold

官方文件也是建議先利用實際 Touch Measurement 找出 Touched 與 Untouched 狀態後再建立 Threshold。

六十、常見問題:為什麼 Touch 開關一次會切換很多次?

通常不是 Touch Sensor 被「按很多次」。

而是程式寫成:

if (touched)
{
  ledState =
    !ledState;
}

手指停留期間:

loop()

會一直執行。

解決方法是使用:

Edge Detection

只在:

Released
↓
Touched

那一刻處理一次。

也就是:

if (
  isTouched
  &&
  !wasTouched
)

六十一、常見問題:Touch 誤觸很多

依序檢查:

Threshold
↓
Touch Pad
↓
線長
↓
Noise
↓
電源
↓
Filtering
↓
Hysteresis
↓
PCB / 外殼

通常第一個要做的不是:

換 ESP32

而是先把:

Touch Value

連續印到 Serial Monitor,

觀察真正的:

Baseline
Noise Range
Touched Range

再決定 Threshold。

六十二、常見問題:Touch Pad 一定要直接碰金屬嗎?

不一定。

Capacitive Touch 的原理是:

Capacitance Change

因此適當設計下可以隔著:

塑膠
玻璃
壓克力
面板

感應。

但材料厚度增加時,

Touch Signal 可能變小,

所以需要重新調整:

Pad Size
Threshold
Sensitivity

六十三、常見問題:Touch Pad 可以做成很大的金屬片嗎?

可以增大感應面積,但:

越大

不代表:

一定越好

因為更大的 Pad 也會改變:

Base Capacitance
Noise
Sensitivity
Environmental Coupling

因此 Touch Pad 應配合實際:

外殼
PCB
使用者手指
環境

一起設計。

六十四、ESP32 Touch 可以應用在哪些專題?

學完本章後可以做:

1. Touch Light

手指 Touch
↓
LED ON / OFF

2. Touch Dimmer

短按
→ ON / OFF

長按
→ Brightness

3. RGB Touch Controller

Touch R
Touch G
Touch B
↓
RGB Mixing

4. Touch Doorbell

Touch
↓
Buzzer
↓
Wi-Fi Notification

5. Touch Menu

UP
DOWN
ENTER

6. Touch Slider

手指位置
↓
Brightness / Volume

7. Hidden Control Panel

塑膠外殼
↓
隱藏 Touch Electrode

8. Smart Home Panel

Touch
↓
ESP32
↓
Wi-Fi / MQTT
↓
Lighting / Relay

六十五、Touch + PWM + Wi-Fi 可以形成完整智慧燈

目前已經學過:

PWM
Touch

後續加入:

Wi-Fi

就可以變成:

手指 Touch
↓
ESP32 Touch
↓
燈光控制
↓
PWM Brightness

同時

Wi-Fi
↓
Web / MQTT
↓
遠端控制

也就是:

Local Control + Remote Control

這是實際智慧家庭裝置非常常見的架構。

六十六、本章正式實作一覽

基礎實作

ESP32 觸控式燈光開關(補充說明)

硬體:

GPIO27
↓
Touch Pad

GPIO18
↓
LED

流程:

touchRead()
↓
Threshold
↓
New Touch
↓
Toggle
↓
LED ON / OFF

進階實作

三鍵觸控控制 RGB LED(補充說明)

硬體:

GPIO32
→ RED Touch

GPIO33
→ GREEN Touch

GPIO27
→ BLUE Touch

輸出:

GPIO18
→ RGB Red

GPIO19
→ RGB Green

GPIO21
→ RGB Blue

架構:

Touch R ──┐
Touch G ──┼── ESP32 ── LEDC ── RGB LED
Touch B ──┘

六十七、FAQ:ESP32 Touch 常見問題

Q1:ESP32 有內建 Touch Sensor 嗎?

部分 ESP32 SoC 有。

原始 ESP32 具有 10 個 Capacitive Touch Channel,但 Arduino-ESP32 官方提醒 Touch Peripheral 並不是所有 ESP32 SoC 都具備,因此應確認實際晶片 Datasheet。

Q2:ESP32 Touch 使用什麼函式?

最基本:

touchRead(pin);

例如:

touchRead(27);

會取得該 Touch GPIO 的量測值。

Q3:原始 ESP32 有哪些 Touch GPIO?

原始 ESP32 包括:

GPIO4
GPIO0
GPIO2
GPIO15
GPIO13
GPIO12
GPIO14
GPIO27
GPIO33
GPIO32

共 10 個 Touch Channel。

Q4:Touch 時數值會增加還是下降?

這要看 ESP32 型號。

原始 ESP32
→ Touch 時下降

ESP32-S2 / S3
→ Touch 時上升

Q5:ESP32 Touch Threshold 要設多少?

沒有固定答案。

應先:

touchRead();

取得:

Untouched Value
Touched Value

再根據實際硬體設定 Threshold。Arduino-ESP32 官方也建議使用這種方式建立 Threshold。

Q6:Touch Sensor 可以隔著塑膠嗎?

Capacitive Touch 是利用電容量變化,不需要像機械開關一樣金屬直接導通,因此經過適當電極、外殼與 Threshold 設計後,可以製作隔著非導電面板操作的 Touch Interface。

Q7:Touch Sensor 為什麼會誤觸?

常見原因包括:

Noise
Threshold 太敏感
線路太長
Touch Pad 設計
Power Noise
外部環境

Espressif 官方建議在 Noise 較大時使用 Filtering,並根據實際環境重新評估 Touch Threshold。

Q8:ESP32 Touch 可以判斷長按嗎?

可以。

利用:

millis();

記錄:

Touch Down

到:

Release

的 Duration,

就可以區分:

Short Touch
Long Touch

Q9:ESP32 Touch 可以使用 Interrupt 嗎?

可以。

Arduino-ESP32 提供:

touchAttachInterrupt();

以及:

touchAttachInterruptArg();

Q10:Touch 可以喚醒 Deep Sleep 嗎?

支援 Touch Peripheral 的相關 ESP32 SoC 可利用 Touch Wake-up 功能;Arduino-ESP32 提供:

touchSleepWakeUpEnable();

但不同 SoC 的 Wake-up 能力與限制不同,應依所用晶片確認。

六十八、本章學習重點整理

第一個重點:

Capacitive Touch

並不是:

接點導通

而是:

手指
↓
Capacitance Change
↓
Touch Peripheral
↓
Touch Value Change

第二個重點:

最基本 API:

touchRead(
  pin
);

第三個重點:

對原始 ESP32:

未 Touch
→ Value 較大

Touch
→ Value 下降

對 ESP32-S2 / S3 則方向相反。

第四個重點:

Threshold 不要抄別人的數字。

應該:

Measure Baseline
↓
Measure Touch
↓
Observe Noise
↓
Choose Threshold

第五個重點:

正式 Touch 系統最好加入:

Average
+
Threshold Margin
+
Edge Detection
+
Hysteresis
+
Debounce

來降低 False Touch。

第六個重點:

Touch 不只是:

ON / OFF

還可以判斷:

Touch Down
Release
Short Touch
Long Touch
Multiple Touch Keys

第七個重點:

多個 Touch GPIO:

Touch R
Touch G
Touch B

搭配:

LEDC PWM

就可以製作:

三鍵 RGB Touch Controller

六十九、本章總結

在第 7 章中,我們正式學習 ESP32 很有代表性的硬體特色:

Capacitive Touch Sensor(補充說明)

它不需要傳統:

Push Button

而可以利用:

Copper Pad
Metal Plate
PCB Electrode

建立觸控式人機介面。

整個工作流程可以整理成:

Finger
↓
Capacitance Change
↓
ESP32 Touch GPIO
↓
touchRead()
↓
Touch Value
↓
Threshold
↓
Touch / Release
↓
Application

Espressif 官方說明,Touch Peripheral 會量測 Touch Channel 在固定時間中的充放電週期,手指所造成的等效電容變化會改變這個測量結果。

本章首先學會:

touchRead();

接著建立:

Baseline
Threshold

再加入:

Average
Hysteresis
Debounce
Edge Detection

提高 Touch 判斷的可靠度。

之後進一步利用:

millis();

區分:

Short Touch
Long Touch

並完成第一個正式實作:

ESP32 觸控式燈光開關(補充說明 2)

架構:

Touch Pad
↓
GPIO27
↓
touchRead()
↓
Threshold
↓
Touch Event
↓
LED ON / OFF

進階則完成:

三鍵觸控控制 RGB LED(補充說明 2)

架構:

GPIO32 Touch ──────┐
GPIO33 Touch ──────┼── ESP32
GPIO27 Touch ──────┘
                    │
                    ▼
                  LEDC
                    │
          ┌─────────┼─────────┐
          ▼         ▼         ▼
         Red       Green      Blue
          │         │         │
          └──────── RGB LED ──┘

因此從前面幾章開始,現在已經逐漸形成一套完整 ESP32 控制架構:

GPIO Output
+
GPIO Input
+
PWM
+
ADC
+
Touch

而 Touch Sensor 最重要的價值,就是讓 ESP32 能從一般:

機械式按鍵控制器

進一步變成:

無機械接點
平面式
隱藏式
智慧家電式

的人機控制介面。

接下來只要再加入:

OLED / LCD
Wi-Fi
Bluetooth
MQTT
Web Server

就可以把本章的三鍵 Touch Controller 發展成真正完整的:

ESP32 智慧觸控控制面板

下一步學習

不要停在這一篇,接著把內容做成自己的實作

目前主題:ESP32 / IoT。從完整學習路線、免費資源、會員下載,再接到實作所需材料。

同系列:ESP32 |  已是會員?直接前往 Getfile
相關資源與會員文章下載
文章可免費閱讀;下載完整 DOCX 或 PDF 需登入免費基本會員。
查看相關資源 會員免費下載 DOCX 會員免費 PDF/列印

← 回文章列表