ARDUINO Не могу остановить buzzer в будильнике

iamavasya

✩✩✩✩✩✩✩
6 Июн 2022
4
0
Всех приветствую! Делаю свой проект часов с мини-метеостанцией с лсд 1602. Уже который день меня мучает проблема, что при нажатии кнопки баззер не прекращает пищать. Время не идёт далее на экране. Я уже код переписывал, отпустил пока метеостанцию, только часы и баззер. Уже брал с нета разные коды, но всё равно. Хэээлп):cry:
Код:
// Підключення бібліотек
#include "LiquidCrystal_I2C.h"            // Екран
#include "Wire.h"                         // З'єднувальна бібліотека
#include <iarduino_RTC.h>                 // Годинник
// Визначення модулів і т.д.
iarduino_RTC time(RTC_DS1302, 8, 10, 9);  // Годинник
LiquidCrystal_I2C lcd(0x27, 16, 2);       // Екран

// Налаштування
int alarm_time_h = 17;                    // Година будильника
int alarm_time_m = 37;                    // Хвилина будильника

bool alarm_flag;

void timer_screen1(){
  if(millis()%1000==0) {                // в 1 секунду 
    lcd.setCursor(4, 0);
    lcd.print(time.gettime("H:i:s"));   // вивід часу
    lcd.setCursor(0, 1);
    lcd.print(time.gettime("D, d-m-Y"));
    //delay(1);                           // тут питання
    }
      if(time.seconds==00){                  // если в текущем времени 0 секунд
        if(time.minutes==alarm_time_m){     // если совпали минуты
          if(time.Hours==alarm_time_h){    // если совпали часы
            alarm_flag=true;            // устанавливаем флаг разрешающий совершение действий будильника (сигнализация)
          }
        }
      }
      else {alarm_flag=false;}            // если будильник выключен, то сбрасываем флаг разрешающий совершение действий будильника (сигнализация)
    if(alarm_flag){Func_alarm_action();}// запускаем действия будильника
  button_control();                    // передаём управление кнопкам
    } 


bool butt_flag = 0;

bool butt;


void setup() {
  Serial.begin(9600);
  pinMode(3, INPUT_PULLUP);
  pinMode(4, OUTPUT);
  lcd.begin(16, 2);
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Meteostat v.2.2");
  lcd.setCursor(0, 1);
  lcd.print("beta by R and A");
  tone(4, 1000);
  delay(100);
  tone(4, 1500);
  delay(100);
  noTone(4); 
  delay(150);
  tone(4, 2000);
  delay(200);
  noTone(4);
  lcd.clear();
  time.begin();

}

void loop() {
  timer_screen1();

}

void button_control(){
  butt = !digitalRead(3);
  if (butt == 1 && butt_flag == 0) {
    butt_flag = 1;
    alarm_flag = 0;
    Serial.println("(butt == 1 && butt_flag == 0)");
    }
  if (butt == 0 && butt_flag == 1) {
    butt_flag = 0;
    alarm_flag = 0;
    Serial.println("(butt == 0 && butt_flag == 1)");
    }
  if (butt == 1 && butt_flag == 1) {
    alarm_flag = 0;
    Serial.println("(butt == 1 && butt_flag == 1)");
    }
  }

void Func_alarm_action(){
    tone(4, 2000); delay(100); noTone(4); delay(100);
    tone(4, 2000); delay(100); noTone(4); delay(100);
    tone(4, 2000); delay(100); noTone(4);
}
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,262
1,300
Москва
Судя по логике - должно выключаться, почти!
Цикл луп тут крутиться довольно шустро, вы правильно выводите данные раз в секунду.
Но теперь смотрим:
Допустим что будильник стоит на 10 часов ровно.
При переходе с 9:59:59 на 10:00:00 выполниться условие и запуститься будильник. И он еще будет запускаться 100 000 (на самом деле меньше!) раз за это время. Вернее столько же раз, сколько в цикле loop будет проходить сравнение.
Далее вызывается пиликантье: Func_alarm_action. Относительно всего цикла эта функция будет занимать довольно продолжительное время - 0,5 секунды. И далее проверяется кнопка. И получается, что на проверку кнопки без вывода данных уходит 1/100000 секунды и 0.5 секунды на звук. Т.е. кнопку надо нажать а) спустя 1 секунду от начала и б) продержать ее минимум 0.5 секунды, а не просто нажать. Тогда должна сработать отмена будильника

Сделать проигрывание звука в фоновом режиме не самая простая задача, но ни не самая сложная, возможно есть и библиотеки, но для решения вполне достаточно запустить обработку нажатия пина 3 по прерыванию.
 
  • Лойс +1
Реакции: iamavasya

bort707

★★★★★★✩
21 Сен 2020
3,058
910
Вася
Уточните, после срабатывания будильника он звонит вечно или отзвонит свое время и выключится сам?
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,262
1,300
Москва
@bort707, А кстати да, сразу не заметил, как только секунды сменяться с 0 на что то другое он должен выключиться, т.е. должен пиликнуть только 2 раза
 

iamavasya

✩✩✩✩✩✩✩
6 Июн 2022
4
0
@bort707, нет, он дальше крутит. только ресет в помощь

б) продержать ее минимум 0.5 секунды, а не просто нажать
да, Я перепробовал эти варианты, даже просто зажал от начала. как вы думаете, какой исход?

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

Старик Похабыч

★★★★★★★
14 Авг 2019
4,262
1,300
Москва
Предлагаю пока все оставить как есть кроме функции будильника. Сделать так:
условие включения:
если секунды==0 и минуты ==заданному и часы== заданному, то флаг_аларма=истина. // при полном совпадении выключить будильник
если минуты!=заданному, то флаг_аларма=фальш. // выключение происходит автоматом через минуту.
все это вынести в отдельную функции и добавить ее в цикл луп.
При этом делать эту проверку не чаще чем раз в пол секунды. Т.е. в начале функции написать такое:
C++:
  static uint32_t tmr = millis();
  if (millis() - tmr < 500) return;
  tmr = millis();
Далее, пищалку тоже оформить в виде отдельной функции и ее проверять раз в секунду.
C++:
  static uint32_t tmr = millis();
  if (millis() - tmr < 1000) return;
  tmr = millis();
а звук давать командой
tone(4,2000,500);
где 500 - длительность сигнала в пол секунды, т.е. получиться чередования пол секунды звука - пол секунды тишины, но не нужно будет писать задержку и noTone
Ну естественно перед тем как давать звук надо проверить стоит ли флаг будильника.

Это что касается включения.

Кнопки:
Вашу button_control
вынесите в цикл loop , ей там самое место.
у кнопки есть 2 состояния, нажатое и нет. Т.к. для выключения мы будем ловить нажатое состояние, то предыдущее состояние можно не ловить.
Соотв. если кнопка подтянута к +, то нажатое будет 0
Значит:
если дигиталРид(кнопка)==0 , то аларм_флак=фальш.

Т.к. не знаю полной идеи и для чего еще нужна будет кнопка, то для данной задачи этого хватит
 
Изменено:
  • Лойс +1
Реакции: iamavasya

Старик Похабыч

★★★★★★★
14 Авг 2019
4,262
1,300
Москва

iamavasya

✩✩✩✩✩✩✩
6 Июн 2022
4
0
понял, у меня еще один вопрос, это уже с метео + переход страницы, но это позже, а пока благодарю! Лучший!

Нет, по крайней мере с вашими поправками всё уладилось. Благодарю!