Воспроизведение мелодии с Tone() без использования delay()

Есть ли способ воспроизвести мелодию с помощью Tone() без использования функции delay()?

tone(8, melody[thisNote], noteDuration);
int pauseBetweenNotes = noteDuration;
**delay(pauseBetweenNotes);**

, 👍2

Обсуждение

ДА. Тот же метод, что и в примере скетча BlinkWithoutDelay., @Majenko

Это можно сделать с помощью прерывания таймера. http://stackoverflow.com/questions/33051500/arduino-tone-without-delay/33052071#33052071, @Artium


4 ответа


0

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

https://learn.adafruit.com/multi-tasking-the-arduino-part-1/ditch-the-delay

,

4

Как уже отмечали другие, это можно сделать, используя тот же метод, что и в стандартном примере скетча "BlinkWithoutDelay", и сочетая его с подходом типа конечного автомата. В простом конечном автомате можно предположить, что вы можете находиться в одном из двух состояний: выводить тон и не выводить тон.

Применяя эти идеи к приведенному выше фрагменту кода:

// ПЕРЕД НАСТРОЙКОЙ
const int tonePin = 8;
unsigned long previousMillis = 0;
const long interval = pauseBetweenNotes;
const long interval = noteDuration;
boolean outputTone = false;                // Записывает текущее состояние


// В ЦИКЛЕ
unsigned long currentMillis = millis();

if (outputTone) {
// В настоящее время мы выводим тон
// Проверьте, достаточно ли долго это было, и выключите, если да
    if (currentMillis - previousMillis >= noteDuration) {
        previousMillis = currentMillis;
        noTone(tonePin);
        outputTone = false;
    }
} else {
// В настоящее время мы находимся в паузе
// Проверьте, достаточно ли долго это было, и включите, если это так
    if (currentMillis - previousMillis >= pauseBetweenNotes) {
        previousMillis = currentMillis;
        tone(tonePin, melody[thisNote]);
        outputTone = true;
    }
}
,

Работает только для одной задачи. Например, если лента работает параллельно, то возникнет шум., @Andrey Mihalev


1

Добавим немного к великому примеру кабдуллы, чтобы иметь возможность использовать MelodyArray

// объявление переменных
const int tonePin = 10;
unsigned long previousMillis = 0;
const long pauseBetweenNotes = 250;   // интервал между заметками (мс)
const long noteDuration = 400;        // (мс)
boolean outputTone = false;                // Записывает текущее состояние
const int MelodyLength = 2;
const int Melody[MelodyLength] = {880, 698};
int MelodyIndex = 0;
unsigned long currentMillis;



void setup() {
}

void loop() {
  currentMillis = millis();
  PlayMelody();
}

void PlayMelody() {
  if (outputTone) {
    // В настоящее время мы выводим тон
    // Проверьте, достаточно ли долго это было, и выключите, если да
    if (currentMillis - previousMillis >= noteDuration) {
      previousMillis = currentMillis;
      noTone(tonePin);
      outputTone = false;
    }
  } else {
    // В настоящее время мы находимся в паузе
    // Проверьте, достаточно ли долго это было, и включите, если это так
    if (currentMillis - previousMillis >= pauseBetweenNotes) {
      previousMillis = currentMillis;
      tone(tonePin, Melody[MelodyIndex]);
      outputTone = true;
      // Обновление для воспроизведения следующего тона в следующий раз
      MelodyIndex = MelodyIndex + 1;
      if (MelodyIndex >= MelodyLength) {
        MelodyIndex = 0;
      }
    }
  }
}
,

1

это минимальная модификация базового примера Arduino toneMelody в неблокирующую версию

#include "pitches.h"

// ноты в мелодии:
int melody[] = {
  NOTE_C4, NOTE_G3, NOTE_G3, NOTE_A3, NOTE_G3, 0, NOTE_B3, NOTE_C4
};

// длительность ноты: 4 = четверть ноты, 8 = восьмая нота и т.д.:
int noteDurations[] = {
  4, 8, 8, 4, 4, 4, 4, 4
};

unsigned long previousMillis = 0;
unsigned long pauseBetweenNotes;
int thisNote;

void setup() {
}

void loop() {

  // перебирать ноты мелодии:
  unsigned long currentMillis = millis();
  if (thisNote < 8 && currentMillis - previousMillis >= pauseBetweenNotes) {
    previousMillis = currentMillis;

    // чтобы рассчитать длительность ноты, возьмите одну секунду, разделенную на тип ноты.
    // например, четвертная нота = 1000/4, восьмая нота = 1000/8 и т.д.
    int noteDuration = 1000 / noteDurations[thisNote];
    tone(8, melody[thisNote], noteDuration);

    // чтобы различать ноты, установите минимальное время между ними.
    // длительность заметки + 30%, похоже, работает хорошо:
    pauseBetweenNotes = noteDuration * 1.30;
    
    thisNote++;
  }
}
,