Звуковой генератор
Часть 2. Конструкция и программное обеспечение
Конструкция прибора
Для изготовления звукового генератора автор использовал готовый корпус из полистирола размерами 162*120*68 мм (Ш*Г*В). Корпус состоит из двух половин - нижней и верхней, скрепляемых между собой саморезами. В комплекте поставляются также ножки и заготовки для изготовления передней и задней панели.
К нижней части корпуса с помощью четырех саморезов привинчена несущая панель из стеклотекстолита с резьбовыми втулками, предназначенными для крепления модулей (фото справа, кликните для увеличения). Втулки шестигранной формы взяты от разъемов DB9 / DB25, применявшихся в старых настольных компьютерах для подключения COM-портов.
На фото показаны модули, установленные на несущую панель. Слева - модуль аттенюатора ATT02, в центре - модуль генератора GEN01, справа - модуль питания POWER01 и микроконтроллер Arduino Nano (вертикально). Для удобства крепления микроконтроллер установлен на кусочке перфорированной макетной платы с помощью угловой вилки от разъема Dupont.
Кнопки S1-S4 формата 12*12 мм и энкодер BR1 распаяны на куске текстолитовой макетной платы. Соединения между элементами на плате выполнены монтажным проводом с задней стороны платы, а сама плата прикреплена к передней панели прибора с помощью гайки энкодера и трех резьбовых втулок из нейлона.
Вид передней панели с внутренней стороны показан на фото слева (кликните для увеличения). На эту панель кроме платы с кнопками и энкодером крепятся модуль ЖК дисплея LCD1602 с интерфейсной платой I2C и разъемы XW1, XW2 типа BNC. Можно также использовать разъемы типа RCA, если они имеются в наличии.
На задней панели прибора установлен разъем для подключения внешнего источника питания J1. Можно использовать любой разъем размерности 2,1*5,5 мм, например DS-026A, DC-022B или DJK-04В. Выключатель питания в приборе не предусмотрен, предполагается, что он имеется у внешнего источника.
Разумеется, приведенная выше конструкция является лишь одним из возможных вариантов компоновки изделия, читатели, решившие собрать звуковой генератор на основе наших модулей, могут, в зависимости от своих технологических возможностей и от имеющихся у них в наличии комплектующих и материалов, избрать и другие конструктивные решения. Тем интереснее будет увидеть, что у вас получилось - присылайте фото ваших конструкций, мы их тут с радостью опубликуем.
Монтаж
Межплатные соединения выполнены при помощи монтажных проводов, снабженных соответствующими разъемами. Для соединения микроконтроллера с органами управления передней панели использован шлейф из 8-ми разноцветных проводов с разъемом Dupont на конце, для подключения к модулю ЖК дисплея - такой же разъем, но с 4-мя контактами, остальные модули соединяются между собой жгутами монтажных проводов с разъемами KF2510. Подробнее можно рассмотреть на фото внизу (кликните для увеличения).
В результате того, что все соединения между узлами прибора выполнены разъемными, любой модуль можно извлечь для ремонта или замены без применения пайки, просто отключив соответствующие разъемы.
Программное обеспечение
Программное обеспечение микроконтроллера написано на языке C++ в среде разработки Arduino IDE. Для удобства чтения и возможной последующей модификации кода исходные тексты разбиты на четыре файла:
- SignalGenerator.ino - главный файл программы, содержащий функции setup() и loop() а также основные функции, определяющие реакции прибора на нажатие кнопок и вращение вала энкодера.
- attenuator.ino - процедуры работы с модулем аттенюатора ATT02.
- display.ino - процедуры работы с ЖК дисплеем LCD1602.
- generator.ino - процедуры работы с модулем генератора GEN01.
Загрузить эти файлы (в виде архива .zip) можно по ссылке в конце этой публикации. Исходные тексты снабжены подробными комментариями и в целом должны быть понятны читателям, владеющим минимальными навыками программирования для Arduino. Если какие-то нюансы все же покажутся непонятными, автор будет рад ответить на вопросы читателей.
Для того чтобы выполнить компиляцию кода и его загрузку в микроконтроллер, необходимо все четыре файла поместить в одну папку на жестком диске компьютера, названную так же как и главный файл - SignalGenerator (но без расширения ".ino"). В этом случае при открытии главного файла в среде Arduino IDE три остальных файла будут автоматически загружены, открыты в отдельных вкладках и будут компилироваться совместно с главным.
Кроме того для компиляции необходимы следующие библиотеки, подключаемые в коде программы директивами #include:
- EEPROM - работа с энергонезависимой памятью микроконтроллера
- Wire - работа с интерфейсом I2C
- LiquidCrystal_I2C - работа с ЖК дисплеем
- Adafruit_MCP4725 - работа с ЦАП MCP4725 (входит в состав модуля генератора GEN01)
Первые три из перечисленных библиотек входят в комплект поставки Arduino IDE и, как правило, разыскивать их где-то на просторах интернета и отдельно загружать не требуется. Четвертую легко найти на сайтах arduino, adafruit или github.
Компиляция кода может выполняться в двух вариантах - в режиме отладки или в режиме релиза. Для выбора режима отладки нужно раскомментировать находящуюся в самом начале файла SignalGenerator.ino строчку:
#define __DEBUG__
В режиме отладки программа будет передавать среде разработки Arduino IDE детальные сообщения обо всех выполняемых действиях через последовательный порт. Для того чтобы увидеть эти сообщения, необходимо установить связь между компьютером и микроконтроллером через кабель USB, запустить на компьютере Arduino IDE и открыть в ней окно Serial Monitor. Такая трассировка хода выполнения программы может существенно облегчить поиск неисправности в случае, если в работе прошивки что-то пойдет не так.
По окончании отладки следует перейти в режим релиза, закомментировав указанную выше строчку, после чего нужно будет вновь откомпилировать программу и загрузить получившийся двоичный код в микроконтроллер. В этом случае отладочные сообщения в среду разработки передаваться не будут, объем, занимаемый прошивкой в памяти контроллера заметно уменьшится, а скорость выполнения кода повысится.
Настройка прибора
Предполагаем, что каждый из трех модулей, входящих в состав прибора, был ранее настроен в соответствии с рекомендациями в их описаниях. Если вы этого еще не сделали, то вам необходимо обратиться к соответствующим публикациям на этом сайте и выполнить те операции по настройке, которые там описаны.
Для настройки прибора в целом необходимо выполнить следующие операции:
1. Выполнить компиляцию кода в режиме отладки, как указано в предыдущем разделе, загрузить прошивку в микроконтроллер.
2. Нажимая кнопки прибора и вращая вал энкодера, пройти все режимы работы, указанные в разделе "Режимы работы и функции органов управления" в 1-й части данной публикации. При этом по индикации на дисплее и по отладочным сообщениям в окне Serial Monitor убедиться, что все функции прибора соответствуют описанию.
Если поведение прибора отличается от ожидаемого или в окне Serial Monitor видны сообщения типа "dac.begin() call failed", то одной из вероятных причин этого может являться то, что ваши периферийные модули имеют адреса на шине I2C, отличающиеся от использованых автором в скетче.
В обсуждаемом изделии к шине I2C подключены три периферийных устройства - микросхема PT2257 в модуле аттенюатора ATT02, микросхема MCP4725 в модуле генератора GEN01 и микросхема PCF8574 в конвертере интерфейса для ЖК дисплея. Первая из них имеет фиксированный адрес 0x44 на шине I2C, а вот адреса двух других могут меняться в зависимости от варианта исполнения самой микросхемы и от положения перемычек на их платах. В результате модуль генератора и конвертер интерфейса могут иметь по 8 различных адресов каждый.
Вы можете выяснить экспериментально, какие именно адреса портов задействованы в ваших модулях, загрузив в микроконтроллер программу i2c_scanner, которую можно отыскать среди примеров программ в среде Arduino IDE или скачать с официального сайта Arduino. Программа просканирует все существующие на шине I2C адреса портов и отметит те из них, на которых "откликаются" ваши периферийные модули. Если адреса портов ваших модулей отличаются от указанных на схеме, вам следует исправить соответствующие константы в скетче.
Другой причиной неправильного функционирования прибора (при заведомо исправных модулях) могут быть ошибки в монтаже межплатных соединений, которые необходимо выявить и устранить. С помощью тестера и осциллографа проверьте наличие напряжений питания и сигналов на контактах разъемов всех модулей.
3. Отрегулировать выходное напряжение. Для этого в первую очередь надо убедиться, что перемычка SV1 в модуле аттенюатора ATT02 находится в положении 1-2, которое соответствует коэффициенту усиления буферного усилителя равному 3.16 (10 дб). Если перемычка отсутствует или находится в другом положении, следует установить ее в положение 1-2.
Затем нужно подключить на выход сигнала синусоидальной формы милливольтметр и осциллограф, при помощи кнопок "Up", "Down" и энкодера установить на дисплее частоту сигнала 400 Гц и выходное напряжение 775 мВ (0 dBu). Вращая подстроечный резистор R11 ("Amplitude") в модуле генератора, установить напряжение на выходе прибора равным установленному на дисплее. Убедиться, что сигнал при этом имеет хорошую синусоидальную форму без видимых искажений.
4. Привести в соответствие частоту выходного сигнала звукового генератора с показаниями на дисплее. Для этого на выход звукового генератора нужно подключить частотомер или цифровой осциллограф с функцией измерения частоты, затем в четырех точках, соответствующих границам поддиапазонов модуля GEN01 (12 Гц, 500 Гц, 630 Гц и 25000 Гц), проверить соответствие частоты, показанной на дисплее, реальной частоте сигнала на выходе. Если имеются отклонения, то, найдя в исходном тексте прошивки определения констант range0min, range0max, range1min и range1max, следует изменить их значения таким образом, чтобы частота сигнала на выходе была равна частоте, показанной на дисплее. Определения этих констант находятся в файле SignalGenerator.ino рядом с текстом функции fCode и их легко найти, воспользовавшись поиском.
Подробнее о том, как это делается и как без многочисленных проб и ошибок быстро вычислить правильные значения этих констант, можно прочитать под спойлером ниже.
Как мы уже объясняли, описывая модуль генератора GEN01, изменение вырабатываемой модулем частоты происходит путем записи различных значений в рабочий регистр ЦАП MCP4725. Разрядность рабочего регистра ЦАП равна 12-ти, поэтому записываемые в него значения должны лежать в диапазоне от 0 до 4095. Для дальнейших объяснений назовем это числовое значение кодом частоты. Каждому коду частоты соответствует определенная частота выходного сигнала модуля.
Кроме того, рабочий диапазон частот модуля GEN01, разбит на два поддиапазона - поддиапазон 0 (низкочастотный, от 12 до 630 Гц) и поддиапазон 1 (высокочастотный, от 630 до 25000 Гц), выбор которых осуществляется при помощи логического сигнала Range, подаваемого на вход модуля.
Константы range0min, range0max, range1min и range1max определяют коды частоты для минимальных и максимальных частот каждого из поддиапазонов следующим образом:
- range0min - поддиапазон 0 - код частоты 12 Гц
- range0max - поддиапазон 0 - код частоты 500 Гц
- range1min - поддиапазон 1 - код частоты 630 Гц
- range1max - поддиапазон 1 - код частоты 25000 Гц
Для вычисления кодов, соответствующих другим частотам, находящимся в промежутках между максимальной и минимальной в каждом поддиапазоне, программа использует метод линейной интерполяции (cм. функцию fCode() в исходном тексте скетча). Этот метод в данном случае дает очень хорошие результаты, поскольку зависимость частоты сигнала на выходе модуля от значения, записанного в рабочий регистр АЦП является строго линейной. Таким образом, для настройки соответствия между установленной пользователем частотой и фактической частотой сигнала на выходе прибора необходимо лишь установить точные значения кодов частоты на краях обоих поддиапазонов, а все промежуточные значения будут вычисляться программой автоматически.
Делается это следующим образом:
- При помощи энкодера устанавливаем на дисплее одну из четырех частот, соответствующую какой-либо из указанных выше констант. Например, частоту 500 Гц, если мы занимаемся подбором значения константы range0max;
- Частотомером или осциллографом измеряем получившееся значение частоты сигнала на выходе прибора. Получилось, например, 522 Гц. Плохо! Очевидно, надо корректировать значение константы range0max;
- Смотрим в исходном тексте прошивки, какое значение константа range0max имеет в текущий момент. Если вы ничего не меняли в исходном тексте, то ее определение выглядит вот так:
#define range0max 2765
Это же значение кода 2765 для частоты 500 Гц можно увидеть и в окне Serial Monitor, когда программа откомпилирована в режиме отладки; - Пользуясь тем фактом, что зависимость частоты от значения кода является линейной, составляем пропорцию
2765 / 522 = x / 500
Прочитать эту пропорцию можно следующим образом: "Записали в регистр код 2765 - получили на выходе 522 Гц. Какой код x нужно записать в регистр, чтобы получить на выходе ровно 500 Гц?" - Решаем пропорцию по известному правилу арифметики:
x = 2765 * 500 / 522
получаем:
х = 2648 (с округлением до целого) - Изменяем в исходном тексте прошивки значение константы range0max следующим образом:
#define range0max 2648
Далее повторяем описанные выше действия для трех других констант, перекомпилируем прошивку с новыми значениями констант и загружаем ее в микроконтроллер. После этого частота сигнала, вырабатываемого прибором, будет совпадать (или отличаться очень незначительно) от установленной пользователем и отображаемой на дисплее, причем не только на краях диапазонов, но и на любых других частотах.
Дело в том, что соотношение между кодом частоты, записываемым в рабочий регистр ЦАП, и генерируемой модулем GEN01 частотой сигнала зависит от параметров некоторых компонентов модуля, например, от фактической емкости конденсаторов C3 и C4 во времязадающей цепи, от сопротивлений резисторов R3, R4 и R9, от разброса параметров микросхемы XR2206 и так далее. Поэтому на практике каждый изготовленный экземпляр получается в какой-то степени уникальным и требует индивидуальной подгонки констант range0min, range0max, range1min и range1max в исходном тексте скетча звукового генератора. Автор был бы рад выполнить эту работу один раз, внести в скетч "правильные" значения и не пускаться в сложные объяснения о том, как читатели должны будут это делать сами, но, увы, это невозможно.
5. После окончания всех работ по настройке выполнить компиляцию кода в режиме релиза, как указано в разделе "Программное обеспечение", загрузить прошивку в микроконтроллер. После этого можно начинать использовать изготовленный вами звуковой генератор в вашем повседневном труде по созданию новых радиолюбительских конструкций, наслаждаясь его отличной работой и интересными функциональными возможностями.
Небольшие конструктивные улучшения
В процессе изготовления, настройки и первых недель эксплуатации прибора у автора появились некоторые идеи по улучшению его конструкции, часть из которых уже воплощена в жизнь, а часть, возможно, будет реализована позже, если для этого найдется достаточное количество свободного времени. Вот некоторые из этих идей:
1. Если разъем USB микроконтроллера Arduino Nano вывести наружу, то подключать к нему кабель для обновления прошивки можно будет без развинчивания корпуса. Сделать это можно двумя способами:
- можно разместить микроконтроллер в корпусе прибора таким образом чтобы его разъем USB оказался вплотную к боковой или задней стенке корпуса, а в корпусе в этом месте проделать отверстие соответствующей формы так, чтобы кабель вставлялся снаружи непосредственно в разъем на плате Arduino Nano
- или установить отдельную розетку USB на задней стенке прибора и при помощи монтажных проводов соединить ее контакты с соответствующим цепями на плате микроконтроллера. Можно использовать USB розетку любого типа - классическую Type-A, "квадратную" Type-B, миниатюрную Micro-USB и так далее, главное, чтобы у вас нашелся кабель, который позволил бы соединить эту розетку с портом USB вашего компьютера.

Автор использовал второй из перечисленных способов - установил розетку на задней стенке прибора. Была использована розетка Type-B (слева на фото ). Такие розетки широко использовались в принтерах, сканерах и других периферийных устройствах, поэтому кабель для ее соединения с USB портом компьютера найти несложно. После этой доработки стало гораздо легче обновлять прошивку - разборки корпуса для этого теперь не требуется.
2. Неплохо было бы поменять местами модули генератора GEN01 и аттенюатора ATT02. Дело в том, что при раположении модулей, показанном на фото в разделе "Конструкция прибора", наиболее чувствительные к нагреву элементы - времязадающие конденсаторы C3 и C4 в модуле генератора - находятся в непосредственной близости от радиатора 5-вольтового линейного регулятора IC1 модуля питания. В процессе работы этот радиатор, хоть и не сильно, но все-таки греется, что может вызывать некоторое повышение температуры времязадающих конденсаторов и, как следствие, уход частоты генератора. В экземпляре звукового генератора, собранном автором, удалось подобрать в качестве C3 и C4 пары конденсаторов с практически нулевым ТКЕ, поэтому их нагрев не влияет на частоту генератора, однако, при повторении этой конструкции лучше будет все-таки удалить эти конденсаторы от любых элементов, выделяющих тепло.
3. Габариты корпуса прибора вполне позволяют разместить внутри сетевой источник питания вроде одного из тех, что показаны на фото внизу.

При подборе подходящего источника надо учесть, что продавцы этих изделий склонны сильно завышать в описаниях своего товара их нагрузочные характеристики, такие как выходной ток и выходную мощность. Это означает, что если для питания обсуждаемого здесь звукового генератора необходимо получить от источника питания ток нагрузки 200 мА при напряжении 9 В, то надо искать источник минимум на 600 мА, а еще лучше на 1 А. Только в этом случае можно будет надеяться, что он не сгорит со страшным дымом и треском через несколько минут после первого включения.
Если вы решите добавить такой источник питания, то вам надо будет на задней стенке прибора заменить входной 9-вольтовый разъем, разъемом, предназначенным для подключения сетевого шнура 220 В и там же установить сетевой выключатель и гнездо для плавкого предохранителя.
Файлы для загрузки
Исходный текст прошивки микроконтроллера: SignalGenerator.zip