#include <FastLED.h>
#include <fix_fft.h>
#define WIDTH 32 //Ширина матрицы
#define HEIGHT 16 //Высота матрицы
#define LED_PIN 13 //Пин подключения матрицы на ардуино
#define BUTTON_PIN 3 //Пин подключения кнопки на ардуино
#define MIC_PIN A4 //Пин подключения микрофона на ардуино
#define BRT_PIN A0 //Пин подключения потенциометра на ардуино
#define NUM_LEDS (WIDTH * HEIGHT) //Общее количество светодиодов
char ALGORITHM = 1; //1 - Осцилограмма, 2 - Спектр мощности
char MODE = 1; //Режим
char lenPush = 0; //Длина нажатия
CRGB leds[NUM_LEDS]; //Массив для светодиодов
unsigned char old_brightness = 0; //Яркость
long int coeff = 0; //Коэффициент выравнивания графика на матрице
char brightness_down = 35;
char fr[WIDTH]={}; //Реальная часть
char fi[WIDTH]={}; //Мнимая часть
char offset_count = 0; //Счётчик тиков для сдвига графика вниз
void setup() {
FastLED.addLeds<WS2811, LED_PIN, GRB>(leds, NUM_LEDS);
FastLED.setBrightness(analogRead(BRT_PIN) * 0.25);
for (char i = 0; i < HEIGHT; i++) { //Очистка матрицы
for (char j = 0; j < WIDTH; j++) {
leds[XY(i, j)] = CRGB(0, 0, 0);
}
}
FastLED.show();
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(MIC_PIN, INPUT);
for (char i = 0; i < 100; i++) { //Находим сумму первых 100 показаний
coeff += analogRead(MIC_PIN);
//Serial.println(analogRead(MIC_PIN));
}
coeff = coeff / 100; //Определяем среднее значение
coeff = coeff / (1024 / HEIGHT); //Масштабируем среднее значение к высоте матрицы
coeff = HEIGHT / 2 - coeff; //Находим остаток до половины высоты матрицы
//Serial.begin(115200);
}
void Oscillogram() { //1 - Осцилограмма
for (char i = 0; i < HEIGHT; i++) { //Сдвиг матрицы вправо
for (char j = WIDTH - 1; j > 0; j--) {
leds[XY(i, j)] = leds[XY(i, j - 1)];
leds[XY(i, j - 1)] = CRGB(0, 0, 0);
}
}
if (MODE == 1) {
char rise = round(analogRead(MIC_PIN) / (1024 / HEIGHT)) + coeff;
if (rise > HEIGHT - 1) //Масштабируем, сдвигаем и ограничиваем показания
rise = HEIGHT - 1;
char old_height = -1;
for (char i = 0; i < HEIGHT; i++) { //Находим старую высоту 2 столбца
if (leds[XY(i, 1)] == CRGB(0, 255, 0)) {
old_height = i;
break;
}
}
if (old_height == -1) //Если не нашли старую высоту (для первой итерации)
old_height = rise;
char new_height = 0;
if (rise < old_height) { //Новая высота, если старая выше
if (abs(rise - old_height) < HEIGHT / 6)
new_height = old_height - 1;
else if (abs(rise - old_height) < HEIGHT / 3)
new_height = old_height - 2;
else
new_height = old_height - 3;
}
else if (rise == old_height) //Новая высота, если старая такая же
new_height = old_height;
else { //Новая высота, если старая ниже
if (abs(rise - old_height) < HEIGHT / 6)
new_height = old_height + 1;
else if (abs(rise - old_height) < HEIGHT / 3)
new_height = old_height + 2;
else
new_height = old_height + 3;
}
leds[XY(new_height, 0)] = CRGB(0, 255, 0);
for (char i = 0; i < new_height; i++) //Заполняем область под графиком
leds[XY(i, 0)] = CRGB(0, brightness_down, 0);
}
else if (MODE == 2) {
char rise = round((analogRead(MIC_PIN) - 250) / (512 / (HEIGHT / 2)));
if (rise >= HEIGHT / 2) //Масштабируем и ограничиваем показания
rise = HEIGHT / 2 - 1;
else if (rise < 0)
rise = 0;
leds[XY(HEIGHT / 2 - rise - 1, 0)] = CRGB(0, 255, 0);
leds[XY(HEIGHT / 2 + rise, 0)] = CRGB(0, 255, 0);
char flag_fill = 0;
for (char j = 0; j < HEIGHT; j++) { //Заполняем внутреннюю часть
if(leds[XY(j, 0)] != CRGB(0, 255, 0) && flag_fill == 1) {
leds[XY(j, 0)] = CRGB(0, brightness_down, 0);
}
if(leds[XY(j, 0)] == CRGB(0, 255, 0)) {
flag_fill += 1;
}
}
}
}
void Power_spectrum() { //2 - Спектр мощности
for (char i = 0; i < WIDTH; i++) //Масштабируем и сохраняем показания
fr[i] = analogRead(MIC_PIN) / (1024 / (HEIGHT * 10));
fix_fft(fr, fi, 5, 0); //fft
if (MODE == 1) {
for (char i = 0; i < WIDTH; i++) { //Создание графика
char new_height = sqrt(fr[i]*fr[i] + fi[i]*fi[i]);
if (new_height > HEIGHT - 1)
new_height = HEIGHT - 1;
char old_height = 0;
for (char j = 0; j < HEIGHT; j++) { //Находим старую высоту точки i
if(leds[XY(j, i)] == CRGB(0, 255, 0))
old_height = j;
}
if(new_height > old_height) { //Если новая выше, то убираем старую и ставим новую
leds[XY(old_height, i)] = CRGB::Black;
leds[XY(new_height, i)] = CRGB(0, 255, 0);
for (char q = old_height; q < new_height; q++)//Заполняем пустую область под графиком
leds[XY(q, i)] = CRGB(0, brightness_down, 0);
}
else if(old_height != 0 && offset_count == 4) {//Если же ниже, то смещаем старую на 1 вниз
leds[XY(old_height, i)] = CRGB::Black;
leds[XY(old_height - 1, i)] = CRGB(0, 255, 0);
}
}
}
else if (MODE == 2) {
for (char i = 0; i < WIDTH; i++) { //Создание графика
char new_offset = sqrt(fr[i]*fr[i] + fi[i]*fi[i] - 7) / 2;
if (new_offset >= HEIGHT / 2)
new_offset = HEIGHT / 2 - 1;
else if(new_offset < 0)
new_offset = 0;
char old_offset = 0;
for (char j = 0; j < HEIGHT / 2; j++) {//Находим смещение от центра через низ
if(leds[XY(j, i)] == CRGB(0, 255, 0)) {
old_offset = HEIGHT / 2 - 1 - j;
break;
}
}
if(new_offset > old_offset) { //Если новое смещение больше, то убираем старое и ставим новое
leds[XY(HEIGHT / 2 - old_offset - 1, i)] = CRGB::Black;
leds[XY(HEIGHT / 2 + old_offset, i)] = CRGB::Black;
leds[XY(HEIGHT / 2 - new_offset - 1, i)] = CRGB(0, 255, 0);
leds[XY(HEIGHT / 2 + new_offset, i)] = CRGB(0, 255, 0);
}
else if(new_offset < old_offset && offset_count == 4) {//Если же меньше, то смещаем старое на 1 к центру
leds[XY(HEIGHT / 2 - old_offset - 1, i)] = CRGB::Black;
leds[XY(HEIGHT / 2 + old_offset, i)] = CRGB::Black;
leds[XY(HEIGHT / 2 - old_offset, i)] = CRGB(0, 255, 0);
leds[XY(HEIGHT / 2 + old_offset - 1, i)] = CRGB(0, 255, 0);
}
char flag_fill = 0;
for (char j = 0; j < HEIGHT; j++) { //Заполняем внутреннюю часть
if(leds[XY(j, i)] != CRGB(0, 255, 0) && flag_fill == 1) {
leds[XY(j, i)] = CRGB(0, brightness_down, 0);
}
if(leds[XY(j, i)] == CRGB(0, 255, 0)) {
flag_fill += 1;
}
}
}
}
if (offset_count == 4) //Смещение вниз раз в 4 обновления
offset_count = 0;
offset_count += 1;
}
int XY(char x, char y) { //Функция преобразования координат
//Для wokwi
if (y < 16)
return ((16 - x) * 16 - (16 - y));
else
return ((16 - x) * 16 - (16 - y)) + 16 * 15;
//Для реальной матрицы
/*if (y % 2 == 0)
return (y * HEIGHT + (HEIGHT - x - 1));
return (y * HEIGHT + x);*/
}
void NewBrightness() { //Изменение яркости
unsigned char new_brightness = analogRead(BRT_PIN) * 0.25;
if (abs(new_brightness - old_brightness) > 3) {
FastLED.setBrightness(new_brightness);
old_brightness = new_brightness;
FastLED.show();
}
}
void SetNextAlgorithm() { //Смена алгоритма
for (char i = 0; i < HEIGHT; i++) {
for (char j = 0; j < WIDTH; j++) {
leds[XY(i, j)] = CRGB::Black;
}
}
if (ALGORITHM == 1) {
if (MODE == 1) {
for (char j = 0; j < WIDTH; j++) {
leds[XY(0, j)] = CRGB(0, 255, 0);
}
}
if (MODE == 2) {
for (char j = 0; j < WIDTH; j++) {
leds[XY(HEIGHT / 2, j)] = CRGB(0, 255, 0);
leds[XY(HEIGHT / 2 - 1, j)] = CRGB(0, 255, 0);
}
}
ALGORITHM = 2;
}
else if (ALGORITHM == 2)
ALGORITHM = 1;
}
void SetNextMode() { //Смена режима
for (char i = 0; i < HEIGHT; i++) {
for (char j = 0; j < WIDTH; j++) {
leds[XY(i, j)] = CRGB::Black;
}
}
if (MODE == 1) {
if (ALGORITHM == 2) {
for (char j = 0; j < WIDTH; j++) {
leds[XY(HEIGHT / 2, j)] = CRGB(0, 255, 0);
leds[XY(HEIGHT / 2 - 1, j)] = CRGB(0, 255, 0);
}
}
MODE = 2;
}
else if (MODE == 2) {
if (ALGORITHM == 2) {
for (char j = 0; j < WIDTH; j++) {
leds[XY(0, j)] = CRGB(0, 255, 0);
}
}
MODE = 1;
}
}
void loop() {
if (digitalRead(BUTTON_PIN) == LOW)
lenPush += 1;
else if (digitalRead(BUTTON_PIN) != LOW && lenPush != 0) {
if (lenPush < 10)
SetNextMode();
else
SetNextAlgorithm();
lenPush = 0;
}
NewBrightness();
if (ALGORITHM == 1) {
Oscillogram();
delay(8);
}
else if (ALGORITHM == 2)
Power_spectrum();
FastLED.show();
//delay(50);
}