ESP32는 10개의 터치 센서를 제공하고 있으며 ESP32 아두이노 코어에서 제공하는 예제 스케치에서는 touchRead() 함수를 이용하는 방법과 터치 인터럽트를 이용하는 두 가지 방법을 예시하고 있습니다.
touchRead() 함수를 통해 터치센서의 값을 읽을 경우 터치 전 읽은 값은 범위는 보통 45 ~ 107 사이의 값이며 터치 시 값의 범위는 전원 종류에 따라 USB 5V 전원 일 경우 8 ~ 15 사이이고 5V 휴대용 배터리를 입력전원으로 사용하는 경우 대략 25 ~ 35 사이의 값입니다. touchRead() 함수 이용할 경우 직관적으로 값을 확인할 수 있어 좀 더 쉽게 코딩할 수 있으나 센서를 터치하지 않은 상태에서도 불규칙적으로 그 값이 0이 되거나 35 이하의 갑이 되는 경우가 있습니다. 값이 0인 경우는 아마도 touchRead() 함수가 정상적으로 값을 읽어오지 못한 것으로 생각됩니다. 이 현상으로 인해 만약 touchRead() 함수의 읽은 값이 35 이하일 경우 어떤 동작을 하도록 코딩하였다면 터치를 하지 않았음에도 불구하고 해당 코드가 실행되는 오류가 발생하게 됩니다. 따라서 이러한 오류 내포 문제로 터치센서를 단독으로 사용할 수가 없게 됩니다.
이를 해결하는 방법으로는 두 개의 터치센서의 값을 한 개의 그룹으로 묶어 두 개의 값이 모두 만족할 경우에만 어떤 동작을 하도록 코딩하는 것입니다. 터치센서 값이 0이 되는 오류는 불규칙 적일 뿐만 아니라 그 발생 빈도가 낮습니다. 따라서 두 개의 터치센서 값이 동시에 오류가 발생할 가능성을 현저하게 줄어들게 됩니다.
테스트 방법으로는 100밀리 초마다 touchRead() 함수가 두 개의 터치센서 값을 확인하고 그 값들이 35 이하의 조건을 만족할 경우 비프음이 울리도록 하였습니다.
타이머 및 인터럽트를 제어하는 Xtensa 컴포넌트를 활용한 인터럽트 예제 스케치에서는 Xtensa 인터럽트 코드가 보이지 않으므로 확인할 수는 없지만 인터럽트 코드 내의 touchRead() 함수가 실패 없이 값을 읽어오는 것으로 생각되어 이러한 문제가 해결된 것처럼 보이나 Xtensa 컴포넌트 역시 반복작업을 하도록 타이머를 세팅하고 touchRead() 함수를 실행하고 있을 것으로 예상되므로 장기간 테스트를 해보지 않는 이상 오류가 없다고 확신할 수는 없습니다. 또한 터치센서 이외의 인터럽트를 사용하고 있거나 하드웨어 타이머를 사용한 코드가 있다면 아래와 같은 오류가 발생할 수 있습니다.
"Guru Meditation Error: Core 1 panic'ed (Cache disabled but cached memory region accessed)"
아래 예제와 같이 인터럽트가 터치버튼 처리를 위해서만 사용되고 있을경우에는 오류가 발생하지 않았습니다.
결론적으로 만약 터치센서를 단독으로 사용하여 코딩한다면 인터럽트를 사용해야 하고 터치센서 이외의 하드웨어 타이머 및 인터럽트를 사용하는 경우에 캐시 접근 오류가 발생한다면 touchRead() 함수를 사용 해야 할 것입니다.
ESP32 터치센서
• T0: GPIO 4
• T1: GPIO 0
• T2: GPIO 2
• T3: GPIO 15
• T4: GPIO 13
• T5: GPIO 12
• T6: GPIO 14
• T7: GPIO 27
• T8: GPIO 33
• T9: GPIO 32
ESP32 터치센서 예제 스케치
아두이노 IDE에서 파일 > 예제 > ESP32 > Touch > TouchInterrupt & TouchRead
TouchRead 테스트용 스케치
1. esp32_touchRead_test.zip
int beepPin = 25;
void setup() {
Serial.begin(115200);
ledcSetup(0,1E5,12); // ESP32 톤전용 ledcSetup: ledcSetup(channel,1E5,12);
ledcAttachPin(beepPin,0); // ledcAttachPin(uint8_t pin, uint8_t channel);
}
bool beepOn = true;
bool beep = false;
//------------------------------------------------------------------------ 터치 버튼
#define TV 40 // touch value
#define LC 15 // long counter
unsigned long int touchInt = 0; // touch interval
void touch() { // 100 millis 마다 확인
uint8_t t1 = touchRead(14); // 터치전 값 약45~70사이 터치시 값 8~15 (USB 전원)
uint8_t t2 = touchRead(27); // 배터리 전원일경우 값 다름(터치시 값 25이상)
uint8_t t3 = touchRead(33);
uint8_t t4 = touchRead(32);
if (t1 < TV) { beep = true; Serial.print(F("touch: 1 - ")); Serial.println(t1);} // 버튼1
else if (t2 < TV) { beep = true; Serial.print(F("touch: 2 - ")); Serial.println(t2); }// 버튼2
else if (t3 < TV) { beep = true; Serial.print(F("touch: 3 - ")); Serial.println(t3); }// 버튼3
else if (t4 < TV) { beep = true; Serial.print(F("touch: 4 - ")); Serial.println(t4); }// 버튼4
if (beepOn && beep) { ledcWriteNote(0, NOTE_C, 3); }
}
//------------------------------------------------------------------------ 터치 버튼
void checkMillis() { // 100 millis 초마다 값 확인
if (millis() - touchInt > 100) {
touchInt = millis();
if (beep) { ledcWrite(0,0); beep = false; } // 비프음 종료
touch();
}
}
void loop() {
checkMillis();
}
시리얼 모니터 오류 메시지
2. esp32_touchRead_test_modi.zip(읽어온 값 중 0은 제거)
if (t1 == 0) t1 = 100; // 값이 0이면 touchRead()함수의 값 읽어오기 실패, 가끔씩 7 ~ 35 나옴
if (t2 == 0) t2 = 100;
if (t3 == 0) t3 = 100;
if (t4 == 0) t4 = 100;
3. esp32_touchRead_test_modi_group.zip(두 개의 터치센서를 그룹으로 묶음)
4. esp32_touchInterrupt_test.zip(인터럽트 이용)
터치센서 4개로 터치버튼 4개와 롱터치 구현
터치센서 4개를 사용하여 터치 버튼과 롱터치 버튼을 구현했습니다. 터치 버튼은 터치업시 트리거 되며 롱터치 버튼은 약 1초 동안 길게 누를 경우 트리거 됩니다.
esp32_touchInterrup4.zip
int beepPin = 25;
#define TV 35 // touch value
#define LC 10 // long counter
bool TC1 = false;
bool TC2 = false;
bool TC3 = false;
bool TC4 = false;
void gotTC1() { TC1 = true; }
void gotTC2() { TC2 = true; }
void gotTC3() { TC3 = true; }
void gotTC4() { TC4 = true; }
void setup() {
Serial.begin(115200);
ledcSetup(0,1E5,12); // ESP32 톤전용 ledcSetup: ledcSetup(channel,1E5,12);
ledcAttachPin(beepPin,0); // ledcAttachPin(uint8_t pin, uint8_t channel);
touchAttachInterrupt(T6, gotTC1, TV); // 14
touchAttachInterrupt(T7, gotTC2, TV); // 23
touchAttachInterrupt(T8, gotTC3, TV); // 33
touchAttachInterrupt(T9, gotTC4, TV); // 32
}
bool beepOn = true;
bool beep = false;
//------------------------------------------------------------------------ 터치 버튼
unsigned long int beepInt = 0; // BEEP OFF
unsigned long int touchInt = 0; // touch interval
unsigned long int touch_time = 0; // LOGN TOUCH 입력방지
uint8_t tcNum = 0;
uint8_t tcCount = 0;
bool tcLong = 0;
uint8_t tcLongNum = 0;
uint8_t orderNum = 0;
void touch() { // 50 millis 마다 확인
bool tcUp = false; bool pass = false;
if (orderNum > 6) pass = true;
orderNum = 0;
if (!pass) {
if (TC1) { // 버튼1
if (tcNum == 1) { if (tcCount < LC) tcCount++; }
else { tcNum = 1; tcCount = 0; }
} else if (TC2) { // 버튼2
if (tcNum == 2) { if (tcCount < LC) tcCount++; }
else { tcNum = 2; tcCount = 0; }
} else if (TC3) { // 버튼3
if (tcNum == 3) { if (tcCount < LC) tcCount++; }
else { tcNum = 3; tcCount = 0; }
} else if (TC4) { // 버튼4
if (tcNum == 4) { if (tcCount < LC) tcCount++; }
else { tcNum = 4; tcCount = 0; }
} else {
if (tcNum > 0) {
if (tcLong) {
if (tcLongNum != tcNum) { tcUp = true; tcCount = 0; tcLong = false; }
else { tcCount = 0; tcNum = 0; }
} else { tcUp = true; tcCount = 0; }
}
}
if (TC1) TC1 = false; if (TC2) TC2 = false; if (TC3) TC3 = false; if (TC4) TC4 = false;
if (tcNum > 0) {
if (tcUp) {
beep = true; orderNum = tcNum; tcNum = 0;
if (beepOn) { ledcWriteNote(0, NOTE_C, 3); beepInt = millis(); }
} else if (!tcLong && tcCount == LC) {
beep = true; tcLong = true; orderNum = tcNum + 6; tcLongNum = tcNum;
if (beepOn) { ledcWriteNote(0, NOTE_C, 4); beepInt = millis(); }
}
if (!tcLong) touch_time = millis();
}
if (orderNum > 0) {
if (orderNum == 1) Serial.println(F("touch: 1"));
else if (orderNum == 2) Serial.println(F("touch: 2"));
else if (orderNum == 3) Serial.println(F("touch: 3"));
else if (orderNum == 4) Serial.println(F("touch: 4"));
else if (orderNum == 7) Serial.println(F("touch Long: 1"));
else if (orderNum == 8) Serial.println(F("touch Long: 2"));
else if (orderNum == 9) Serial.println(F("touch Long: 3"));
else if (orderNum == 10) Serial.println(F("touch Long: 4"));
}
}
}
//------------------------------------------------------------------------ 터치 버튼
void touch_ini() { // 복수 입력 방지 -> long TOUCH
if (millis() - touch_time >= 1500) {
tcLong = false; tcLongNum = 0; tcCount = 0;
}
}
void touchMillis() { // 100 millis 초마다 값 확인
if (millis() - touchInt > 50) {
touchInt = millis();
touch();
}
}
void beepMillis() { // 100 millis 초마다 값 확인
if (millis() - beepInt > 100) {
beepInt = millis();
ledcWrite(0,0); beep = false;
}
}
void loop() {
touchMillis();
if (tcLong) touch_ini();
if (beepOn && beep) beepMillis();
}
터치센서 4개로 터치버튼 6개와 롱터치 구현
터치센서 4개를 사용하고 각각 터치센서 2개를 한 개의 그룹으로 묶으면 6개의 가짓수가 나옵니다. 이를 터치 PCB를 이용하여 터치 버튼과 롱터치 버튼을 구현했습니다. 터치 버튼은 터치업시 트리거 되며 롱터치 버튼은 약 1초 동안 길게 누를 경우 트리거 됩니다.
esp32_touchRead4-6.zip
int beepPin = 25;
#define TV 40 // touch value
#define LC 10 // long counter
void setup() {
Serial.begin(115200);
ledcSetup(0,1E5,12); // ESP32 톤전용 ledcSetup: ledcSetup(channel,1E5,12);
ledcAttachPin(beepPin,0); // ledcAttachPin(uint8_t pin, uint8_t channel);
}
bool beepOn = true;
bool beep = false;
//------------------------------------------------------------------------ 터치 버튼
unsigned long int beepInt = 0; // BEEP OFF
unsigned long int touchInt = 0; // touch interval
unsigned long int touch_time = 0; // LOGN TOUCH 입력방지
uint8_t tcNum = 0;
uint8_t tcCount = 0;
bool tcLong = 0;
uint8_t tcLongNum = 0;
uint8_t orderNum = 0;
void touch() { // 50 millis 마다 확인
bool tcUp = false; bool pass = false;
uint8_t t1 = 100, t2 = 100, t3 = 100, t4 = 100;
if (orderNum < 7) {
if (!tcNum) {
t1 = touchRead(14); // 터치전 값 약45~70사이 터치시 값 10~15 약1 ~ 4(USB 전원)
t2 = touchRead(27); // 배터리 전원일경우 값 다름(터치시 값 25이상)
t3 = touchRead(33);
t4 = touchRead(32);
if (t1 == 0) t1 = 100; // 값이 0이면 touchRead()함수의 값 읽어오기 실패, 가끔씩 10 ~ 30 나옴
if (t2 == 0) t2 = 100;
if (t3 == 0) t3 = 100;
if (t4 == 0) t4 = 100;
} else {
if (tcNum == 1) { t1 = touchRead(14); t2 = touchRead(27); }
else if (tcNum == 2) { t1 = touchRead(14); t3 = touchRead(33); }
else if (tcNum == 3) { t1 = touchRead(14); t4 = touchRead(32); }
else if (tcNum == 4) { t2 = touchRead(27); t3 = touchRead(33); }
else if (tcNum == 5) { t2 = touchRead(27); t4 = touchRead(32); }
else { t3 = touchRead(33); t4 = touchRead(32); }
}
} else pass = true;
orderNum = 0;
if (!pass) {
if (t1 < TV && t2 < TV) { // 버튼1
if (tcNum == 1) { if (tcCount < LC) tcCount++; }
else { tcNum = 1; tcCount = 0; }
} else if (t1 < TV && t3 < TV) { // 버튼2
if (tcNum == 2) { if (tcCount < LC) tcCount++; }
else { tcNum = 2; tcCount = 0; }
} else if (t1 < TV && t4 < TV) { // 버튼3
if (tcNum == 3) { if (tcCount < LC) tcCount++; }
else { tcNum = 3; tcCount = 0; }
} else if (t2 < TV && t3 < TV) { // 버튼4
if (tcNum == 4) { if (tcCount < LC) tcCount++; }
else { tcNum = 4; tcCount = 0; }
} else if (t2 < TV && t4 < TV) { // 버튼5
if (tcNum == 5) { if (tcCount < LC) tcCount++; }
else { tcNum = 5; tcCount = 0; }
} else if (t3 < TV && t4 < TV) { // 버튼6
if (tcNum == 6) { if (tcCount < LC) tcCount++; }
else { tcNum = 6; tcCount = 0; }
} else {
if (tcNum > 0) {
if (tcLong) {
if (tcLongNum != tcNum) { tcUp = true; tcCount = 0; tcLong = false; }
else { tcCount = 0; tcNum = 0; }
} else if (tcCount < 5) { tcUp = true; tcCount = 0; }
}
}
if (tcNum > 0) {
if (tcUp) {
beep = true; orderNum = tcNum; tcNum = 0;
if (beepOn) { ledcWriteNote(0, NOTE_C, 3); beepInt = millis(); }
} else if (!tcLong && tcCount == LC) {
beep = true; tcLong = true; orderNum = tcNum + 6; tcLongNum = tcNum;
if (beepOn) { ledcWriteNote(0, NOTE_C, 4); beepInt = millis(); }
}
if (!tcLong) touch_time = millis();
}
if (orderNum > 0) {
if (orderNum == 1) Serial.println(F("touch: 1"));
else if (orderNum == 2) Serial.println(F("touch: 2"));
else if (orderNum == 3) Serial.println(F("touch: 3"));
else if (orderNum == 4) Serial.println(F("touch: 4"));
else if (orderNum == 5) Serial.println(F("touch: 5"));
else if (orderNum == 6) Serial.println(F("touch: 6"));
else if (orderNum == 7) Serial.println(F("touch Long: 1"));
else if (orderNum == 8) Serial.println(F("touch Long: 2"));
else if (orderNum == 9) Serial.println(F("touch Long: 3"));
else if (orderNum == 10) Serial.println(F("touch Long: 4"));
else if (orderNum == 11) Serial.println(F("touch Long: 5"));
else if (orderNum == 12) Serial.println(F("touch Long: 6"));
}
}
}
//------------------------------------------------------------------------ 터치 버튼
void touch_ini() { // long TOUCH 복수 입력 방지 초기화
if (millis() - touch_time >= 1500) {
tcLong = false; tcLongNum = 0; tcCount = 0;
}
}
void touchMillis() { // 100 millis 초마다 값 확인
if (millis() - touchInt > 50) {
touchInt = millis();
touch();
}
}
void beepMillis() { // 100 millis 초마다 값 확인
if (millis() - beepInt > 100) {
beepInt = millis();
ledcWrite(0,0); beep = false;
}
}
void loop() {
touchMillis();
if (tcLong) touch_ini();
if (beepOn && beep) beepMillis();
}
esp32_touchInterrup4-6.zip
터치센서 7개로 터치키패드 구현
esp32_touchRead7-12.zip
esp32_touchInterrup7-12.zip
'Arduino' 카테고리의 다른 글
아두이노 - random() 함수 사용하기, 랜덤함수 (0) | 2019.10.06 |
---|---|
아두이노 - 무드등, 블루투스 연결 스마트폰 원격제어 (0) | 2019.10.05 |
ESP32 - 피에조 부저, 곰 세 마리 멜로디, tone() 대체 ledcWriteNote(), ledcWriteTone(), pitches.h 이용 (0) | 2019.10.04 |
ESP32 - PWM - analogWrite(), ledcWrite() - RGB LED 제어 (0) | 2019.10.03 |
아두이노 끼리 연결, 시리얼 통신을 통한 float 값 송신 및 수신 (6) | 2019.10.01 |
아두이노 - 무드등 예제, RGB LED 제어 (0) | 2019.09.28 |
아두이노 - ADC 핀을 이용한 터치 센서의 구현 (0) | 2019.09.24 |
아두이노 - 입력 버튼 설정 방법, debouncing (0) | 2019.09.21 |