Внешние прерывания Esp32 иногда отсутствуют

Короче говоря. ESP32, два счетчика воды (горячей и холодной). Будка, горячая и холодная, некоторые прерывания пропущены. Когда я подключаю ESP32 к последовательному монитору и смотрю, то обнаруживаются все прерывания (около 5-10 минут). Но если я оставлю питание только на 5 В, то некоторые прерывания будут пропущены (за один день их может быть до 50 или даже больше).

О счетчике воды - один импульс на литр. Правильная информация о датчике содержится в оригинальной инструкции по эксплуатации в формате PDF. Here is image of technical info

Подключения датчиков. Коричневый провод к GND, белый к контакту 32(горячий),33(холодный).

Плата. Olimex ESP32-POE Rev C.

  • Питание от зарядного устройства Samsung 5 В (стандартное зарядное устройство 5 В без 9 В)
  • Включен Wi-Fi (для NTP и просмотра показаний счетчика)
  • Включено OTA
  • Запущенный веб-сервер (обычный html, ESPAsyncWebServer)
  • Bluetooth отключен
  • Подключена SD-карта (хранит только базу данных SQLite)
  • Использует библиотеку siara-cc/esp32_arduino_sqlite3_lib

Потребление воды в прошлом месяце (май)

  • горячая - 4777 литров (подсчитано с помощью датчика - 2675)
  • холод - 9289, с датчиком - 5528

Как мы видим, разница огромна. Может быть, время выполнения процедуры ISR слишком велико, и некоторые прерывания пропущены? Я знаю, что Wi-Fi тоже использует прерывания... Мой код прерывания неверен? Показания счетчика воды сохраняются в базе данных SQLite при использовании 10 литров. Заранее спасибо всем, кто уделил вам время!

Вот изображение счетчика воды и датчикаimage of water counter and sensor

Вот некоторый код, связанный с прерываниями (отладка отключена).

struct WaterCounter
{
  const uint8_t PIN; // microcontroller pin...
  volatile uint32_t liters_total; // max 4294967295
  volatile uint16_t liters_in_session; // max 65535
  volatile uint32_t session_started; // unix timestamp
  volatile uint32_t session_last_pulse; // unix timestamp
  const char display_name[5];
  volatile unsigned long pulse_start;
  volatile unsigned long pulse_stop;
  volatile uint32_t isr_prev_time;
  volatile uint32_t liters_last_written;
  volatile uint32_t liters_used_today;
};
WaterCounter wc_hot =  { PIN_WC_HOT, 0, 0, 0, 0, "Hott", 0, 0, 0, 0, 0 };
WaterCounter wc_cold = {PIN_WC_COLD, 0, 0, 0, 0, "Cold", 0, 0, 0, 0, 0 };
void IRAM_ATTR handle_wc(WaterCounter *wc)
{
  uint32_t  t = micros();
  uint32_t dt = t - wc->isr_prev_time;
  if (dt<1500) return;
  wc->isr_prev_time = t;
  if (wc->pulse_start == 0)
  {
    wc->pulse_start = millis();
    #ifdef DEBUG_ISR
      //Serial.printf("Started %s pulse!\n", wc->display_name);
      ets_printf("Started %s pulse!\n", wc->display_name);
    #endif
  }else
  {
    wc->pulse_stop = millis();
    unsigned long pulsew = wc->pulse_stop - wc->pulse_start;
    wc->pulse_start = 0;
    if (pulsew > 40 && pulsew < 55)
    {
      wc->liters_total++;
      wc->liters_in_session++;
      wc->liters_used_today++;
      if (wc->session_started == 0)
      {
        wc->session_started = now;
      }
      wc->session_last_pulse = now;
    }
    #ifdef DEBUG_ISR
      //Serial.printf("%s: pulse_width: %ld\n", wc->display_name, pulsew);
      ets_printf("%s: pulse_width: %ld\n", wc->display_name, pulsew);
    #endif
  }
}
void IRAM_ATTR isr_wc_cold()
{
  handle_wc(&wc_cold);
}

void IRAM_ATTR isr_wc_hot()
{
  handle_wc(&wc_hot);
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.println("Boot...");

  // allow some time to pull up pin, interrupt is attached below
  pinMode(wc_cold.PIN, INPUT_PULLUP);
  pinMode(wc_hot.PIN, INPUT_PULLUP);




  Serial.printf("Watchdog timeout: %dms\n", WATCHDOG_TIMEOUT);
  timerWD = timerBegin(0, 80, true);                  //timer 0, div 80
  timerAttachInterrupt(timerWD, &resetModule, true);  //attach callback
  timerAlarmWrite(timerWD, WATCHDOG_TIMEOUT * 1000, false); //set time in us
  timerAlarmEnable(timerWD); //enable interrupt
  timerWrite(timerWD, 0); //reset timer (feed watchdog)

  SD_MMC.begin();

  enqRC = sqlite3_initialize();
  if (enqRC == SQLITE_OK)
  {
    openDb();
    initSensorDatabase();
    timerWrite(timerWD, 0); //reset timer (feed watchdog)
    SetupWiFi();
    closeDb();
  }
  timerWrite(timerWD, 0); //reset timer (feed watchdog)
  pollNtp();
  timerWrite(timerWD, 0); //reset timer (feed watchdog)

  openDb();
  initTotalValues(&wc_cold);
  timerWrite(timerWD, 0); //reset timer (feed watchdog)
  initTotalValues(&wc_hot);
  closeDb();
  timerWrite(timerWD, 0); //reset timer (feed watchdog)

  attachInterrupt(digitalPinToInterrupt(wc_cold.PIN), &isr_wc_cold, FALLING); 
  attachInterrupt(digitalPinToInterrupt(wc_hot.PIN), &isr_wc_hot, FALLING); 

  timer_session = timerBegin(1, 80, true);
  timerAttachInterrupt(timer_session, &onSessionTimer, true);
  timerAlarmWrite(timer_session, 1000000, true); // every 1 second
  timerAlarmEnable(timer_session);

  EnableOTA();

  //* async web
  webServer.on("/", HTTP_GET, handleRootAsync);
  webServer.on("/heap", HTTP_GET, heapInfoAsync);
  webServer.on("/post", HTTP_POST, handlePostAsync);
  webServer.on("/params", HTTP_GET, handleParameterPage);
  webServer.onNotFound(onNotFoundAsync);
  webServer.begin();

  time(&now);
}

void loop() {
  // put your main code here, to run repeatedly:
  loop_task();
}
void loop_task()
{
  if (time_every_second <= now)
  {
    writeWcTotalToDb(&wc_cold);
    writeWcTotalToDb(&wc_hot);
    time_every_second = now + 1;
  }

  if (time_every_30_seconds <= now)
  {
    pollNtp();
    time_every_30_seconds = now + 30;
  }
}
void IRAM_ATTR finishSession(WaterCounter *wc, time_t tt)
{
  if (wc->session_started == 0)
  {
    return;
  }
  if (tt - wc->session_last_pulse > SESSION_LENGHT)
  {
    //finish session
    #ifdef DEBUG_ISR
      //Serial.printf("# %s liters in session: %d, duration %d(s)\n", wc->display_name, wc->liters_in_session, wc->session_last_pulse - wc->session_started);
      ets_printf("# %s liters in session: %d, duration %d(s)\n", wc->display_name, wc->liters_in_session, wc->session_last_pulse - wc->session_started);
    #endif

    wc->session_started = 0;
    wc->liters_in_session = 0;
  }
}

/* every 1s  */
void IRAM_ATTR onSessionTimer()
{
  timerWrite(timerWD, 0); //reset timer (feed watchdog)
  //ets_printf("\nonSessionTimer()\n");
  time(&now);
  getLocalTime(&timeinfo);
  strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%d %H:%M:%S", &timeinfo);
  if (now % 86400 == 75600) /* works if this function is called every second */
  {
    ets_printf("\n!!!midnight!!\n");
    wc_cold.liters_used_today = 0;
    wc_hot.liters_used_today = 0;
  }
  finishSession(&wc_cold, now);
  finishSession(&wc_hot, now);
}
void writeWcTotalToDb(WaterCounter *wc)
{
  #ifdef DEBUG_WRITE
    Serial.printf("writeWcTotalToDb(%s): begin\n", wc->display_name);
  #endif

  uint8_t ldiff = wc->liters_total - wc->liters_last_written;
  if (ldiff == 0)
  {
    #ifdef DEBUG_WRITE
      Serial.println("writeWcTotalToDb(): diff zero");
    #endif
    return;
  }
  if (ldiff <= LITERS_BEFORE_WRITE && wc->session_started > 0)
  {
    #ifdef DEBUG_WRITE
      Serial.println("writeWcTotalToDb(): ldiff <= LITERS_BEFORE_WRITE && wc->session_started > 0");
    #endif
    return;
  }
  #ifdef DEBUG_WRITE
    Serial.println("writeWcTotalToDb(): start writting procedure!");
  #endif
  if (!openDb())
  {
    char *sql = "INSERT INTO `water_counter` VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
    sqliteResultCode = sqlite3_prepare_v2(sqliteDb, sql, strlen(sql), &sqliteRes, NULL);
    if (sqliteResultCode != SQLITE_OK) 
    {
      #ifdef DEBUG
        Serial.printf("writeWcTotalToDb(): ERROR preparing sql: %d -> %s\n", sqliteResultCode, sqlite3_errmsg(sqliteDb));
      #endif
    }else
    {
      #ifdef DEBUG
        Serial.print("writeWcTotalToDb(): Prepare OK\n");
      #endif
      //getLocalTime(&timeinfo); // inside every 1 sec
      //strftime(timeStringBuff, sizeof(timeStringBuff), "%Y-%m-%d %H:%M:%S", &timeinfo);
      sqlite3_bind_int(sqliteRes, 1, now); // datums
      sqlite3_bind_int(sqliteRes, 2, wc->liters_total); 
      sqlite3_bind_text(sqliteRes, 3, timeStringBuff, strlen(timeStringBuff), SQLITE_STATIC);
      sqlite3_bind_text(sqliteRes, 4, wc->display_name, strlen(wc->display_name), SQLITE_STATIC);
      sqlite3_bind_int(sqliteRes, 5, 0);
      sqlite3_bind_int(sqliteRes, 6, wc->liters_in_session);
      sqlite3_bind_int(sqliteRes, 7, wc->session_started);
      sqlite3_bind_int(sqliteRes, 8, 0); /* currently not used */

      if (sqliteResultCode = sqlite3_step(sqliteRes) != SQLITE_DONE) 
      {
          #ifdef DEBUG
            Serial.printf("writeWcTotalToDb(): ERROR executing stmt: %d -> %s\n", sqliteResultCode, sqlite3_errmsg(sqliteDb));
          #endif
      }else
      {
          #ifdef DEBUG
            Serial.print("writeWcTotalToDb(): data saved!\n");
          #endif
          wc->liters_last_written = wc->liters_total;
          sqlite3_clear_bindings(sqliteRes);
          sqliteResultCode = sqlite3_reset(sqliteRes);
          if (sqliteResultCode != SQLITE_OK) 
          {
            #ifdef DEBUG
              Serial.printf("writeWcTotalToDb(): sqlite3_reset(res) result code = [%s] %s\n", sqliteResultCode, sqlite3_errmsg(sqliteDb));
            #endif
          }else
          {
            #ifdef DEBUG
              Serial.print("writeWcTotalToDb(): sqlite3_reset(res) OK\n");
            #endif
          }
          sqlite3_finalize(sqliteRes);
      }
    }
    closeDb();
  }else
  {
    #ifdef DEBUG
      Serial.println("writeWcTotalToDb(): Failed to open database!");
    #endif
  }
  #ifdef DEBUG_WRITE
    Serial.printf("writeWcTotalToDb(%s): finished!\n", wc->display_name);
  #endif
} /* writeWcTotalToDb() */

, 👍0

Обсуждение

Вы должны переключиться на использование периферийного устройства "счетчик импульсов" в ESP32. Подробнее читайте здесь: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html, @Majenko

Попробуем это завтра, @Guntis

@Majenko: можно ли это использовать с Arduino?, @dandavis

двоичный счетчик IC сделал бы надежность простой, но если есть встроенный счетчик,который мы можем использовать, это еще лучше., @dandavis

ДА. Arduino использовал IDF для управления чипом. Вы просто пропускаете слой Arduino и вызываете IDF напрямую., @Majenko

Я попробовал pcnt (с arduino). Он работает с одним входным контактом, но пока нет, я не могу работать с двумя разными входами (для каждого счетчика воды). Как я понял, я должен запустить два экземпляра pcnt.., @Guntis

Может быть, кто-то знает, как получить номер канала в обработчике pcnt_isr_register?, @Guntis


2 ответа


Лучший ответ:

1

Как и предполагал @Majenko, я создал решение со счетчиком импульсов.

Вот рабочий код, основанный на примере espressif PCNT. Студия Arduino, плата Olimex ESP32-POE.

Каждый счетчик воды использует отдельный блок счетчика импульсов. Сейчас я тестирую этот код и через несколько дней приму ответ, если все будет работать так, как я хочу :)

#include "freertos/queue.h"
#include "driver/pcnt.h"
#include "driver/periph_ctrl.h"
#include "driver/gpio.h"
#include "esp_attr.h"


#define PCNT_H_LIM_VAL      1
#define PCNT_L_LIM_VAL     -1
#define PCNT_THRESH1_VAL    0
#define PCNT_THRESH0_VAL   -0
#define PCNT_INPUT_SIG_WC_HOT   32 // hot water counter  
#define PCNT_INPUT_SIG_WC_COLD  33 // cold water counter
/*
Cold meter uses PCNT_UNIT_1
hot meter uses PCNT_UNIT_0
*/
xQueueHandle pcnt_evt_queue;   // A queue to handle pulse counter events
pcnt_isr_handle_t user_isr_handle = NULL; //user's ISR service handle



/* A sample structure to pass events from the PCNT
 * interrupt handler to the main program.
 */
typedef struct {
    pcnt_unit_t unit;  // the PCNT unit that originated an interrupt
    uint32_t status; // information on the event type that caused the interrupt
} pcnt_evt_t;

/* Decode what PCNT's unit originated an interrupt
 * and pass this information together with the event type
 * the main program using a queue.
 */
static void IRAM_ATTR pcnt_example_intr_handler(void *arg)
{
    uint32_t intr_status = PCNT.int_st.val;
    int i;
    pcnt_evt_t evt;
    portBASE_TYPE HPTaskAwoken = pdFALSE;

    for (i = 0; i < PCNT_UNIT_MAX; i++) {
        if (intr_status & (BIT(i))) {
            evt.unit = (pcnt_unit_t)i;
            /* Save the PCNT event type that caused an interrupt
               to pass it to the main program */
            evt.status = PCNT.status_unit[i].val;
            PCNT.int_clr.val = BIT(i);
            xQueueSendFromISR(pcnt_evt_queue, &evt, &HPTaskAwoken);
            if (HPTaskAwoken == pdTRUE) {
                portYIELD_FROM_ISR();
            }
        }
    }
}


/* Initialize PCNT functions:
 *  - configure and initialize PCNT
 *  - set up the input filter
 *  - set up the counter events to watch
 */
static void pcnt_example_init()
{
    //Serial.printf("pcnt_example_init(%d, %d)\n", _unit, _pin);
    /* Prepare configuration for the PCNT unit */
    pcnt_config_t pcnt_config = {};
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_HOT;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_0;

    /* Initialize PCNT unit */
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));


    /* cold water meter */
    pcnt_config.pulse_gpio_num = PCNT_INPUT_SIG_WC_COLD;
    pcnt_config.ctrl_gpio_num = PCNT_PIN_NOT_USED;
    pcnt_config.channel = PCNT_CHANNEL_0;
    pcnt_config.pos_mode = PCNT_COUNT_INC;
    pcnt_config.neg_mode = PCNT_COUNT_DIS;
    pcnt_config.lctrl_mode = PCNT_MODE_KEEP;//PCNT_MODE_REVERSE;
    pcnt_config.hctrl_mode = PCNT_MODE_KEEP;
    pcnt_config.counter_h_lim = PCNT_H_LIM_VAL;
    pcnt_config.counter_l_lim = PCNT_L_LIM_VAL;
    pcnt_config.unit = PCNT_UNIT_1;
    ESP_ERROR_CHECK(pcnt_unit_config(&pcnt_config));



    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_0, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_0));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_0, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_0, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_0));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_0));

    /* Register ISR handler and enable interrupts for PCNT unit */
    ESP_ERROR_CHECK(pcnt_isr_register(pcnt_example_intr_handler, NULL, 0, &user_isr_handle));
    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_0));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_0));




    /* PCNT_UNIT_1 configuration  */
    /* Configure and enable the input filter */
    ESP_ERROR_CHECK(pcnt_set_filter_value(PCNT_UNIT_1, 1000)); // filter_val is a 10-bit value, so the maximum filter_val should be limited to 1023.
    ESP_ERROR_CHECK(pcnt_filter_enable(PCNT_UNIT_1));

    /* Set threshold 0 and 1 values and enable events to watch */
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_1, PCNT_THRESH1_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_1));
    ESP_ERROR_CHECK(pcnt_set_event_value(PCNT_UNIT_1, PCNT_EVT_THRES_0, PCNT_THRESH0_VAL));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_THRES_0));
    /* Enable events on zero, maximum and minimum limit values */
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_ZERO));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_H_LIM));
    ESP_ERROR_CHECK(pcnt_event_enable(PCNT_UNIT_1, PCNT_EVT_L_LIM));

    /* Initialize PCNT's counter */
    ESP_ERROR_CHECK(pcnt_counter_pause(PCNT_UNIT_1));
    ESP_ERROR_CHECK(pcnt_counter_clear(PCNT_UNIT_1));

    ESP_ERROR_CHECK(pcnt_intr_enable(PCNT_UNIT_1));

    /* Everything is set up, now go to counting */
    ESP_ERROR_CHECK(pcnt_counter_resume(PCNT_UNIT_1));
}



void setup() {
  Serial.begin(115200);
  Serial.println("Boot...");
  // put your setup code here, to run once:
  pinMode(PCNT_INPUT_SIG_WC_HOT, INPUT_PULLUP);
  pinMode(PCNT_INPUT_SIG_WC_COLD, INPUT_PULLUP);
  /* Initialize PCNT event queue and PCNT functions */
  pcnt_evt_queue = xQueueCreate(10, sizeof(pcnt_evt_t));

  pcnt_example_init();
  //  pcnt_example_init(PCNT_UNIT_WC_HOT, PCNT_INPUT_SIG_WC_HOT);
    //pcnt_example_init(PCNT_UNIT_WC_COLD, PCNT_INPUT_SIG_WC_COLD);

    Serial.printf("Setup done\n");
}

int16_t count = 0;
pcnt_evt_t evt;
portBASE_TYPE res;

char * chToName(int ch)
{
  if (ch == 1) return "Cold";
  if (ch == 0) return "Hot";

  return "Unc";
}

void loop() {
  // put your main code here, to run repeatedly:
      /* Wait for the event information passed from PCNT's interrupt handler.
         * Once received, decode the event type and print it on the serial monitor.
         */
        res = xQueueReceive(pcnt_evt_queue, &evt, 1000 / portTICK_PERIOD_MS);
        if (res == pdTRUE) {
            pcnt_get_counter_value(evt.unit, &count);
            Serial.printf("Event PCNT unit[%d=%s]; cnt: %d, status: %d\n", evt.unit, chToName(evt.unit), count, evt.status);
            if (evt.status & PCNT_EVT_THRES_1) {
                Serial.printf("THRES1 EVT\n");
            }
            if (evt.status & PCNT_EVT_THRES_0) {
                Serial.printf("THRES0 EVT\n");
            }
            if (evt.status & PCNT_EVT_L_LIM) {
                Serial.printf("L_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_H_LIM) {
                Serial.printf("H_LIM EVT\n");
            }
            if (evt.status & PCNT_EVT_ZERO) {
                Serial.printf("ZERO EVT\n");
                // here we are increment liter count
            }
        } else {
            pcnt_get_counter_value(PCNT_UNIT_0, &count);
            Serial.printf("Current counter value: %s=%d,", chToName(PCNT_UNIT_0), count);
            pcnt_get_counter_value(PCNT_UNIT_1, &count);
            Serial.printf(" %s=%d\n", chToName(PCNT_UNIT_1), count);
            //pcnt_get_counter_value(PCNT_UNIT_WC_COLD, &count);
            //Serial.printf(", %d on unit: %d\n", count, PCNT_UNIT_WC_COLD);
        }    

        /*
        if(user_isr_handle) {
          Serial.printf("Clearing user_isr_handle\n");
          //Free the ISR service handle.
          esp_intr_free(user_isr_handle);
          user_isr_handle = NULL;
        }*/
} 
,

0

Вы можете использовать функцию счетчика импульсов(PCNT) в ESP32 для подсчета количества импульсов в фоновом режиме, также можно настроить событие,когда количество отсчетов достигло определенного порога и имело множество опций,

Для получения дополнительной информации и доступных интерфейсов и API для счетчика импульсов(PCNT), пожалуйста, перейдите по ссылке ниже, https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html

Первоначально я столкнулся с большой проблемой, чтобы заставить счетчик импульсов(PCNT) работать в IDE Adrino для ESP-32, После нескольких попыток я заставил его работать, И тот же пример кода загружен в GitHub для справки. Я не использовал все API в официальной документации, но использовал несколько из них и работаю..

Я создал простую примерную программу для расходомера воды, там же мы используем для получения импульса, который необходимо подсчитать для измерения расхода воды.

Путь к образцу кода на GitHub:- https://github.com/Embedded-Linux-Developement/Arduino_Sample_Programs/tree/main/ESP_32/Water_Flow_Pulse_counter_WithOut_Interrupt_Using_PCNT

Я не размещал код здесь, потому что он есть в GitHub и является сравнением, и я могу его использовать. Это рабочий код, который я тестировал в ESP32 HW.

Надеется, что Это поможет, С уважением, Джерри Джеймс

,