Как использовать два пьезоэлемента одновременно?

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

//Левая рука
const int leftPin = 10; /Left pin
const int leftTones[] = {123.4, 103.83, 138.59, 92.50}; //Зацикливание левых тонов
const int leftDelays[] = {700, 1300, 900, 900}; //Как долго длятся эти сигналы
const int leftNotes = 4; //Сколько осталось нот

//Правая рука
const int rightPin = 2; //Правый штифт
const int rightTones[] = {739.99, 587.33, 587.33, 659.25, 698.46, //Циклические правые тона
659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 493.88, 
554.37, 587.33, 659.25, 587.33, 554.37, 880.00, 783.99, 739.99, 
587.33, 587.33, 659.25, 698.46, 659.25, 587.33, 554.37, 587.33, 
659.25, 739.99, 987.77, 987.77, 1108.73, 1174.66, 783.99, 739.99, 
698.46, 1174.66, 1318.51};
const int rightDelays[] = {700, 1000, 100, 100, 300, 300, 200, //Как долго длятся эти сигналы
300, 300, 200, 700, 700, 250, 150, 200, 400, 300, 300, 400, 200,
700, 1000, 100, 100, 300, 300, 200, 400, 300, 200, 700, 700, 300,
200, 400, 300, 200, 400, 300, 200};
const int rightNotes = 40; //Сколько правильных нот

void setup(){
    pinMode(leftPin, OUTPUT);
    pinMode(rightPin, OUTPUT);
    delay(1000);
}

void loop(){
  for (int i = 0; i < leftNotes; i++){
    tone(leftPin, leftTones[i]);
    delay(leftDelays[i]);
    noTone(leftPin);
  }
  for (int i = 0; i < rightNotes; i++){
    tone(rightPin, rightTones[i]);
    delay(rightDelays[i]);
    noTone(rightPin);
  }
}

При использовании этого кода сначала воспроизводится левый пьезоэлемент, а затем правый. Это должно быть одновременно.

Отредактированный код:

long currentMillis = 0;
long leftPreviousMillis = 0; // предыдущий раз для левой руки
long rightPreviousMillis = 0; // предыдущий раз для правой руки

const int leftNotes = 4; // Количество оставшихся нот
const int rightNotes = 40; // Количество правильных нот
int leftIndex = 0; // Конкретный индекс для левого пьезоэлемента
int rightIndex = 0; // Конкретный индекс для правого пьезоэлемента
const int leftPin = 10; // Левый пьезо
const int rightPin = 2; // Правильный пьезоэлемент

// Конкретные левые шаги (в виде числа с плавающей запятой)
const float leftTones[] = {123.4, 103.83, 138.59, 92.50};
// Как долго длятся левые питчи
const long leftDelays[] = {700, 1300, 900, 900};

// Конкретные правые шаги (в виде числа с плавающей запятой)
const float rightTones[] = {739.99, 587.33, 587.33, 659.25, 698.46, 659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 493.88, 554.37, 587.33, 659.25, 587.33, 554.37, 880.00, 783.99, 739.99, 587.33, 587.33, 659.25, 698.46, 659.25, 587.33, 554.37, 587.33, 659.25, 739.99, 987.77, 987.77, 1108.73, 1174.66, 783.99, 739.99, 698.46, 1174.66, 1318.51};
// Как долго длятся правильные питчи
const long rightDelays[] = {700, 1000, 100, 100, 300, 300, 200, 300, 300, 200, 700, 700, 250, 150, 200, 400, 300, 300, 400, 200, 700, 1000, 100, 100, 300, 300, 200, 400, 300, 200, 700, 700, 300, 200, 400, 300, 200, 400, 300, 200};

void setup() {
  pinMode(leftPin, OUTPUT);
  pinMode(rightPin, OUTPUT);
  Serial.begin(9600);
  delay(1000);
  tone(rightPin, rightTones[rightIndex]);
  tone(leftPin, leftTones[leftIndex]);
}

void loop() {
  currentMillis = millis();
  // Заметки левой рукой
  if (currentMillis - leftPreviousMillis >= leftDelays[leftIndex]) {
    noTone(leftPin); // Выключаем левую ноту
    leftPreviousMillis = currentMillis;
    leftIndex++;
    if (leftIndex == leftNotes) // Сброс индекса левой руки
      leftIndex = 0;
    tone(leftPin, leftTones[leftIndex]); // Включаем новую левую ноту
  }

  // Заметки правой рукой
  if (currentMillis - rightPreviousMillis >= rightDelays[rightIndex]) {
    noTone(rightPin); // Выключаем правую ноту
    rightPreviousMillis = currentMillis;
    rightIndex++;
    if (rightIndex == rightNotes) // Сброс индекса правой руки
      rightIndex = 0;
    tone(rightPin, rightTones[rightIndex]); // Включаем новую правую ноту
  }
}

Я провел некоторое тестирование и думаю, что проблема связана с функцией звуковых сигналов. Сейчас этот код воспроизводит только ноты правой руки. Проблема вот в чем:

tone(rightPin, rightTones[rightIndex]);
tone(leftPin, leftTones[leftIndex]);

Когда я это делаю:

tone(leftPin, leftTones[leftIndex]);
tone(rightPin, rightTones[rightIndex]);

Слышны только ноты левой руки. Но это не идеально. Время от времени раздаются небольшие гудки и гудения. Это приводит меня к выводу, что если одновременно есть два тона, он воспроизводит только тот, который читает первым. Я проверил это на более простом коде, и это правда.

Возникает вопрос: возможно ли использовать два пьезоэлемента одновременно с одним Arduino? Я тестирую его с помощью симулятора Arduino Tinkercad, так что, может быть, проблема в этом? Мой код работает для левого и правого пьезоэлементов. Но когда их складываешь вместе, все портится.

, 👍1

Обсуждение

Погуглите «неблокирующий код» и «сроки без задержек». Эта тема — одна из самых обсуждаемых проблем программирования. Вы обнаружите, что тысячи людей до вас сталкивались с этой проблемой. Решение хорошо документировано., @Delta_G

Я полностью перезаписал свой предыдущий код в отредактированной версии выше, но думаю, что проблема может быть в самой функции тонов. Мои рассуждения выше., @Harrisino

Пожалуйста, не меняйте свой вопрос после того, как получите ответ., @Delta_G

Тон можно использовать только на одном выводе одновременно. В качестве параметра «частота» Tone использует беззнаковое целое число, а не числа с плавающей запятой. Эта библиотека утверждает, что может воспроизводить 2 разных файла на 2 разных контактах: https://github.com/nathanRamaNoodles/Noodle-Synth, @VE7JRO


2 ответа


Лучший ответ:

0

Всегда полезно просмотреть документацию, если у вас есть вопрос о том, как работает фрагмент кода. В данном случае я просмотрел страницу функции тона, которую можно найти здесь. https://www.arduino.cc/reference/en/language/functions/advanced -io/tone/

И второе предложение на этой странице говорит само за себя:

Одновременно может быть сгенерирован только один тон. Если мелодия уже звучит на другом выводе вызовtone() не будет иметь никакого эффекта. Если на том же контакте звучит звуковой сигнал, вызов установит его частоту.

,

Ах, ты был быстрее меня. Также: [Polytone](https://github.com/connornishijima/arduino-polytone) кажется многообещающей альтернативой., @chrisl


0

Как использовать два пьезоэлемента одновременно?

Рассмотрите возможность использования метода программирования конечного автомата.

Как было обнаружено, использование вызовов функции delay() ( где процессор ничего не делает) блокирует любую другую функцию скетча (программы пользователя). В шаблоне программирования конечного автомата вызовы функции задержки() отсутствуют. Вместо этого функция цикла() скетча может выполняться как можно быстрее. Хитрость заключается в том, чтобы контролировать, какой код выполняется в функции цикла() на основе конечного автомата. И в этом случае используйте время для переключения между разными состояниями.

На платформе Arduino (аппаратное и программное обеспечение, которое вы никогда или редко видите, составляющее Arduino) счетчик всегда отслеживает прошедшее время. Используйте функцию millis(), чтобы получить текущее значение в миллисекундах (1000 миллисекунд = 1 секунду) каждый раз с помощью функции цикла(). Рассмотрите возможность использования конечного автомата с двумя состояниями. В 1-м состоянии получаем текущее значение счетчика, добавляем к нему задержку в миллисекундах следующей ноты, запускаем воспроизведение ноты и, наконец, меняем состояние отслеживания переменной на 2-е состояние. В следующий раз с помощью функции цикла(), находясь во 2-м состоянии, проверьте, превышает ли ответ от повторного вызова millis() значение, сохраненное в 1-м состоянии. Если это так, прекратите играть ноту и измените состояние отслеживания переменных на 1-е состояние.

После работы создайте второй аналогичный конечный автомат для воспроизведения встречной мелодии.

Однако, как указал delta-g, библиотека, выбранная ОП, очевидно, может не играйте более одной ноты одновременно. Но ve7jro отметил, что эта библиотека мелодий Arduino может удовлетворить требование одновременного воспроизведения двух нот, как указано в вопросе ОП.

Создание конечного автомата на бесценном уроке программирования. Однако эта библиотека конечных автоматов Arduino доступна, если программист захочет ею воспользоваться.

,

Я поместил свой новый код внизу моего предыдущего ответа., @Harrisino

@Харрисино, ты принял ответ. Так что не редактируйте свой вопрос в другой. Только отредактируйте его, чтобы сделать его лучше. Если у вас другой вопрос, начните сначала, задав новый вопрос. Цель обмена стеками — накапливать вопросы и ответы для поиска людей, у которых есть похожие вопросы. Подумайте, насколько запутанным будет измененный вопрос для этих людей. Кстати, вы приняли ответ, в котором говорится, что вы не можете сделать то, о чем просил ваш вопрос. Я все еще думаю, что государственная машина — это то, что вам нужно. И, возможно, [лучшая библиотека мелодий](https://github.com/nathanRamaNoodles/Noodle-Synth)., @st2000