Чтобы просто заработало, можно добавить ключевое слово
static
перед
uint32_t dxfa2se;
, но как уже сказали выше, качество кода не на высоте. И вот почему.
Функцию
aTimer
нельзя будет использовать для разных таймеров, так как она использует глобальную переменную
aTimerBool
и не понятно, к какому таймеру ее значение относится. Название функций и переменных просто плохое - не понятно, что они означают. Вообще, правильно выбранные названия - это залог успеха, они вносят ясность, внушают оптимизм и пользователь библиотеки обязательно скажет тебе за это спасибо. Функция
aDelay
вообще не используется и не понятно, зачем нужна.
Попробуем улучшить твою библиотеку. Во-первых, поменяем название функции
aTimer
. Для этого зададим вопрос: что она делает? По идее, она проверяет, не прошел ли определенный промежуток времени со времени последнего срабатывания таймера, и если прошёл, то считаем, что таймер снова сработал. Теперь надо перевести это на английский и постараться, чтобы получилось не слишком длинно. Я плохо придумываю названия, поэтому пусть будет
trigger_if_passed
.
Дальше, так как мы хотим знать, сработал ли снова таймер, то пусть она возвращает
bool
.
И наконец, если мы хотим, чтобы можно было использовать в программе несколько таймеров, нужно указать, какой таймер мы имеем в виду. Таким образом, мы получаем функцию
bool trigger_if_passed(uint32_t interval, timer_t *timer);
Что такое
timer_t
? Это тип, в котором мы будем хранить информацию о таймере. Почему мы передаем в функцию ссылку на таймер
timer_t *timer
, а не сам таймер? Потому что при передаче в функцию таймера создается его локальная копия, что делает невозможным его изменение внутри функции.
Пришло время определить
timer_t
. О таймере нам нужно знать только время его последнего срабатывания (достаточно
uint32_t
), поэтому можно определить его как
typedef uint32_t timer_t;
. Но если таймер должен срабатывать через одинаковые промежутки времени, то лучше размер этих промежутков сделать свойством таймера и хранить в нем. Тогда таймер можно определить как
typedef struct {
uint32_t last_trigger_time; // время последнего срабатывания
uint32_t interval; // интервал
} timer_t;
// Тогда объявление функции можно переписать так. Я поменял заодно название, оно мне показалось лучше.
bool timer_is_triggered(timer_t *timer);
Теперь можно реализовать функцию
timer_is_triggered
.
bool timer_is_triggered(timer_t *timer) {
uint32_t now = millis(); // текущее время
if (timer->last_trigger_time + timer->interval > now) { // если со времени последнего срабатывания прошло больше, чем `interval`
timer->last_trigger_time = now; // обновляем время последнего срабатывания
return true;
} else {
return false;
}
}
Тут можно заметить, что
timer->last_trigger_time + timer->interval
почти все время будет одинаковым и по сути означает время следующего срабатывания триггера, поэтому чтобы не делать каждый раз это вычисление, можно хранить его вместо времени последнего срабатывания. Итого получаем
typedef struct {
uint32_t next_trigger_time;
uint32_t interval;
} timer_t;
bool timer_is_triggered(timer_t *timer) {
uint32_t now = millis();
if (timer->next_trigger_time > now) {
timer->next_trigger_time = now + timer->interval;
return true;
}
return false;
}
И пример использования:
#include "timer_lib.h"
timer_t led_timer;
void setup() {
led_timer = {
.next_trigger_time = 0,
.interval = 1000
};
// прочая инициализация
}
void loop() {
if (timer_is_triggered(&led_timer)) { // если таймер сработал
// меняем состояние светодиода
}
}
Чтобы сделать код еще лучше, можно воспользоваться средствами языка C++ и объявить таймер как класс, но это уже другая история.