Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей... |
18.03.2014, 19:18
|
|
Администратор
Регистрация: 10.05.2003
Сообщений: 1,739
Сказал спасибо: 497
Сказали Спасибо 2,686 раз(а) в 595 сообщении(ях)
|
Графический анализатор спектра на Arduino
Надо было тут кое-куда быстро прикрутить сию конструкцию. Делюсь с вами.
Имеем Arduino Uno и дисплей на светодиодных матрицах (когда-то давно покупал на ибее: http://www.ebay.com/itm/LED-Lattice-...-/400375652285 )
В протоколе дисплея можно разобраться по исходнику, переписав функцию вывода столбцов на него, можно использовать любой дисплей, можно и на MAX7219 собрать).
Использовал готовую библиотеку FFT - по Фурье раскладывает спектр. Функция возвращает массив из 64 значений, а значит можно использовать дисплей 64х16, будет зрелищнее)) Три режима - сплошные столбики, пиковые точки и смешанный режим.
Вторая библиотека - TimerOne. Пришлось использовать прерывание, из-за того, что в свободном цикле функция преобразования Фурье работает слишком долго, а моя платка индикаторов без памяти (с MAX7219/21 можно будет рисовать без прерывания), и контроллер не успевает регенерировать картинку.
В конечном итоге все это будет собрано на Arduino Mini (2.5$) и 8 матричных индикаторах с MAX7219 на каждом (5$+4$), т.е будет 32-полосный эквалайзер. Операционник LM386 (первое, что было под рукой). Печатка, кнопка, пассивные детальки... Цена конструкции выйдет баксов 15. Неплохо))
Фотки, "схемка", исходник/скетч, библиотека FFT и видео - во вложении. Будут вопросы по программе и некоторым нюансам, задавайте - отвечу. Пользуйтесь на здоровье, дорогие форумчане!
Видео работы:
Вложения:
|
eq.rar (242.6 Кб, 630 просмотров) |
|
|
|
Эти 9 пользователя(ей) сказали Спасибо mikesmith за это сообщение:
|
|
|
18.03.2014, 19:21
|
|
Администратор
Регистрация: 10.05.2003
Сообщений: 1,739
Сказал спасибо: 497
Сказали Спасибо 2,686 раз(а) в 595 сообщении(ях)
|
Re: Графический анализатор спектра на Arduino
Код:
Код:
|
#include ‹TimerOne.h› // Библиотека для таймера
#include ‹fix_fft.h› // Библиотека для преобразований Фурье
int i = 0;
int v[16], w[16];
char im[128], data[128];
int ModeState = 0; // Режим отображения: 0 - Обычный, 1 - Пиковые значения, 2 - Смешанный
boolean ButtonModeState = false;
int D_port = 7;
int C_port = 6;
int B_port = 5;
int A_port = 4;
int G_port = 3;
int DI_port = 2;
int CLK_port = 1;
int Latch_port = 0;
int Sound_input = A0;
const int ButtonModePin = 8;
void setup()
{
ADCSRA = (1‹‹ADEN)|(1‹‹ADPS0)|(0‹‹ADPS1)|(1‹‹ADPS2); // Устанавливаем частоту дискретизации АЦП - sps=500k ~f=10k
analogReference(DEFAULT); // Опорное напряжение для AЦП - 5 вольт
pinMode(ButtonModePin, INPUT); // Вход, к которому подключена кнопка выбора режимов
digitalWrite(ButtonModePin, HIGH); // Подключаем подтягивающий (+) резистор к кнопке
pinMode(D_port, OUTPUT); // Выводы индикатора
pinMode(C_port, OUTPUT);
pinMode(B_port, OUTPUT);
pinMode(A_port, OUTPUT);
pinMode(G_port, OUTPUT);
pinMode(DI_port, OUTPUT);
pinMode(CLK_port, OUTPUT);
pinMode(Latch_port, OUTPUT);
Timer1.initialize(10000); // Инициализируем прерывания по таймеру для вывода данных на дисплей
Timer1.attachInterrupt(Timer1_action);
}
void Timer1_action() // Обработка прерывания от таймера - перерисовываем дисплей
{
for (int t=0;t‹16;t++)
{
HC595_Data_Send(v[t], t);
delayMicroseconds(200);
}
delayMicroseconds(300);
digitalWrite(G_port, 1);
}
void HC595_Data_Send(int da, int han) // Процедура вывода одного столбца на дисплей
{
digitalWrite(Latch_port, 0);
digitalWrite(CLK_port, 0);
for (int i=16;i›0;i--)
{
if (ModeState == 0) // обычный режим
{
if (da › i) digitalWrite(DI_port, 0); else digitalWrite(DI_port, 1);
}
if (ModeState == 1) // пиковый режим
{
if (da == i+1) digitalWrite(DI_port, 0); else digitalWrite(DI_port, 1);
}
if (ModeState == 2) // смешанный режим
{
if (da › 7)
{
if (da == i-1 || da › i) digitalWrite(DI_port, 0); else digitalWrite(DI_port, 1);
}
else
{
if (da › i) digitalWrite(DI_port, 0); else digitalWrite(DI_port, 1);
}
}
digitalWrite(CLK_port, 1);
digitalWrite(CLK_port, 0);
}
digitalWrite(G_port, 1);
switch (han)
{
case 0: digitalWrite(A_port, 0); digitalWrite(B_port, 0); digitalWrite(C_port, 0); digitalWrite(D_port, 0); break;
case 1: digitalWrite(A_port, 1); digitalWrite(B_port, 0); digitalWrite(C_port, 0); digitalWrite(D_port, 0); break;
case 2: digitalWrite(A_port, 0); digitalWrite(B_port, 1); digitalWrite(C_port, 0); digitalWrite(D_port, 0); break;
case 3: digitalWrite(A_port, 1); digitalWrite(B_port, 1); digitalWrite(C_port, 0); digitalWrite(D_port, 0); break;
case 4: digitalWrite(A_port, 0); digitalWrite(B_port, 0); digitalWrite(C_port, 1); digitalWrite(D_port, 0); break;
case 5: digitalWrite(A_port, 1); digitalWrite(B_port, 0); digitalWrite(C_port, 1); digitalWrite(D_port, 0); break;
case 6: digitalWrite(A_port, 0); digitalWrite(B_port, 1); digitalWrite(C_port, 1); digitalWrite(D_port, 0); break;
case 7: digitalWrite(A_port, 1); digitalWrite(B_port, 1); digitalWrite(C_port, 1); digitalWrite(D_port, 0); break;
case 8: digitalWrite(A_port, 0); digitalWrite(B_port, 0); digitalWrite(C_port, 0); digitalWrite(D_port, 1); break;
case 9: digitalWrite(A_port, 1); digitalWrite(B_port, 0); digitalWrite(C_port, 0); digitalWrite(D_port, 1); break;
case 10: digitalWrite(A_port, 0); digitalWrite(B_port, 1); digitalWrite(C_port, 0); digitalWrite(D_port, 1); break;
case 11: digitalWrite(A_port, 1); digitalWrite(B_port, 1); digitalWrite(C_port, 0); digitalWrite(D_port, 1); break;
case 12: digitalWrite(A_port, 0); digitalWrite(B_port, 0); digitalWrite(C_port, 1); digitalWrite(D_port, 1); break;
case 13: digitalWrite(A_port, 1); digitalWrite(B_port, 0); digitalWrite(C_port, 1); digitalWrite(D_port, 1); break;
case 14: digitalWrite(A_port, 0); digitalWrite(B_port, 1); digitalWrite(C_port, 1); digitalWrite(D_port, 1); break;
case 15: digitalWrite(A_port, 1); digitalWrite(B_port, 1); digitalWrite(C_port, 1); digitalWrite(D_port, 1); break;
}
digitalWrite(Latch_port, 1);
digitalWrite(G_port, 0);
digitalWrite(Latch_port, 0);
}
void loop()
{
for (i=0;i‹128;i++) // Считываем значение с аналогового входа в массив
{
data[i] = analogRead(Sound_input);
im[i] = 0;
}
fix_fft(data, im, 7, 0); // Преобразование Фурье
for (i=0;i‹64;i++)
{
data[i] = sqrt(data[i] * data[i] + im[i] * im[i]); // Считаем и делаем значения положительными
}
for (i=1;i‹16;i++) // Считаем значение для каждого столбца (отбрасываем первый - там помехи и фон 50Гц)
{
w[i] = v[i];
v[i] = (data[i*4] + data[i*4+1] + data[i*4+2] + data[i*4+3])/4; // Считаем среднее арифметическое соседних столбцов, так как у нас их всего 16, а в массиве 64
if (v[i] › 15) v[i] = 15;
if (v[i] ‹ w[i]) v[i] = w[i]-0.1; // Плавное угасание столбцов, как в профессиональном эквалайзере
}
v[0] = v[1]/2; // Значение первого столбца самых нижних частот (в котором фон 50Гц) получаем, разделив следующий на 2
if (digitalRead(ButtonModePin) == LOW&&!ButtonModeState) // Обработка кнопочных нажатий
{
ModeState = ++ModeState;
if (ModeState › 2) ModeState = 0;
ButtonModeState = true;
delay(5);
}
if (digitalRead(ButtonModePin) == HIGH&&ButtonModeState)
{
ButtonModeState = false;
delay(5);
}
} |
|
|
|
Эти 6 пользователя(ей) сказали Спасибо mikesmith за это сообщение:
|
|
|
20.03.2014, 10:59
|
|
Прописка
Регистрация: 13.03.2007
Сообщений: 135
Сказал спасибо: 7
Сказали Спасибо 37 раз(а) в 22 сообщении(ях)
|
Re: Графический анализатор спектра на Arduino
Спасибо, грамотно сделано!
|
|
|
|
20.03.2014, 12:15
|
|
Администратор
Регистрация: 10.05.2003
Сообщений: 1,739
Сказал спасибо: 497
Сказали Спасибо 2,686 раз(а) в 595 сообщении(ях)
|
Re: Графический анализатор спектра на Arduino
Спасибо. Кстати, не помешает 100К резистор между землей и катодом диода, чтобы при отсутствии сигнала, на входе АЦП не было фона или помех. Пририсовал его на схемке. Также внес небольшие изменения в код (архив в первом посте уже с изменениями), теперь при отсутствии сигнала нету небольших выбросов на дисплее.
|
|
|
Сказали "Спасибо" mikesmith
|
|
|
09.04.2014, 09:52
|
|
Администратор
Регистрация: 10.05.2003
Сообщений: 1,739
Сказал спасибо: 497
Сказали Спасибо 2,686 раз(а) в 595 сообщении(ях)
|
Re: Графический анализатор спектра на Arduino
Друзья, так как я пень пнем в делах аналоговых, нужна ваша "аналоговая" помощь. Настал момент сборки, и нужно нарисовать схемку предусилителя с АРУ.
Питание 5В. Либо на MCP6002, либо на LM358/LM324.
Сигнал будет идти со звуковой карты компьютера, на выходе надо получить сигнал 0-5В. АРУ - обязательно.
Буду признателен за любые советы/наброски.
|
|
|
|
04.05.2014, 00:50
|
|
Прохожий
Регистрация: 04.05.2014
Сообщений: 9
Сказал спасибо: 0
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Графический анализатор спектра на Arduino
Друзья, подскажите пжалуйста - обираю эту схему! не пойму - если вместо ардуино подключить динамик - то он просто хрипит и звук какойто искаженный, а если поставить кандер на 250мФ как по даташиту то звук боле менее нормальный, так должно быть? я динамик подключал для проверки - пойдет ли сигнал на ардуино. Ардуино пока не подключал...
|
|
|
|
04.05.2014, 12:08
|
|
Гражданин KAZUS.RU
Регистрация: 01.09.2007
Сообщений: 898
Сказал спасибо: 278
Сказали Спасибо 57 раз(а) в 54 сообщении(ях)
|
Re: Графический анализатор спектра на Arduino
Сообщение от mikesmith
|
АРУ - обязательно.
|
А это у вас нужно спросить если честно...
Автоматическая Регулировка Усиления.....
Если без АРУ.... То в зависимости от уровня сигнала выдаваемого звуковой картой, нужно будет подстраивать переменный резистор. Который у вас в схеме. Если это устраивает можно и без АРУ.
Если не устраивает то придумываем схему АРУ...
|
|
|
|
04.05.2014, 12:10
|
|
Гражданин KAZUS.RU
Регистрация: 01.09.2007
Сообщений: 898
Сказал спасибо: 278
Сказали Спасибо 57 раз(а) в 54 сообщении(ях)
|
Re: Графический анализатор спектра на Arduino
Сообщение от fivist
|
Друзья, подскажите пжалуйста - обираю эту схему! не пойму - если вместо ардуино подключить динамик - то он просто хрипит и звук какойто искаженный, а если поставить кандер на 250мФ как по даташиту то звук боле менее нормальный, так должно быть? я динамик подключал для проверки - пойдет ли сигнал на ардуино. Ардуино пока не подключал...
|
Динамик имеет сопротивление на много меньше чем вход АЦП на Ардуино.
Делаем выводы.
|
|
|
|
04.05.2014, 19:35
|
|
Администратор
Регистрация: 10.05.2003
Сообщений: 1,739
Сказал спасибо: 497
Сказали Спасибо 2,686 раз(а) в 595 сообщении(ях)
|
Re: Графический анализатор спектра на Arduino
fivist, собирайте так, как указано (LM386 - это УЗЧ, его я поставил только потому, что ничего больше под рукой не оказалось). Входное сопротивление ардуинки намного выше сопротивления динамика, как вам ответили выше.
В скором времени выложу более навороченный вариант устройства с дисплеем 32х16.
|
|
|
|
06.05.2014, 10:53
|
|
Прохожий
Регистрация: 04.05.2014
Сообщений: 9
Сказал спасибо: 0
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: Графический анализатор спектра на Arduino
Уважаемые, собрал такую схему! что в ней не так, постоянно открыты ключи на BC557 транзисторе, в матрице столбец постоянно светится, digitalWrite(номер пина, HIGH); или digitalWrite(номер пина, LOW); ничего не дают. Может я не так что то подключаю? что сдесь не правильно?
пример тестового скетча:
Код:
|
#include ‹SPI.h›
enum { REG = 8 }; // пин, управляющий защёлкой (SS в терминах SPI)
int col_1 = 2;
int col_2 = 3;
int col_3 = 4;
int col_4 = 5;
int col_5 = 6;
int col_6 = 7;
int col_7 = 9;
/* Теперь шлём по 16 бит. Важный момент: так как по умолчанию
* данные передаются, начиная со старшего бита, сначала нужно
* послать старший байт, затем - младший - тогда всё 16 бит
* передадутся в правильном порядке.
*/
void writeShiftRegister16(int ss_pin, uint16_t value)
{
digitalWrite(ss_pin, LOW);
/* Фокус вот в чём: сначала шлём старший байт */
SPI.transfer(highByte(value));
/* А потом младший */
SPI.transfer(lowByte(value));
digitalWrite(ss_pin, HIGH);
}
/* Слегка изменим функцию для работы с 16-битными значениями */
void rotateLeft(uint16_t &bits)
{
uint16_t high_bit = bits & (1 ‹‹ 15) ? 1 : 0;
bits = (bits ‹‹ 1) | high_bit;
}
void setup() {
pinMode(col_1, OUTPUT);
pinMode(col_2, OUTPUT);
pinMode(col_3, OUTPUT);
pinMode(col_4, OUTPUT);
pinMode(col_5, OUTPUT);
pinMode(col_6, OUTPUT);
pinMode(col_7, OUTPUT);
digitalWrite(col_1, HIGH);
digitalWrite(col_2, HIGH);
digitalWrite(col_3, HIGH);
digitalWrite(col_4, HIGH);
digitalWrite(col_5, HIGH);
digitalWrite(col_6, HIGH);
digitalWrite(col_7, HIGH);
SPI.begin();
pinMode(REG, OUTPUT);
writeShiftRegister16(REG, 0);
}
// the loop routine runs over and over again forever:
void loop() {
uint16_t nomad = 1;
for(int i = 0; i ‹ 10; i++){ // в данный момент матрица на 10 столбиков!
// writeShiftRegister16(REG, 0);
// digitalWrite(col_1, HIGH);
// delay(300);
// digitalWrite(col_1, LOW);
// writeShiftRegister16(REG, 0);
// delay(300);
// digitalWrite(col_2, HIGH);
// delay(300);
// digitalWrite(col_2, LOW);
// writeShiftRegister16(REG, 0);
// delay(300);
writeShiftRegister16(REG, nomad);
rotateLeft(nomad);
delay(250);
}
} |
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 14:37.
|
|