ESP32 с FreeRTOS: Программные таймеры / Таймерные прерывания (Arduino IDE)

В этом руководстве вы узнаете, как использовать программные таймеры (таймерные прерывания) с ESP32, используя программирование FreeRTOS в Arduino IDE. Мы рассмотрим таймеры с автоперезагрузкой (периодические) и одноразовые таймеры, а также предоставим простые примеры, чтобы вы могли легко применить программные таймеры в своих собственных проектах. Вы увидите, что использование программных таймеров FreeRTOS значительно упрощает планирование различных задач в ваших проектах.

ESP32 FreeRTOS Программные таймеры, таймерные прерывания

Новичок в FreeRTOS? Вот другие руководства по FreeRTOS с ESP32, которые мы рекомендуем изучить:

Таймерные прерывания / Программные таймеры

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

Таймерные прерывания и программные таймеры

Программный таймер позволяет запланировать выполнение функции в определённый момент времени в будущем. Функция, которую вызывает таймер, известна как его функция обратного вызова (callback), а интервал от момента запуска таймера до выполнения callback-функции – это период таймера.

В FreeRTOS с ESP32 доступны два типа таймеров:

  • Периодический таймер (таймер с автоперезагрузкой): таймер, который будет срабатывать бесконечно каждые x секунд, которые вы определите. Это позволяет периодически выполнять задачу. Например, мигание светодиодом каждую секунду.

  • Одноразовый таймер (one-shot): таймер, который сработает один раз через заданный период. Это позволяет выполнить определённую задачу через заданное время. Например, включить светодиод через пять секунд после нажатия кнопки.

Основы таймеров FreeRTOS

Вот некоторые базовые концепции создания и управления таймерами FreeRTOS с ESP32 в Arduino IDE:

Создание таймера

Для создания таймера используется функция xTimerCreate(), которой передаются следующие параметры в качестве аргументов в указанном порядке:

  • имя таймера

  • период

  • autoReload (pdTRUE для периодического таймера или pdFALSE для одноразового таймера)

  • timerID (пользовательское значение, передаваемое в callback)

  • функция обратного вызова (callback)

Например:

xTimerCreate(
    "BlinkTimer",                   // Timer name
    1000 / portTICK_PERIOD_MS,      // 1s period
    pdTRUE,                         // Auto-reload (periodic timer)
    NULL,                           // Timer ID
    BlinkCallback                   // Callback function
);

Запуск таймера

Для запуска таймера используйте xTimerStart(timer, blockTime). Первый аргумент – это дескриптор таймера, а второй аргумент – количество секунд ожидания перед запуском таймера.

Остановка таймера

Для остановки работающего таймера просто вызовите xTimerStop(timer, blockTime). Аргументы те же, что и у предыдущей функции.

Сброс таймера

Для сброса таймера, что означает перезапуск обратного отсчёта, даже если он уже работает, вызовите xTimerReset(timer, blockTime). Аргументы те же, что и у предыдущих функций.

Запуск таймера в ISR (процедуры обработки прерываний)

Если вы хотите запустить таймер из ISR (функции обработки прерываний), следует вызвать xTimerStartFromISR(timer, &higherPriorityTaskWoken).

higherPriorityTaskWoken может быть pdTRUE или pdFALSE. Установите в pdTRUE, если задача имеет более высокий приоритет и мы должны немедленно переключиться на неё. В этом случае следует вызвать portYIELD_FROM_ISR() из ISR для немедленного переключения на эту задачу для обеспечения реального времени.


Периодический таймер FreeRTOS с ESP32 (Auto-Reload)

Теперь, когда мы изучили основы программных таймеров, начнём с тестирования простых примеров, чтобы показать, как создавать и управлять периодическими таймерами (с автоперезагрузкой) с ESP32 с использованием FreeRTOS в Arduino IDE.

Два светодиода, подключённые к ESP32 для тестирования программных таймеров FreeRTOS

1) Мигание светодиодом с периодическим таймером

Первый пример, который мы рассмотрим – это простой скетч мигания светодиодом. Этот скетч создаёт периодический таймер FreeRTOS для переключения состояния светодиода каждую секунду.

Это простой пример, который покажет вам, как использовать таймеры. Вот как это работает:

  1. Запуск таймера с периодом в одну секунду.

  2. После истечения периода таймера выполняется его callback-функция.

  3. Callback-функция переключает состояние светодиода (сначала включает его).

  4. После истечения периода таймера (одна секунда) callback-функция запустится снова, переключая состояние светодиода (на этот раз выключает его).

  5. Это будет повторяться бесконечно, пока программа не будет остановлена или пока вы не остановите таймер. Это создаст эффект мигания.

Схема подключения

Для этого примера мы будем мигать встроенным светодиодом ESP32. В нашем случае он подключён к GPIO 2. Другие платы ESP32 могут иметь встроенный светодиод, подключённый к другому GPIO.

В качестве альтернативы вы можете подключить физический светодиод через резистор 220 Ом к вашей плате.

Необходимые компоненты:

Схема подключения ESP32 к GPIO 2

Код

Следующий код использует периодические таймеры FreeRTOS для мигания встроенным светодиодом ESP32. Вы можете загрузить его на свою плату ESP32.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-freertos-software-timers-interrupts/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Arduino.h>

#define LED_PIN 2

TimerHandle_t blinkTimer = NULL;

bool ledState = false;

void BlinkCallback(TimerHandle_t xTimer) {
  ledState = !ledState;

  if (ledState) {
    digitalWrite(LED_PIN, HIGH);
    Serial.print("LED is ");
    Serial.println("ON");
  } else {
    digitalWrite(LED_PIN, LOW);
    Serial.print("LED is ");
    Serial.println("OFF");
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting FreeRTOS");
  Serial.println("Periodic Timer for LED Blink");

  pinMode(LED_PIN, OUTPUT);

  blinkTimer = xTimerCreate(
    "BlinkTimer",                   // Timer name
    1000 / portTICK_PERIOD_MS,      // 1s period
    pdTRUE,                         // Auto-reload (periodic timer)
    NULL,                           // Timer ID
    BlinkCallback                   // Callback function
  );
  if (blinkTimer == NULL) {
    Serial.println("Failed to create timer!");
    while (1);
  }

  xTimerStart(blinkTimer, 0); // Start timer immediately
}

void loop() {
  // Empty
}

Просмотреть исходный код

Как работает код?

Начните с определения GPIO, подключённого к светодиоду. Измените, если используете другой пин GPIO.

#define LED_PIN 2

Создайте дескриптор (handler) для таймера. Дескриптор – это как имя, которое мы используем для обращения к таймеру. Изначально мы устанавливаем его в NULL, потому что фактический таймер ещё не создан. Мы назовём дескриптор таймера blinkTimer.

TimerHandle_t blinkTimer = NULL;

Создайте переменную ledState для хранения текущего состояния светодиода. При первом запуске программы светодиод выключен (false).

bool ledState = false;

Callback-функция таймера

BlinkCallback – это функция, которую мы хотим запускать периодически. Она должна принимать параметр типа TimerHandle_t.

void BlinkCallback(TimerHandle_t xTimer) {
  ledState = !ledState;

  if (ledState) {
    digitalWrite(LED_PIN, HIGH);
    Serial.print("LED is ");
    Serial.println("ON");
  } else {
    digitalWrite(LED_PIN, LOW);
    Serial.print("LED is ");
    Serial.println("OFF");
  }
}

Сначала мы инвертируем текущее состояние светодиода:

ledState = !ledState;

Затем включаем или выключаем светодиод соответственно, используя функцию digitalWrite().

if (ledState) {
  digitalWrite(LED_PIN, HIGH);
  Serial.print("LED is ");
  Serial.println("ON");
} else {
  digitalWrite(LED_PIN, LOW);
  Serial.print("LED is ");
  Serial.println("OFF");
}

setup()

В setup() инициализируем Serial Monitor и настраиваем светодиод как OUTPUT.

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting FreeRTOS");
  Serial.println("Periodic Timer for LED Blink");

  pinMode(LED_PIN, OUTPUT);

Создание таймера

Затем создаём таймер blinkTimer, используя функцию xTimerCreate(), которую мы рассмотрели во вводном разделе. Этот таймер, после запуска, будет вызывать функцию BlinkCallback каждые 1000 миллисекунд (1 секунда).

blinkTimer = xTimerCreate(
  "BlinkTimer",                   // Timer name
  1000 / portTICK_PERIOD_MS,      // 1s period
  pdTRUE,                         // Auto-reload (periodic timer)
  NULL,                           // Timer ID
  BlinkCallback                   // Callback function
);

Мы также проверяем, был ли таймер успешно создан. Если создание не удалось, он вернёт NULL.

if (blinkTimer == NULL) {
    Serial.println("Failed to create timer!");
    while (1);
}

Запуск таймера

Наконец, мы можем запустить наш blinkTimer, вызвав функцию xTimerStart(). Таймер запустится немедленно (второй аргумент функции равен 0).

xTimerStart(blinkTimer, 0); // Start timer immediately

loop()

Функция loop() пуста, потому что планировщик FreeRTOS заботится о поддержании работы программы, ожидая таймерных прерываний и задач. Однако, если это необходимо для вашего проекта, вы можете добавить любой код в loop().

void loop() {
  // Empty
}

Демонстрация

Загрузите код на вашу плату ESP32.

Затем откройте Serial Monitor на скорости 115200 бод.

Встроенный светодиод ESP32 начнёт мигать каждую секунду (или светодиод, подключённый к GPIO 2).

Плата ESP32 со встроенным светодиодом -- включён Плата ESP32 со встроенным светодиодом -- выключен

Serial Monitor будет показывать текущее состояние светодиода (обратите внимание, что встроенный светодиод ESP32 работает с инвертированной логикой).

Serial Monitor показывает текущее состояние светодиода -- тестирование периодических таймеров FreeRTOS

Как видите, использование периодических таймеров FreeRTOS довольно простое, полезное и практичное в ваших проектах. Например, помимо мигания светодиодом, вы можете использовать их для периодических задач, таких как получение данных с датчика, отправка данных на сервер, запись данных на microSD-карту, проверка состояния входа и многое другое.

2) Мигание нескольких светодиодов с разной частотой

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

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

Схема подключения

Для этого примера подключите два светодиода к вашей плате ESP32 через резистор 220 Ом. Мы подключаем светодиоды к GPIO 2 и 4, но вы можете использовать любые другие подходящие пины. Просто убедитесь, что вы соответствующим образом изменили код.

Необходимые компоненты:

Схема подключения ESP32 к GPIO 2 и GPIO 4

Рекомендуемая статья: ESP32 Pinout Reference: Какие пины GPIO следует использовать?

Код

Загрузите следующий код на вашу плату ESP32.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-freertos-software-timers-interrupts/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#define LED_PIN_RED 2
#define LED_PIN_BLUE 4

TimerHandle_t blinkTimerRed = NULL;
TimerHandle_t blinkTimerBlue = NULL;

bool ledStateRed = false;
bool ledStateBlue = false;

void BlinkRedCallback(TimerHandle_t xTimer) {
  ledStateRed = !ledStateRed;

  if (ledStateRed) {
    digitalWrite(LED_PIN_RED, HIGH);
    Serial.print("Red LED is ");
    Serial.println("ON");
  } else {
    digitalWrite(LED_PIN_RED, LOW);
    Serial.print("Red LED is ");
    Serial.println("OFF");
  }
}

void BlinkBlueCallback(TimerHandle_t xTimer) {
  ledStateBlue = !ledStateBlue;

  if (ledStateBlue) {
    digitalWrite(LED_PIN_BLUE, HIGH);
    Serial.print("Blue LED is ");
    Serial.println("ON");
  } else {
    digitalWrite(LED_PIN_BLUE, LOW);
    Serial.print("Blue LED is ");
    Serial.println("OFF");
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting FreeRTOS");
  Serial.println("Periodic Timers for Two LEDs");

  pinMode(LED_PIN_RED, OUTPUT);
  pinMode(LED_PIN_BLUE, OUTPUT);

  blinkTimerRed = xTimerCreate(
    "BlinkTimerRed",               // Timer name
    700 / portTICK_PERIOD_MS,      // 1s period
    pdTRUE,                        // Auto-reload (periodic timer)
    NULL,                          // Timer ID
    BlinkRedCallback               // Callback function
  );
  if (blinkTimerRed == NULL) {
    Serial.println("Failed to create blinkTimerRed timer!");
    while (1);
  }

  blinkTimerBlue = xTimerCreate(
    "BlinkTimerBlue",               // Timer name
    1100 / portTICK_PERIOD_MS,      // 1s period
    pdTRUE,                         // Auto-reload (periodic timer)
    NULL,                           // Timer ID
    BlinkBlueCallback               // Callback function
  );
  if (blinkTimerBlue == NULL) {
    Serial.println("Failed to create blinkTimerBlue timer!");
    while (1);
  }

  xTimerStart(blinkTimerRed, 0); // Start timer immediately
  xTimerStart(blinkTimerBlue, 0); // Start timer immediately
}

void loop() {
  // Empty
}

Просмотреть исходный код

Как работает код?

Если вы поняли, как создать таймер в предыдущем примере, вы увидите, что создать несколько таймеров довольно просто.

Мы определяем GPIO для управления каждым из светодиодов.

#define LED_PIN_RED 2
#define LED_PIN_BLUE 4

Затем создаём дескриптор для каждого таймера. Каждый таймер будет управлять отдельным светодиодом.

TimerHandle_t blinkTimerRed = NULL;
TimerHandle_t blinkTimerBlue = NULL;

Мы создаём callback-функцию, которая будет вызываться после каждого срабатывания таймера для управления каждым из светодиодов.

void BlinkRedCallback(TimerHandle_t xTimer) {
  ledStateRed = !ledStateRed;

  if (ledStateRed) {
    digitalWrite(LED_PIN_RED, HIGH);
    Serial.print("Red LED is ");
    Serial.println("ON");
  } else {
    digitalWrite(LED_PIN_RED, LOW);
    Serial.print("Red LED is ");
    Serial.println("OFF");
  }
}

void BlinkBlueCallback(TimerHandle_t xTimer) {
  ledStateBlue = !ledStateBlue;

  if (ledStateBlue) {
    digitalWrite(LED_PIN_BLUE, HIGH);
    Serial.print("Blue LED is ");
    Serial.println("ON");
  } else {
    digitalWrite(LED_PIN_BLUE, LOW);
    Serial.print("Blue LED is ");
    Serial.println("OFF");
  }
}

В setup() мы фактически создаём таймеры для мигания каждым из светодиодов. Следующий таймер будет вызывать функцию BlinkRedCallback каждые 700 миллисекунд, что приведёт к переключению состояния красного светодиода каждые 700 миллисекунд.

blinkTimerRed = xTimerCreate(
  "BlinkTimerRed",                   // Timer name
  700 / portTICK_PERIOD_MS,      // 1s period
  pdTRUE,                         // Auto-reload (periodic timer)
  NULL,                           // Timer ID
  BlinkRedCallback                   // Callback function
);
if (blinkTimerRed == NULL) {
  Serial.println("Failed to create blinkTimerRed timer!");
  while (1);
}

Мы также создаём таймер для управления другим светодиодом. Этот таймер будет вызывать функцию BlinkBlueCallback каждые 1100 миллисекунд.

blinkTimerBlue = xTimerCreate(
  "BlinkTimerBlue",                   // Timer name
  1100 / portTICK_PERIOD_MS,      // 1s period
  pdTRUE,                         // Auto-reload (periodic timer)
  NULL,                           // Timer ID
  BlinkBlueCallback                   // Callback function
);
if (blinkTimerBlue == NULL) {
  Serial.println("Failed to create blinkTimerBlue timer!");
  while (1);
}

Наконец, мы можем запустить таймеры, вызвав функцию xTimerStart().

xTimerStart(blinkTimerRed, 0); // Start timer immediately
xTimerStart(blinkTimerBlue, 0); // Start timer immediately

Функция loop() пуста, потому что планировщик FreeRTOS позаботится о запуске таймеров в нужное время. При необходимости вы можете добавить код в loop() для любых других задач вашего проекта.

void loop() {
  // Empty
}

Демонстрация

Загрузите предыдущий код на вашу плату ESP32.

В результате два светодиода будут мигать с разной частотой.

ESP32 подключён к двум светодиодам, мигающим с разной частотой, используя программные таймеры ESP32 с двумя светодиодами -- примеры программных таймеров FreeRTOS

Вы также можете открыть Serial Monitor для проверки результатов.

Serial Monitor показывает состояние двух разных светодиодов -- тестирование нескольких таймеров FreeRTOS с ESP32

Одноразовые таймеры FreeRTOS с ESP32

Одноразовые таймеры вызывают callback-функцию один раз через заданный период. Это позволяет выполнить определённую задачу через заданное время.

ESP32 подключён к кнопке и светодиоду для тестирования одноразового таймера FreeRTOS

1) Переключение светодиода кнопкой (с задержкой)

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

Вот как это работает:

  • Светодиод выключен.

  • Нажмите кнопку.

  • Через 5 секунд светодиод включится.

  • Светодиод остаётся включённым.

  • Нажмите кнопку.

  • Через 5 секунд светодиод выключится.

Схема подключения

Для этого примера подключите светодиод и кнопку к GPIO ESP32. Мы подключаем светодиод к GPIO 2, а кнопку к GPIO 4. Мы не используем внешний резистор для кнопки, потому что будем использовать внутренний подтягивающий резистор ESP32.

Необходимые компоненты:

ESP32 подключён к кнопке и светодиоду -- схема подключения

Код

Загрузите следующий код на вашу плату ESP32.

/*
  Rui Santos & Sara Santos - Random Nerd Tutorials
  Complete project details at https://RandomNerdTutorials.com/esp32-freertos-software-timers-interrupts/
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#define BUTTON_PIN 4
#define LED_PIN 2
#define DEBOUNCE_DELAY 200
#define TIMER_DELAY 5000

TimerHandle_t toggleTimer = NULL;
volatile uint32_t lastInterruptTime = 0;
volatile bool ledState = false;

void IRAM_ATTR buttonISR() {
  uint32_t currentTime = millis();
  if (currentTime - lastInterruptTime > DEBOUNCE_DELAY) {
    BaseType_t higherPriorityTaskWoken = pdFALSE;
    xTimerStartFromISR(toggleTimer, &higherPriorityTaskWoken);
    Serial.print("buttonISR: LED will ");
    if (ledState) {
      Serial.print("turn OFF");
    } else {
      Serial.print("turn ON");
    }
    Serial.print(" in 5 seconds");
    Serial.println();
    lastInterruptTime = currentTime;
    if (higherPriorityTaskWoken) {
      portYIELD_FROM_ISR();
    }
  }
}

void ToggleCallback(TimerHandle_t xTimer) {
  ledState = !ledState;
  if (ledState) {
    digitalWrite(LED_PIN, HIGH);
    Serial.println("LED is ON");
  } else {
    digitalWrite(LED_PIN, LOW);
    Serial.println("LED is OFF");
  }
}

void setup() {
  Serial.begin(115200);
  delay(1000);
  Serial.println("Starting FreeRTOS");

  pinMode(BUTTON_PIN, INPUT_PULLUP);
  pinMode(LED_PIN, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, FALLING);

  toggleTimer = xTimerCreate(
    "ToggleTimer",                    // Timer name
    TIMER_DELAY / portTICK_PERIOD_MS, // 5s delay
    pdFALSE,                          // One-shot
    NULL,                             // Timer ID
    ToggleCallback                   // Callback
  );
  if (toggleTimer == NULL) {
    Serial.println("Failed to create timer!");
    while (1);
  }
}

void loop() {
  // Empty
}

Просмотреть исходный код

Как работает код

Начните с определения GPIO для светодиода и кнопки. Мы используем GPIO 2 и 4 соответственно. Вы можете использовать любые другие подходящие GPIO.

#define BUTTON_PIN 4
#define LED_PIN 2

Определите задержку дебаунса (подавления дребезга) для кнопки в миллисекундах.

#define DEBOUNCE_DELAY 200

Определите время задержки для одноразового таймера (время между нажатием кнопки и изменением состояния светодиода).

#define TIMER_DELAY 5000

Создайте дескриптор для нашего одноразового таймера. Мы назовём его toggleTimer.

TimerHandle_t toggleTimer = NULL;

Создайте переменную для проверки того, сколько времени прошло с момента последнего нажатия кнопки (для предотвращения ложных срабатываний).

volatile uint32_t lastInterruptTime = 0;

Создайте переменную ledState для хранения текущего состояния светодиода.

volatile bool ledState = false;  // Made volatile for ISR access

В setup() инициализируем Serial Monitor для отладки.

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

Устанавливаем кнопку как вход с внутренним подтягивающим резистором.

pinMode(BUTTON_PIN, INPUT_PULLUP);

Светодиод устанавливается как OUTPUT.

pinMode(LED_PIN, OUTPUT);

Затем устанавливаем кнопку как прерывание по спадающему фронту (FALLING). При нажатии кнопки будет вызвана функция buttonISR.

attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonISR, FALLING);

Создание одноразового таймера

Мы создаём наш одноразовый таймер toggleTimer, используя функцию xTimerCreate(). Обратите внимание, что мы установили 5-секундную задержку (второй аргумент), и что третий аргумент – pdFALSE, указывающий, что мы хотим установить одноразовый таймер, который сработает через 5 секунд после инициализации. Как видите, настроить одноразовый таймер довольно просто.

В данном случае при срабатывании будет вызвана функция ToggleCallback.

toggleTimer = xTimerCreate(
  "ToggleTimer",                  // Timer name
  TIMER_DELAY / portTICK_PERIOD_MS,  // 5s delay
  pdFALSE,                        // One-shot
  NULL,                           // Timer ID
  ToggleCallback                  // Callback
);
if (toggleTimer == NULL) {
  Serial.println("Failed to create timer!");
  while (1);
}

Функция buttonISR()

ISR (callback-функция) для кнопки – это функция buttonISR(). Сначала мы проверяем, является ли нажатие кнопки валидным.

void IRAM_ATTR buttonISR() {
  uint32_t currentTime = millis();
  if (currentTime - lastInterruptTime > DEBOUNCE_DELAY) {

Затем создаём и устанавливаем переменную higherPriorityTaskWoken в pdFALSE. Эта переменная сообщает нам, разблокировала ли операция ISR (в данном случае запуск таймера) задачу с более высоким приоритетом, которую нужно немедленно выполнить. Она начинается как false.

BaseType_t higherPriorityTaskWoken = pdFALSE;

Запуск таймера

Затем мы запускаем наш таймер, вызывая функцию xTimerStartFromISR. Мы передаём в качестве аргументов дескриптор таймера toggleTimer и адрес higherPriorityTaskWoken (&higherPriorityTaskWoken), чтобы FreeRTOS мог обновить флаг, если операция разблокирует задачу с более высоким приоритетом (например, служебную задачу таймера), позволяя нам проверить его далее (if (higherPriorityTaskWoken)) и при необходимости немедленно переключиться на эту задачу для обеспечения реального времени (portYIELD_FROM_ISR()).

xTimerStartFromISR(toggleTimer, &higherPriorityTaskWoken);

Запуская наш таймер, он выполнит функцию ToggleCallback через пять секунд (TIMER_DELAY). Функция ToggleCallback просто переключает текущее состояние светодиода.

void ToggleCallback(TimerHandle_t xTimer) {
  ledState = !ledState;
  if (ledState) {
    digitalWrite(LED_PIN, HIGH);
    Serial.println("LED is ON");
  } else {
    digitalWrite(LED_PIN, LOW);
    Serial.println("LED is OFF");
  }
}

Демонстрация

Загрузите код на вашу плату ESP32.

Откройте Serial Monitor на скорости 115200 бод.

Нажмите кнопку. В Serial Monitor вы получите сообщение: «buttonISR: LED will turn ON in 5 seconds».

Включение светодиода по нажатию кнопки с одноразовым таймером -- демонстрация Serial Monitor

И через пять секунд светодиод включится.

ESP32 подключён к светодиоду и кнопке для тестирования одноразовых таймеров FreeRTOS

Нажмите кнопку ещё раз, и через 5 секунд светодиод выключится.

Выключение светодиода по нажатию кнопки с одноразовым таймером -- демонстрация Serial Monitor

Заключение

В этом руководстве мы рассмотрели, как настроить и использовать программные таймеры FreeRTOS с ESP32, программируемым в Arduino IDE. Вы узнали о периодических и одноразовых таймерах.

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

Если вы хотите узнать больше о программировании FreeRTOS с ESP32, ознакомьтесь с другими нашими руководствами:

Хотите узнать больше об ESP32? Ознакомьтесь с нашими ресурсами:


Источник: Rui Santos & Sara Santos – Random Nerd Tutorials