Предисловие
У меня дома есть пара комплектов хороших советских акустических систем. Но техника эта довольная старая и просто не может включаться с пульта или автоматически, а постоянно подходить к усилителю звука и включать/выключать его просто лень. Это проблему я и решил решить. Сначало было куплена ардуино и проект был сделан на ней, но качество работы меня не устроило и проект был переделан под STM32F103C8. В итоге у меня получилось устройство, которое имеет 4 аудио-входа, 1 аудио-выход, вход 220В и выход 220В. При наличии хотя бы одного активного аудио-входа на выходе 220В появляется напряжение, тем самым включая усилитель звука, и активный аудио-канал передается на выход.
Сложности при разработке
Казалось бы все просто: если АЦП получает не 0, тогда считать канал активным. Все почти так, но это работает только если включить источник аудио-сигнала и выключить на нем звук. При выключенном состоянии разные устройства дают разные помехи, тк они не полностью обесточены. Да и у плохих источников звука микроконтроллер мог улавливать помехи при выключенном звуке, причем довольно сильные. И это именные помехи источника, помехи на моей внешней аудиокарте STMка не видит, более того тихий звук с нее — 0.
Как сделать себе такое?
Давайте прежде всего определимся что нам надо. Писать стоимость я не буду, т.к. это сильно зависит от Вашего местоположения.
Что нам понадобится:
- печатная плата
- программатор ST-Link v2
- 1 чип STM32f103C8
- 4 реле для коммутации входного аудио-канала на выход
- 1 реле для коммутации 220В для включения усилителя
- AC-DC понижающий преобразователь 220В — 5В(можно взять со старой зарядки телефона)
- сетевой провод и разъем для подачи тока нашему устройству и усилителю
- розетка
- резисторы, конденсаторы и другая мелочь
Естественно нам понадобятся аудио-провода и minijack штекера с гнездами.
Хотелось бы заострить внимание на выборе реле… Если с выбором 220В реле все предельно понятно: оно должно «уметь» коммутировать 220В переменное напряжение и управляться 3.3В. То с выбором звуковых реле не все так просто. Далеко не каждое реле, даже твердотельное, не будет давать помехи на выходе, а нам это очень важно. Я живу в Минске и не смог ничего найти подходящего и по адекватной цене, поэтому были заказаны с известного китайского магазина 4 реле PVT322A. Возможно в вашем регионе вы сможете найти что-то подешевле.
Раз уж начали, то продолжим изучать аппаратные особенности. На схеме, которую вы можете найти в репозитории в папке Eagle нужно подобрать токоограничительные резисторы(R4-7) под ваши реле. В моем случае это 30 Ом. Так же есть катушка L1: выбирайте любой фильтр, сглаживающий высокочастотные помехи.
Заказать печатную плату вы можете на PCBWAY или JLCPCB. Цены у них низкие, я заказывал у JLCPCB и они выставили мне счет всего в 2$. При заказе печатной платы вам нужны будут гербер файлы, вы из сможете найти все в той же папке или сами сгенерировать.
Перейдем к программной части
Рассказывать как подключить программатор к компьютеру, установить среду программирования и драйвер я не буду, т.к. этих инструкций очень много и они предельно доступные. На моей схеме предусмотрены выходы для программаторы. Я использовал Visual Studio 2017 + VisualGDB. Скачав проект из того же репозитория мы сможем открыть проект. Сразу же обратим на файл Settings.cpp.
Settings.cpp
#define DEBUG0 0//init USART and send all measurement values
#define DEBUG1 1//init USART and send information about recognition music or not
#define DEBUG2 0//just init USART
#define MaxEqualToZeroValue 3 //the value which equal or less is equated to zero
#define MaxAvarageForNoise (float)0.4//this is max avarage of measurement values so that the sound is considered noise for NOT active channel
#define MaxAvarageForActiveNoise (float)0.06//this is max avarage of measurement values so that the sound is considered noise for active channel
#define CountOfConsecutiveZeroValueForNoise 250//if count of consecutive zero values bugger it that sound is equated to noise
#define MinCountOfZeroValue 550//it's minimum count of zero values to equate to music(not consecutive)
#define USE_LED 1
#define LED_GPIO_PERIPH RCC_APB2Periph_GPIOC
#define LED_GPIO_GROUP GPIOC
#define LED_GPIO_PIN GPIO_Pin_13
#define USE_AMP 1
#define AMP_GPIO_PERIPH RCC_APB2Periph_GPIOB
#define AMP_GPIO_GROUP GPIOB
#define AMP_GPIO_PIN GPIO_Pin_12
Все настройки в этом файле задокументированы, но мы все равно остановимся на каждой настройке.
#define DEBUG0 0
#define DEBUG1 1
#define DEBUG2 0
Если присвоить дефайну DEBUG0 единицу, то наше устройство перестанет что либо делать, кроме того, что выводить по UARTу значения, которые он получает с аудио-входов в формате, который может «переварить» SerialPortPlotter.
Если же присвоить единицу DEBUG1, то устройство уже будет полностью функционировать, но будет выводить немного информации о работе по UARTу. Это все нужно исключительно для отладки.
Присвоение DEBUG2 даст всего лишь инициализацию UARTа. Если вы не понимаете, зачем это, то и не надо :-)
#define MaxEqualToZeroValue 3
Далее у нас параметр отвечающий значение которого или менее будет считать нулем. Как уже было ранее сказано некоторые источники звука плохого качества и сильно зашумлены.
#define MaxAvarageForNoise (float)0.4
Если аудио-канал сейчас не активен(т.е. канал, который сейчас не коммутируется на выход) и среднее значение измерений за одну цикл измерений по этому каналу меньше значения этого параметра, то канал считается без звука.
#define MaxAvarageForActiveNoise (float)0.06
Этот параметр почти тоже самое, что и предыдущий, только для активного на данный момент канала. Дело в том, что когда канал активен и усилитель работает, то происходит падение напряжения аудио-канала. И если пренебречь этой настройкой, то устройство будет считать, что звук есть даже когда провод не подключен ни к какому устройству.
#define CountOfConsecutiveZeroValueForNoise 250
Этот параметр исключительно для оптимизации расхода процессорного времени. Если устройство встречает подряд заданное количество нулей, то оно считает, что это сигнал не звук.
#define MinCountOfZeroValue 550
А это уже важная настройка. Некоторые устройства, когда выключены создают странные помехи, но я выделил один общий фактор среди них: они очень редко опускаются до нулевых значения. Именно поэтому пришлось ввести этот параметр. Если количество нулевых значений за один цикл измерений меньше заданного, то сигнал считается шумом.
#define USE_LED 1
#define LED_GPIO_PERIPH RCC_APB2Periph_GPIOC
#define LED_GPIO_GROUP GPIOC
#define LED_GPIO_PIN GPIO_Pin_13
#define USE_AMP 1
#define AMP_GPIO_PERIPH RCC_APB2Periph_GPIOB
#define AMP_GPIO_GROUP GPIOB
#define AMP_GPIO_PIN GPIO_Pin_12
Данный блок предельно понятен для тех, кто уже программировал микроконтроллеры. Он выбирает пин на котором будет расположен светодиод и выход на реле управления усилителем. Если Вы не будете изменять мою схему, то эти параметры Вам не нужны.
Перейдем к следующим настройкам:
Открыв файл main.cpp, в самом начале функции
int main()
вы найдете определение кучи переменных.Остановимся на этом поподробней. Там достаточно много параметров, отвечающих за аппаратую настройку микроконтроллера. Их мы затрагивать не будем.
const uint8_t channelsCount = 2;
Это количество входных аудиоканалов, которые будут использоваться.
const uint8_t countOfIterationsForSwitch = 5;
Количество циклов измерения, необходимое для изменения состояния активное/пассивное.
const uint8_t ADCSampleTime = ADC_SampleTime_239Cycles5;
Этот параметр отвечает за качество измерения. Оно установлена максимальное, не рекомендую его менять.
const uint16_t measurementsDuration = 2000;
Это время в ms, в течение которого будет производится один цикл измерений.
const uint32_t measurementFrequencies[] = { 1000, 1000, 1000, 1000 };
Не знаю зачем, но я реализовал функцию, которая позволяет проводить измерения входных каналов с разной для каждого канала частотой. Может кому-то эта функция будет нужна.
Заключение
Ну вот и все. Все необходимые настройки я описал. Осталось только собрать схему, скомпилировать проект, залить прошивку в микроконтроллер и радоваться.
В заключении хотелось бы сказать, что нельзя просто так оставить входной аудио-провод «не воткнутым» ни во что, нужно его вставить в какое либо устройство или заглушку в виде гнезда minijack, в котором все контакты соединены между собой.
Если у вас источники звука довольно хорошие, соответственно и значения настроек довольно низкие, для переключения состояния звука может потребоваться его выключение (не из розетки). Возможно когда нибудь я добавлю ссылку на 3D модель корпуса, но пока у меня нет 3D принтера и корпус на данный момент такой. Но это только пока: 3D принтер уже собирается :-)
Это моя первая статья, буду рад любой аргументированной критике. Понимаю, что это не шедевр, но я старался как мог.
Спасибо за прочтение.