Приветствую всех любителей электроники!  Данная статья ориентирована на людей со средним ("молодым"🙃) уровнем знаний в электронике и выше. АЧХ — Амплитудно-частотная характеристика МК — Микроконтроллер БПФ — Быстрое преобразование Фурье ДПФ — Дискретное преобразование Фурье Бывают ситуации, когда нам известен спектр сигнала, но форму сигнала мы не можем представить в виду сложности основого сигнала. Ещё чаще возникает вопрос об построении АЧХ, но вот прибора под рукой нет, особенно если работаешь в гаражном кооперативе дома. В данной статье я хочу поделиться скромным девайсом, моделирующее аналоговый сигнал сложной формы математическим методом и способное построить АЧХ по данному сигналу. Да, на устройство ничего не будет подаваться из-вне. Всё моделирует, строит и вычисляет непосредственно микроконтроллер. Я специально выделил это место, чтобы не обнадёживать людей, которые хотят увидеть полностью законченный и работающий измерительный прибор. Да, цифры перед фамилией для университета, я студент, параллельно работающий техником (программирование STM32) Для разработки устройства нам потребуется: Любая отладочная плата с МК семейства STM32F1xx. В моём случае это STM32F103ZET6  Любой доступный программатор для STM32, у меня это самодельный st-link V2.1. Если будут желающие, выкачу отдельную статью про него и исходными файлами, вещь! Китайский модуль TFT-экрана; 3 потенциометра на 10кОм стандартные китайские; соединительные провода, обычные провода (придётся паять), корпус пластиковый, крепёжные винты м3 для экрана. Уравнение аналогового сигнала будет состоять из трёх гармоник. Для регулирования частоты каждой гармоники используем потенциометры. Разработка кода будет на HAL+CMSIS через STM32CubeMX в Keil uVision5. Выбираем контроллер STM32F103ZET6. Выбираем программирование МК по последовательной шине (SWD – Serial Wire Debug). Подключаем внешний кварц на 8МГц. Подключаем SPI (serial peripheral interface), характеристики SPI: Тут можно выбрать любой МК семейства F1 как было сказано ранее, у них всё одно и тоже, в том числе и распиновка SPI и АЦП. Способ программирования у меня стоит по SWD. Выбирайте как вам удобно, с этим понятно. Также включаем АЦП. Задействуем 3 канала АЦП, под одну составляющую гармонического сигнала отводим 1 канал АЦП. Забирать данные с АЦП будем при помощи DMA в режиме прерывания. АЦП и DMA выставим в одиночном режиме, будем вручную выключать АЦП и включать, когда это будет нужно. Не забудьте включить прерывание по DMA! Кроме этого, активируем ещё 3 вывода МК, настроем их как выходы и присвоим названия. Данные выводы будут использованы для управления дисплеем. Выбор драйвера (chip select), сброс (reset), и разрешения записи данных (data chip). Помимо этого нужно конечно же подать питание, и включить подсветку. Подсветку можно сделать постоянную, а можно организовать регулируемую, через транзистор с помощью таймера в режиме ШИМ. Питание и подсветку я подавал от самой платы... Теперь перейдём в дерево тактирования (clock tree) и разгоним МК до максимально допустимой частоты в 72МГц. Стоит заметить, что в таком положении частоту АЦП можно выставить только на 12МГц, при 14МГц возможных. Чтобы выставить максимум, необходимо понизить частоту системной шины. Однако в данном проекте АЦП не выполняет сверхважную задачу, поэтому оставляем 12МГц. Прежде всего необходима библиотека для дисплея на базе ILI9341. В интернете есть множество вариантов готовых библиотек для данного дисплея, однако в большинстве своём они ограничены, тяжелы в понимании за счёт отсутствия эстетики написания кода, могут вообще не работать или написаны под какое-то конкретное семейство STM32. Поэтому было принято решение написать универсальную для любого семейства STM32 библиотеку уже с полным набором удобных функций на базе библиотек из интернета, однако данная библиотека подходит для любого драйвера, так как она написана на CMSIS. Таким образом её можно подключать в любой проект. Саму инициализацию SPI будет делать CubeMX (так быстрее, при желании скину код инициализации SPI на CMSIS с возможностью разгона частоты до 44МГц). Инициализацию библиотека делает сама. Она имеет понятные названия функций, их легко использовать. Основные функции: 1) void taskSolution (uint16_t k); Данная функция решает основное уравнение, описывающее гармонический сигнал, подготавливая значение выборки для удобного вывода на дисплей. Для данного проекта выбрано следующее уравнение: где in – это частота гармоники, величина которой зависит от изменения на входе канала АЦП;       k – номер выборки;       N – количество выборок (N = 256); Само собой функция стоит в цикле до некого опеределённого значения, в данном случае 256 выборок (X_LINE_LENGTH). По мимо этого в конце функции я зачем-то делаю конверсию. Тут всё просто. Я использую функцию косинуса и значит у меня значение колеблется от 0 до 1, это понятно. Значит мне его нужно просто умножить на некую константу, чтобы удобно было вывести уже большое значение (номер пикселя) на экран + это помогает сразу получить из "плавующей" переменной довольно точную целую. 2) uint32_t MAP (uint32_t au32_IN, uint32_t au32_INmin, uint32_t au32_INmax, uint32_t au32_OUTmin, uint32_t au32_OUTmax); Данная функция конвертирует диапазон изменения значения АЦП (0-4095) в диапазон частот сигнала (0-15); 3) void displaySignal (uint16_t k); Данная функция выводит полученное значение выборки на дисплей; 4) void clearNextPosition (uint16_t k, uint16_t COLOR). Перед выводом на дисплей используем функцию очистки следующего значения выборки. Так как экран обновляется в данном случае слева направо, и чтобы не очищать сразу весь участок сигнала (устранение мерцания), а добиться плавности отображения изображения очищаем только следующий столбец пикселей экрана; 5) void visualSignalIncrement (uint16_t k, uint16_t COLOR); Чтобы визуально сигнал был хорошо различим, зажжём сверху и снизу основного значения функции ещё один пиксель, таким образом сигнал будет жирнее; 6) Функции:  void visualFFT_Increment (uint16_t k, uint16_t harmonic, uint16_t COLOR); void displayFFT (uint16_t k); void clearLastFFT_VAL (uint16_t k);  void displayFFT_VAL (uint16_t k); аналогичны функциям вывода сигнала на экран. Принцип работы такой же, отличие заключается только в определении амплитуды и частоты каждой гармоники, и расчёт спектра сигнала; Я не использовал сложные формулы для вычисления спекртра в данном проекте. Т.к. мне известна формула гармонического сигнала, его параметры, я просто брал значение его аплитуды и частоты и рисовал соответсвующую гармонику на АЧХ. В дальнейшем конечно, устройство можно доработать, тем более, что это может лишь показаться сложным на первый взгляд. Если хочется понять принцип работы алгоритма БПФ и ДПФ, на harb есть понятная и позновательная статья на данную тему, там использован другой язык и нет микроконтроллера, но это не важно, поскольку очень понятно описывается сам алгоритм, чтобы вы могли применить его у себя в проекте. 7) Для отслеживания параметров сигнала и спектральных характеристик необходимо нарисовать координатные оси с соответствующими значениями. Данную операцию выполняют функции drawGridSignal(BLACK); drawGridFFT(BLACK); Из названия функции можно увидеть, что первая функция отвечает за отрисовку координатной оси для гармонического сигнала, а вторая для АЧХ. Количество выборок: 256 (X_LINE_LENGTH). Максимальная частота гармоники: 15 Гц (LIMIT_FREQ); Устройство мне необходимо было сделать довольно быстро для своих нужд, но так, чтобы ничего не развалилось и нормально работало. Поэтому плату я не делал, это было бы долго и дорого, даже если не учитывать около недели на разработку платы, китайцы бы везли платы больше месяца + они стоили бы около 25-35$. А так плат с STM у меня в избытке, как и программаторов с иными коплектующими, поэтому, условно, собрал из того, что было, не задумываясь над ценой конструкции. Разве что покупал пластиковый корпус, так как у меня пока нет своего 3D-принтера, увы... Вырезать пластиковый корпус конечно то ещё удовольствие и не очень красиво выходит по итогу, но тут уж как говорится: "Лучше сделать и пожалеть, чем не сделать и потом жалеть" 😅 Все исходники я выложил на GitHub. Там вы можете скачать проект в CubeMX и сам проект в Keil uVision5. Проект должен завестись сразу же, файл библиотеки уже подключён в проект, ничего стороннего скачивать не нужно. По вопросам моего самодельного программатора и прочим пишите в комментариях. Кроме этого недавно приехали сделанные мной платы на недавно появившуюся STM32G4 (48 пин делал). Очень удобная, с дополнительным функциональным, по сравнению с китайскими платами, да и китайцы сами ещё не успели выкатить дешёвую и удобную версию для данного семейства, если есть желание узнать про это побольше, пишите, с огромной радостью выкачу обзор. Спасибо за внимание!  Инженер-электроник