Цифро-аналоговый преобразователь (ЦАП) Arduino UNO R4 Minima
Узнайте, как создавать волновые формы и выводить их на пьезоэлемент с помощью ЦАП на плате UNO R4 Minima.
Arduino UNO R4 Minima имеет встроенный ЦАП (цифро-аналоговый преобразователь, DAC), который используется для преобразования цифрового сигнала в аналоговый. Эту функцию можно использовать для создания множества интересных аудиопроектов, а также применять в качестве профессионального лабораторного оборудования, например, как недорогой генератор функций.
Цели
В этой статье вы узнаете:
о возможности ЦАП, встроенного в UNO R4 Minima,
о различиях между техниками ШИМ и ЦАП,
как генерировать волновую форму (синусоиду),
как вывести эту волновую форму на пьезозуммер.
Необходимое оборудование и программное обеспечение
Для выполнения этого руководства вам понадобится следующее оборудование:
Пьезозуммер
Потенциометр
Соединительные провода
Схема
Схема, необходимая для данного руководства, представлена на диаграмме ниже:
Пьезозуммер, подключённый к UNO R4
Аналоговый выход vs ШИМ
Во многих случаях, когда требуется аналоговый выход, использование ШИМ (широтно-импульсной модуляции, PWM) вместо настоящего аналогового выхода даёт практически те же результаты. Цифровой выходной пин может быть либо полностью включён (HIGH), либо полностью выключен (LOW), но при очень быстром переключении с точной синхронизацией среднее напряжение можно контролировать и эмулировать аналоговый выход. Этот метод называется ШИМ (PWM).
Например, при диммировании светодиода вы можете свободно использовать цифровой пин с поддержкой ШИМ в качестве аналогового выхода, и светодиод будет диммироваться так же, как если бы вы использовали выход ЦАП.
Однако это не всегда так, и для многих задач вам потребуется настоящий аналоговый выход для получения желаемых результатов. Один из таких случаев — аудиоприложения, где ШИМ-выход просто не обеспечит такое же качество звука, как настоящий аналоговый выход, и для работы потребуется дополнительная настройка.
Код
Код для этого руководства разделён на две части: основной скетч и заголовочный файл, содержащий предварительно сгенерированную пилообразную волновую форму.
В этом скетче мы предварительно сгенерировали синусоидальную волновую форму. Вы также можете динамически генерировать её в начале скетча или во время его выполнения, но это будет менее эффективно без какого-либо прироста производительности. Поэтому данный подход является лучшей практикой.
Волновая форма хранится в виде сэмплов в массиве, и при каждом цикле скетча мы обновляем выходное значение ЦАП на следующее значение в массиве.
Откройте новый скетч и вставьте следующий код в ваше окно.
Исходный код на Github
/*
SineWave
Generates a pre-generated sawtooth-waveform.
See the full documentation here:
https://docs.arduino.cc/tutorials/uno-r4-wifi/dac
*/
#include "analogWave.h" // Include the library for analog waveform generation
analogWave wave(DAC); // Create an instance of the analogWave class, using the DAC pin
int freq = 10; // in hertz, change accordingly
void setup() {
Serial.begin(115200); // Initialize serial communication at a baud rate of 115200
wave.sine(freq); // Generate a sine wave with the initial frequency
}
void loop() {
// Read an analog value from pin A5 and map it to a frequency range
freq = map(analogRead(A5), 0, 1024, 0, 10000);
// Print the updated frequency to the serial monitor
Serial.println("Frequency is now " + String(freq) + " hz");
wave.freq(freq); // Set the frequency of the waveform generator to the updated value
delay(1000); // Delay for one second before repeating
}
Тестирование
После загрузки кода на плату она должна начать генерировать синусоидальное колебание на ЦАП, которое, в зависимости от частоты, может использоваться для воспроизведения звука на пьезозуммере или динамике. Если у вас есть осциллограф, подключение его щупа к выходу ЦАП может быть интересным упражнением, чтобы увидеть, как выглядит волна.
Теперь попробуйте покрутить потенциометр и послушайте, как меняется звук.
Типы аналоговых волн
Скетч выше генерирует так называемую синусоидальную волну. Она называется синусоидальной, потому что если построить график зависимости напряжения от времени, вы заметите, что линия выглядит точно так же, как функция синуса.
Существуют другие типы аналоговых волн, которые производят отчётливо отличающийся тип звука по сравнению с синусоидальной волной. Библиотека, которую мы используем в этом скетче, также позволяет создавать пилообразные и прямоугольные волны. Эти типы волн также получили свои названия от того, как они выглядят при построении графика напряжения от времени.
Попробуйте изменить тип волны и послушайте, как это меняет характер звука.
Измените волну, заменив строку 18 в скетче
wave.sine(freq);
на одну из следующих:
wave.square(freq);
или
wave.saw(freq);
Теперь, когда вы знаете, что ваша установка работает, вы можете экспериментировать дальше с различными примерами и посмотреть, как можно использовать ЦАП UNO R4 для генерации звуков и даже мелодий.
Примечание
В этой установке мы используем просто пьезозуммер, и вы можете заметить, что издаваемые звуки довольно тихие. Если вы хотите исправить это, вам понадобится динамик на 4 или 8 Ом и усилитель. В интернете можно найти множество модулей усилителей на брейкаут-платах, которые легко использовать.
Frere Jacques
Этот пример воспроизводит мелодию Frere Jacques:
Исходный код на Github
/*
DAC Melody player
Generates a series of tones from MIDI note values
using the Uno R4 DAC and the AnalogWave Library.
The melody is "Frere Jacques"
circuit:
* audio amp (LM386 used for testing) input+ attached to A0
* audio amp input- attached to ground
* 4-8-ohm speaker attached to amp output+
* Potentiometer connected to pin A5
created 13 Feb 2017
modified 3 Jul 2023
by Tom Igoe
See the full documentation here:
https://docs.arduino.cc/tutorials/uno-r4-wifi/dac
*/
#include "analogWave.h"
analogWave wave(DAC);
#define NOTE_A4 69 // MIDI note value for middle A
#define FREQ_A4 440 // frequency for middle A
// the tonic, or first note of the key signature for the song:
int tonic = 65;
// the melody sequence. Note values are relative to the tonic:
int melody[] = {1, 3, 5, 1,
1, 3, 5, 1,
5, 6, 8, 5, 6, 8,
8, 10, 8, 6, 5, 1,
8, 10, 8, 6, 5, 1,
1, -4, 1,
1, -4, 1
};
// the rhythm sequence. Values are 1/note, e.g. 4 = 1/4 note:
int rhythm[] = {4, 4, 4, 4,
4, 4, 4, 4,
4, 4, 2,
4, 4, 2,
8, 8, 8, 8, 4, 4,
8, 8, 8, 8, 4, 4,
4, 4, 2,
4, 4, 2
};
// which note of the melody to play:
int noteCounter = 0;
int bpm = 120; // beats per minute
// duration of a beat in ms
float beatDuration = 60.0 / bpm * 1000;
void setup() {
// start the sine wave generator:
wave.sine(10);
}
void loop() {
// current note is an element of the array:
int currentNote = melody[noteCounter] + tonic;
// play a note from the melody:
// convert MIDI note number to frequency:
float frequency = FREQ_A4 * pow(2, ((currentNote - NOTE_A4) / 12.0));
// all the notes in this are sixteenth notes,
// which is 1/4 of a beat, so:
float noteDuration = beatDuration * (4.0 / rhythm[noteCounter]);
// turn the note on:
wave.freq(frequency);
// tone(speakerPin, frequency, noteDuration * 0.85);
// keep it on for the appropriate duration:
delay(noteDuration * 0.85);
wave.stop();
delay(noteDuration * 0.15);
// turn the note off:
// noTone(speakerPin);
// increment the note number for next time through the loop:
noteCounter++;
// keep the note in the range from 0 - 32 using modulo:
noteCounter = noteCounter % 32;
}
Ноты MIDI-пианино
Этот скетч разбивает входной сигнал потенциометра на шаги, которые транслируются в 88 MIDI-нот, представляющих клавиши фортепиано.
Исходный код на Github
/*
Plays a tone in response to a potentiometer
formula from https://newt.phys.unsw.edu.au/jw/notes.html
and https://en.wikipedia.org/wiki/MIDI_tuning_standard:
the MIDI protocol divides the notes of an equal-tempered scale into
128 possible note values. Middle A is MIDI note value 69. There is
a formula for converting MIDI note numbers (0-127) to pitches. This sketch
reduces that to the notes 21 - 108, which are the 88 keys found on a piano:
frequency = 440 * 2^((noteNumber - 69) / 12.0)
You can see this applied in the code below.
circuit:
* audio amp (LM386 used for testing) input+ attached to A0
* audio amp input- attached to ground
* 4-8-ohm speaker attached to amp output+
* Potentiometer connected to pin A5
created 18 Dec 2018
modified 3 Jul 2023
by Tom Igoe
See the full documentation here:
https://docs.arduino.cc/tutorials/uno-r4-wifi/dac
*/
// include the AnalogWave library:
#include "analogWave.h"
analogWave wave(DAC);
// middle A is the reference frequency for an
// equal-tempered scale. Set its frequency and note value:
#define NOTE_A4 69 // MIDI note value for middle A
#define FREQ_A4 440 // frequency for middle A
const int speakerPin = A0; // the pin number for the speaker
void setup() {
Serial.begin(9600);
wave.sine(10);
}
void loop() {
// convert sensor reading to 21 - 108 range
// which is the range of MIDI notes on an 88-key keyboard
// (from A0 to C8):
int sensorReading = analogRead(A5);
int noteValue = map(sensorReading, 0, 1023, 21, 108);
// then convert to frequency:
float frequency = FREQ_A4 * pow(2, ((noteValue - NOTE_A4) / 12.0));
int freq = int(frequency);
// turn the speaker on:
wave.freq(freq);
Serial.print("note value: "+ String(noteValue) + " freq: ");
Serial.println(freq);
delay(500);
}
Заключение
Следуя этому руководству, вы поэкспериментировали с ЦАП на платах Arduino UNO R4 и использовали его сначала для генерации синусоидальной волны, а затем для изучения возможностей аналогового выхода, протестировав различные примеры.