W tym poście chciałbym opisać sposób wykonania przycisku dotykowego na ESP32.
[Źródło: http://paulobrien.co.nz/2017/03/16/esp32-programming-with-arduino-on-windows/]
ESP32 zawiera 10 pinów, które można przygotować jako czujnik pojemnościowy.
- TOUCH0 - GPIO4
- TOUCH1 - GPIO0
- TOUCH2 - GPIO2
- TOUCH3 - GPIO15
- TOUCH4 - GPIO13
- TOUCH5 - GPIO12
- TOUCH6 - GPIO14
- TOUCH7 - GPIO27
- TOUCH8 - GPIO33
- TOUCH9 - GPIO32
W celu odczytu danych z pinu pojemnościowego wykorzystuje się jedną funkcję w Arduino IDE tj. touchRead(PIN_NUMBER)
Funkcja opisana w bibliotece wygląda następująco:
- extern uint16_t touchRead(uint8_t pin) __attribute__ ((weak, alias("__touchRead")));
- uint16_t __touchRead(uint8_t pin)
- {
- int8_t pad = digitalPinToTouchChannel(pin);
- if(pad < 0){
- return 0;
- }
- pinMode(pin, ANALOG);
- __touchInit();
- uint32_t v0 = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
- //Disable Intr & enable touch pad
- WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG,
- (v0 & ~((1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | (1 << (pad + SENS_TOUCH_PAD_OUTEN1_S))))
- | (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
- SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG, (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
- uint32_t rtc_tio_reg = RTC_IO_TOUCH_PAD0_REG + pad * 4;
- WRITE_PERI_REG(rtc_tio_reg, (READ_PERI_REG(rtc_tio_reg)
- & ~(RTC_IO_TOUCH_PAD0_DAC_M))
- | (7 << RTC_IO_TOUCH_PAD0_DAC_S)//Touch Set Slope
- | RTC_IO_TOUCH_PAD0_TIE_OPT_M //Enable Tie,Init Level
- | RTC_IO_TOUCH_PAD0_START_M //Enable Touch Pad IO
- | RTC_IO_TOUCH_PAD0_XPD_M); //Enable Touch Pad Power on
- //force oneTime test start
- SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
- SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_XPD_WAIT, 10, SENS_TOUCH_XPD_WAIT_S);
- while (GET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_MEAS_DONE) == 0) {};
- uint16_t touch_value = READ_PERI_REG(SENS_SAR_TOUCH_OUT1_REG + (pad / 2) * 4) >> ((pad & 1) ? SENS_TOUCH_MEAS_OUT1_S :SENS_TOUCH_MEAS_OUT0_S);
- //clear touch force ,select the Touch mode is Timer
- CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
- //restore previous value
- WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, v0);
- return touch_value;
- }
Kolejna funkcja to touchSetCycles:
- void __touchSetCycles(uint16_t measure, uint16_t sleep)
- {
- __touchSleepCycles = sleep;
- __touchMeasureCycles = measure;
- //Touch pad SleepCycle Time
- SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_SLEEP_CYCLES, __touchSleepCycles, SENS_TOUCH_SLEEP_CYCLES_S);
- //Touch Pad Measure Time
- SET_PERI_REG_BITS(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_MEAS_DELAY, __touchMeasureCycles, SENS_TOUCH_MEAS_DELAY_S);
- }
Ustawia ona odpowiednie wartości w polach kontrolnych interfejsu dotykowego.
Pierwszy parametr measure określa co jaki czas będzie wykonywany pomiar. Domyślnie ustawiona jest wartość 0x1000. Po jej zwiększeniu dłużej będzie przebiegała procedura obliczania wartości, co spowoduje otrzymaniem większych wyników i odwrotnie w przypadku jej zaniżenia. Drugi parametr określa ilość cykli uśpienia dla licznika.
Następna funkcja przypisuje przerwanie do podanego pinu dotykowego:
- void __touchAttachInterrupt(uint8_t pin, void (*userFunc)(void), uint16_t threshold)
- {
- int8_t pad = digitalPinToTouchChannel(pin);
- if(pad < 0){
- return;
- }
- pinMode(pin, ANALOG);
- __touchInit();
- __touchInterruptHandlers[pad] = userFunc;
- //clear touch force ,select the Touch mode is Timer
- CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL2_REG, SENS_TOUCH_START_EN_M|SENS_TOUCH_START_FORCE_M);
- //interrupt when touch value < threshold
- CLEAR_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_SEL);
- //Intr will give ,when SET0 < threshold
- SET_PERI_REG_MASK(SENS_SAR_TOUCH_CTRL1_REG, SENS_TOUCH_OUT_1EN);
- //Enable Rtc Touch Module Intr,the Interrupt need Rtc out Enable
- SET_PERI_REG_MASK(RTC_CNTL_INT_ENA_REG, RTC_CNTL_TOUCH_INT_ENA);
- //set threshold
- uint8_t shift = (pad & 1) ? SENS_TOUCH_OUT_TH1_S : SENS_TOUCH_OUT_TH0_S;
- SET_PERI_REG_BITS((SENS_SAR_TOUCH_THRES1_REG + (pad / 2) * 4), SENS_TOUCH_OUT_TH0, threshold, shift);
- uint32_t rtc_tio_reg = RTC_IO_TOUCH_PAD0_REG + pad * 4;
- WRITE_PERI_REG(rtc_tio_reg, (READ_PERI_REG(rtc_tio_reg)
- & ~(RTC_IO_TOUCH_PAD0_DAC_M))
- | (7 << RTC_IO_TOUCH_PAD0_DAC_S)//Touch Set Slope
- | RTC_IO_TOUCH_PAD0_TIE_OPT_M //Enable Tie,Init Level
- | RTC_IO_TOUCH_PAD0_START_M //Enable Touch Pad IO
- | RTC_IO_TOUCH_PAD0_XPD_M); //Enable Touch Pad Power on
- //Enable Digital rtc control :work mode and out mode
- SET_PERI_REG_MASK(SENS_SAR_TOUCH_ENABLE_REG,
- (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)) | \
- (1 << (pad + SENS_TOUCH_PAD_OUTEN2_S)) | \
- (1 << (pad + SENS_TOUCH_PAD_OUTEN1_S)));
- }
W jej wywołaniu należy zdefiniować pin wywołujący dane przerwanie, funkcję obsługującą oraz maksymalną wartość jaka może spowodować wywołanie przerwania.
Program:
Najprostszy program pozwalający na obsługę pinu dotykowego wygląda następująco:
W nim oprócz standardowego włączenia portu szeregowego pojawia się funkcja opisana powyżej, której zadaniem jest odczytanie danych z padu dotykowego.
- #define TOUCH_PIN_0 T0 //D4
- void setup() {
- Serial.begin(115200);
- delay(1000);
- Serial.println("ESP32 Test");
- }
- void loop() {
- Serial.println(touchRead(TOUCH_PIN_0));
- delay(1000);
- }
Pin można zdefiniować cyfrą np. dla portu dotykowego zero można wpisać 4 lub T0.
Przy przyłożeniu palca do pola dotykowego odczytana wartość pojemności ulega zmniejszeniu.
Ustawienie wywoływania przerwania odbywa się w następujący sposób:
- touchAttachInterrupt(TOUCH_PIN_0, &TestFunction, 40);
Ustawienie sposobu odliczania danych oraz opóźnienia:
- touchSetCycles(0x3000, 3000);
Drobna modyfikacja programu o opisane funkcje:
- #define TOUCH_PIN_0 T0 //D4
- void TestFunction()
- {
- Serial.println("Inter");
- }
- void setup() {
- Serial.begin(115200);
- delay(1000);
- Serial.println("ESP32 Test");
- touchSetCycles(0x3000, 3000);
- touchAttachInterrupt(TOUCH_PIN_0, &TestFunction, 40);
- }
- void loop() {
- Serial.println(touchRead(TOUCH_PIN_0));
- delay(1000);
- }
Dodatkowe materiały [1], [2].