Тон внутри прерывания

Я пытаюсь воспроизвести звук с помощью зуммера, подключенного к контакту arduino nano. Я также подключил геркон с INPUT_PULLUP на INT0 и светодиод. Программа непрерывно зацикливается (это персональный проект мониторинга окружающей среды и сигнализации), пока язычковый переключатель не будет установлен в положение ВЫСОКИЙ, когда вызывается функция, и зуммер должен воспроизводить односекундный сигнал высокого тона.

void doorStateChange() {
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > 1000)
  {
    led_B_state   = !led_B_state;
    digitalWrite(buzzPin, HIGH);
    digitalWrite(led_A_Pin, HIGH);

    if (millis() - interrupt_time <= 1000 ){
        digitalWrite(buzzPin, LOW);
        digitalWrite(led_A_Pin, LOW);
    }

  }
  last_interrupt_time = interrupt_time;
}

Вызывается прерывание, загорается светодиод, но я не могу правильно настроить зуммер. Я пробовал с tone(buzzPin, 5000, 1000);, но кажется, что задержка не работает - звук слышен, но после 1000 мс он продолжает работать в другом тоне (странно?) .

Единственный способ, с помощью которого я мог заставить это работать, — это использовать buzzPin_state = ! buzzPin_state; где зуммер издает звуковой сигнал, пока геркон находится в ВЫСОКОМ положении.

Я также должен сказать, что attachInterrupt(0, doorStateChange, CHANGE);.

Информация, которую я получаю при поиске в Google по этому вопросу, является тарабарщиной: некоторые говорят, что задержки не выполняются в прерываниях, другие вызывают внешние функции и т. д.

Каков правильный способ добиться этого?

, 👍0

Обсуждение

Можете ли вы дать более подробное описание того, что вы ожидаете и что происходит с этим кодом? Вы просто хотите подтянуть контакт зуммера к высокому нарастающему фронту (когда входной контакт переходит от низкого к высокому)?, @Anonymous Penguin

Я хочу перевести зуммер в положение «ИЗМЕНЕНИЕ» на одну секунду., @Radolino

Но тогда вам не нужен tone(), верно? (Подъем/изменение/падение в данном случае не имеют значения), @Anonymous Penguin

Я хотел услышать высокий тон, а не зуммер (звуковой сигнал) по умолчанию., @Radolino

Но дело не только в этом. Я не могу заставить его задержать тон на одну секунду. Это работает только в том случае, если состояние изменяется внутри функции прерывания, что означает, что звук длится столько, сколько на выводе геркона находится высокий уровень., @Radolino

Возможно, вам потребуется разрешить прерывания внутри функции. Попробуйте поместить sei(); в начале функции., @Gerben

Функция tone() инициализирует ШИМ на частоте и определяет количество переключателей, соответствующее желаемой длине. Наряду с инициализацией прерывания захвата вывода, чтобы оно совпадало с каждым переключением ШИМ. Где ISR PWM уменьшает этот счетчик. Следовательно, нахождение внутри другого ISR предотвратит ISR OCI (или PWM). Предложение Гербена о SEI() поможет. Но вы действительно должны написать ISR() или функции, вызываемые AttachInterrupt(), чтобы они не были ДЛИННЫМИ или блокирующими. ISR должны быть быстрыми., @mpflaga

@mpflaga хорошо понял, но я начинаю думать, что весь дизайн этой функции неверен., @Radolino


1 ответ


4

Не выполняйте вызовы delay() внутри ISR. По всей вероятности, он будет висеть бесконечно. Если вы хотите воспроизвести тон на секунду, все, что вам нужно сделать в ISR, это установить флаг, который вы проверяете в основном цикле. Включите зуммер, когда флаг изменит свое состояние. Вспомни, когда ты это сделал. По истечении секунды снова выключите зуммер.

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

,