Изменение рабочего цикла тона на AVR

Я пишу MIDI-преобразователь в квадратную волну, предназначенный для взаимодействия между MIDI-инструментом и музыкальной катушкой Теслы. По сути, это должно действовать как монофонический MIDI-синтезатор, но требования к большинству проектов немного отличаются:

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

Суть того, что мне нужно, - это (непроверенный) скетч, но он, очевидно, не позволяет контролировать время включения.

#include <MIDI.h>

MIDI_CREATE_DEFAULT_INSTANCE();
const static int out_pin = 9;

void handleNoteOn(byte channel, byte pitch, byte velocity)
{
    tone(out_pin, pitch);
    digitalWrite(13, HIGH);   // включите светодиод (HIGH-уровень напряжения)    
}


void handleNoteOff(byte channel, byte pitch, byte velocity)
{
    noTone(out_pin);
    digitalWrite(13, LOW);   // turn the LED off  
}

void setup() {
  MIDI.setHandleNoteOn(handleNoteOn);  
  MIDI.setHandleNoteOff(handleNoteOff);

  
  MIDI.begin(MIDI_CHANNEL_OMNI);
}

void loop() {
  // поместите свой основной код здесь, чтобы запускать его повторно:
  MIDI.read();
}

Мой вопрос, по сути, заключается в том, каков наилучший способ достижения такого рода музыкального контроля ширины импульса. Идеи, которые у меня были, были либо а) Большое количество ручных наборов регистров для битового выброса требуемого сигнала на самой высокой частоте, которую я могу получить, вероятно, в кГц б) Создайте каждый импульс с помощью пользовательской функции pulseOut, используя timer0 для микросекундных задержек.

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

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

, 👍1

Обсуждение

Какую плату Arduino вы используете?, @chrisl

вы видели библиотеку arduino-toneac?, @Juraj

Arduino nano. Я не видел toneaclibrary - хотя он и не совсем способен на то, что мне нужно из коробки, он очень полезен для чтения!, @catalogue_number


1 ответ


3

Я бы рекомендовал использовать аппаратный ШИМ-сигнал, генерируемый таймером 1, или другой 16-битный таймер, если у вас их несколько (как на Mega). 16 бит обеспечивают как приличный частотный диапазон, так и хорошее временное разрешение. Это должно обеспечить свободные от дрожания тайминги, в отличие от любого программного метода. Это также позволит избежать чрезмерной загрузки процессора.

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

  • прескалер = 64, нормальный ШИМ
  • прескалер = 8, фазовая коррекция ШИМ
  • прескалер = 8, нормальный ШИМ
прескалер Режим ШИМ разрешение по времени самая низкая частота. самая низкая нота
64 Нормальный 4 мкс 3,81 Гц C−1 (MIDI 0)
8 фаза правильная 1 мкс 15,26 Гц B0 (MIDI 11)
8 Нормальный 0,5 мкс 30,52 Гц B1 (MIDI 23)

Ради того, чтобы иметь точные ноты, я бы выбрал самое низкое временное разрешение, совместимое с музыкой, которую вы хотите воспроизвести.

Как только это настроено, вы можете управлять музыкой, записывая ее в три регистра:

  • TCR1A включает и выключает ШИМ
  • регистр, удерживающий ВЕРХНЮЮ часть (OCR1A или ICR1, в зависимости от режима) контролирует частоту (высоту тона)
  • регистр сравнения совпадений (OCR1A или OCR1B, в зависимости от канала) управляет длительностью импульсов

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

Основной код даже не нужно синхронизировать с таймером: режимы ШИМ гарантируют отсутствие сбоев ШИМ даже при изменении рабочего цикла. Однако будьте осторожны при изменении частоты: при увеличении частоты могут возникнуть огромные сбои . Безопаснее останавливать, очищать и перезапускать таймер при смене нот.

,