Как предотвратить срабатывание будильника, который проверяет минуты, много раз в течение одной минуты?

rtc

Как предотвратить срабатывание будильника, который проверяет, совпадает ли текущее время с будильником в часах и минутах, более одного раза в течение одной минуты?

Я использую модуль DS3231 RTC и RTClib от adafruit. Я хочу проверить, равно ли текущее время времени будильника, а затем установить переменную alarmFlag. Я хочу очистить alarmFlag при нажатии кнопки на выводе D5.

Приведенный ниже код работает нормально до тех пор, пока я не нажму кнопку в течение примерно минуты с момента запуска будильника. Если я нажму кнопку в течение примерно минуты с начала будильника, alarmFlag будет равен 0 для одного цикла loop (), но затем (почти сразу, у меня не так много в loop()) вернется к 1. Я хочу, чтобы кнопка полностью остановила будильник, поэтому он снова срабатывает только на следующий день.

uint8_t alarm[2] = {19, 30}; // hour (24), minute

// other code ...

void loop() {

  currTime = rtc.now();

  // проверьте, совпадает ли текущее время со временем будильника
  // если он совпадает, он совпадает в течение целой минуты, что является проблемой здесь
  if (!alarmFlag && alarm[0] == currTime.hour() && alarm[1] == currTime.minute()) {
    alarmFlag = true;    
  }

  // clear alarmFlag on button press (это сокращенная версия, извините за отсутствие дебоунсинга/других вещей)
  if (digitalRead(5) == HIGH) {
    alarmFlag = false;
  }

} 

Примечания:

  1. Я не могу использовать встроенные сигналы тревоги RTC, потому что они нужны мне в другом месте.
  2. Я не хочу просто добавлять currTime.seconds() == 0 к первому оператору if, потому что это пропустит сигнал тревоги, если цикл loop() займет больше секунды.
  3. Я знаю, что способ обнаружения нажатия кнопки в примере кода неоптимален, я написал лучший способ справиться с этим в своем основном коде, но я не хочу загромождать этот вопрос.

, 👍2

Обсуждение

Вы пробовали добавить текущие секунды к вашему первому утверждению если? Что-то вроде этого: alarm[2] == currTime.seconds(). О, и, может быть, это тоже: uint8_t alarm[3] = {19, 30, 0};., @VE7JRO

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

Возможно, вы захотите прочитать о "конечных автоматах", потому что это то, что у вас есть здесь. Конечно, это действительно просто, но эти знания будут ценны в вашей будущей жизни разработчика. Вам понадобится как минимум 3 состояния: вооруженное, сработанное, приглушенное. Условия перехода и то, как его реализовать, остается для вас упражнением., @the busybee

Сделайте так, чтобы ваш "alarmFlag" имел три состояния: 0 для ложного, 1 для тревожного, 2 для приглушенного., @Dave X

@MarkLossner Но вы действительно сделали комментарий..., @the busybee


2 ответа


1

Как предположил the busybee, это хрестоматийное применение концепции конечного автомата. Ниже приведена диаграмма состояний, которая , как мы надеемся, отражает желаемое поведение. Его смысл, надеюсь , очевиден с первого взгляда.

State diagram

Здесь ваш alarmFlag заменяется ТРИГГЕРНЫМ состоянием. Обратите внимание , что с помощью этого конечного автомата единственный способ отключить сигнализацию-это нажать кнопку. Если рядом нет никого, кто мог бы на него надавить, это продолжается вечно. Такого рода проблемы вполне очевидны при взгляде на диаграмму состояний, а тем более при взгляде на код. Вот почему желательно нарисовать диаграмму состояний до того, как вы начнете кодировать. Если такое поведение нежелательно, вы можете добавить дополнительный переход из ЗАПУЩЕННОГО состояния, который произойдет во время тайм-аута.

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

Чтобы реализовать это в C++, я предлагаю вам следовать инструкциям этого руководства по конечным автоматам.

,

-1

Если вы добавите задержку(60*1000) к функции нажатия кнопки, то у вас, по сути, будет период охлаждения, прежде чем сигнал тревоги будет проверен снова. Сигнализация не может сработать снова во время этой задержки;

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

    //код для добавления к нажатию кнопки
    lastbuttonpress = millis();  

    //code to add before your alarm check
    if (lastbuttonpress - millis() > 60*1000) {
        //проверьте свою сигнализацию
    }
,

означает ли это, что вы не можете остановить будильник, пока он не пробежит одну минуту?, @Juraj

нет, сигнализация будет немедленно остановлена при нажатии кнопки. Эти рекомендации предотвращают повторное срабатывание будильника только в течение одной минуты после его отключения, @rfii

но время окончания проблемы известно, и зачем иметь 4-байтовую переменную вместо 1-байтового bool и ждать больше, чем необходимо, @Juraj