Использование 2 пьезозуммеров для излучения одного и того же сигнала с разницей фаз

Для физического проекта я хочу записать эффект 2 динамиков, излучающих 100 Гц при разных разностях фаз. Проблема в том, что Arduino может посылать только один сигнал tone() за раз. Как создать эффект разности фаз с помощью одного Arduino?

, 👍1

Обсуждение

Подсказка: Начните с понимания того, как работает tone ()., @Mikael Patel


2 ответа


1

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

Для того чтобы сгенерировать звуковой сигнал, необходимо несколько раз переключить штифт , подключенный к пьезоэлементу. Это очень похоже на мигание светодиода, только несколько быстрее. Мигание светодиода-это самое первое, что вы научитесь делать с Arduino, но вы можете заметить, что мигание двух светодиодов немного сложнее. Проблема – и решение – обсуждаются в руководстве по Arduino, Мигайте без промедления. Основываясь на этом руководстве, вот пример программы, которая генерирует два сигнала частотой 100 Гц в квадратуре:

const uint8_t PIN_A = 8;
const uint8_t PIN_B = 9;
const uint32_t HALF_PERIOD = 5000;  // 5000 us
const float PHASE_SHIFT = 0.25;     // 1/4 period

uint8_t state_A = LOW;
uint8_t state_B = LOW;

uint32_t last_A_toggle = 0;
uint32_t last_B_toggle = - 2 * HALF_PERIOD * PHASE_SHIFT;

void setup() {
    pinMode(PIN_A, OUTPUT);
    pinMode(PIN_B, OUTPUT);
}

void loop() {
    uint32_t now = micros();
    if (now - last_A_toggle >= HALF_PERIOD) {
        last_A_toggle += HALF_PERIOD;
        state_A = !state_A;
        digitalWrite(PIN_A, state_A);
    }
    if (now - last_B_toggle >= HALF_PERIOD) {
        last_B_toggle += HALF_PERIOD;
        state_B = !state_B;
        digitalWrite(PIN_B, state_B);
    }
}

Если вы сравните это с вышеупомянутым учебником, то заметите пару отличий, на которые стоит обратить внимание:

  • Время измеряется с использованием микросекунд, а не миллисекунд, для повышения точности
  • Переменные, содержащие время последнего переключения, обновляются следующим образом last_A_toggle += ПОЛУПЕРИОД, а не last_A_toggle = сейчас ( эквивалент предыдущего миллиметра = текущий миллиметр). Это необходимо для поддержания точной средней частоты. В противном случае время, затраченное на выполнение кода, немного снизит частоту.

Существует небольшая хитрость в инициализации last_B_toggle, которая представляет собой число без знака, инициализированное отрицательным значением. Инициализация действительна и работает по модулю 232. Использование небольшого положительного значения приведет к негативному эффекту now - last_B_toggle переполнение до очень большого положительного числа при первом запуске loop(), что эффективно переносит last_B_toggle в далекое прошлое.

,

1

Для очень простого примера вы можете сделать что-то вроде этого:

#define SPEAKER1_PIN    5
#define SPEAKER2_PIN    6

void setup() {
  pinMode(SPEAKER1_PIN, OUTPUT);
  pinMode(SPEAKER2_PIN, OUTPUT);
}

void loop() {          
  int phase_delay = 1000;   // Phase delay (in us)
  int freq_delay = 5000;    // Half of square wave at 100Hz (5000us)

  // Generate 2 square waves (out of phase)
  while(1) {
    digitalWrite(SPEAKER1_PIN, HIGH);
    delayMicroseconds(phase_delay);
    digitalWrite(SPEAKER2_PIN, HIGH);
    delayMicroseconds(freq_delay - phase_delay);
    digitalWrite(SPEAKER1_PIN, LOW);
    delayMicroseconds(phase_delay);
    digitalWrite(SPEAKER2_PIN, LOW);
    delayMicroseconds(freq_delay - phase_delay);
    }
}

Кстати, 100 Гц может быть слишком низкой частотой, чтобы получить много звука из пьезодинамика. Скорее всего, вы добьетесь большего успеха, используя более высокие частоты.

,