Цифровой VU meter с OLED дисплеем. Arduino проект для начинающих

VU meter, OLED display and Arduino, photo
VU meter, OLED display and Arduino, photo

В сегодняшней статье пойдёт речь о том, как сделать цифровой VU meter, он же измеритель уровня звука, используя Arduino и OLED дисплей, своими руками(DIY). Устройство довольно таки простое, для начинающих это будет полезный опыт. Разумеется, как высокоточный прибор измерения уровня звука оно не годится, но как показометр — вполне.

Содержание:

  1. Видео с демонстрацией работы
  2. Купить комплектующие для проекта из Китая
  3. Схема подключения
  4. Код для Arduino
  5. Ссылки по проекту

Видео с демонстрацией работы

В данном ролике продемонстрирована работа проекта, к тому же он полностью дублирует статью в видео формате, длительность 2 минуты 9 секунд.

Купить комплектующие для проекта из Китая

Заметьте, Ардуино Нано подходит только версия на основе ATmega328(V3.0), и ещё — плата будет в распаянном виде, придётся подыметь паяльником. Mini USB кабеля в комплекте не будет, поэтому понадобится его достать отдельно.

Правда у этих дисплеев есть один недостаток — со временем у них выгорают пиксели, относительно небольшой ресурс, имейте это ввиду.

Ну и подразумевается что провода, макетная плата, mini-USB кабель и 3.3-5В источник питания есть под рукой.

Схема подключения

Электрическая схема подключения выглядит следующим образом:

Цифровой VU meter с OLED дисплеем. Arduino проект для начинающих, электрическая схема
Кликайте чтобы открыть в полном размере

На макетной плате это выглядит вот так:

Схема VUmeter, OLED и Arduino, на макетной плате
Кликайте чтобы открыть в полном размере

Ключевым элементом схемы является резистор R1 на 10 кОм, он нужен для того, чтобы защитный диод AVR микроконтроллера не влиял на качество звучания устройства, да и чисто с целей защиты микроконтроллера он там не будет лишним. Резистором R2 осуществляется подстройка максимального уровня сигнала, можно взять любой другой номинал от 1 кОм до 100 кОм, в случае подключения к аудиовыходу компьютера идеально подходит 10 кОм. Чувствительность составляет всего лишь 1.1 В при дефолтных настройках скетча.

Диапазон питания у схемы довольно таки широкий, от 3.3 до 5 В(рекомендовано 5 В), правда чем ниже напряжение, тем ниже яркость свечения дисплея, что и было продемонстрировано на видео в начале статьи.

Код для Arduino

Исходники к проекту так же можно найти в архиве к статье, или же вот они по отдельности:

display.c

#include <avr/pgmspace.h>

// VU meter background mask image:
const uint8_t VUMeter[] PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
  0x80, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00,
  0x00, 0x40, 0x40, 0x40, 0xC0, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x40, 0xA0, 0xA0, 0x40,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0xA0, 0xA0,
  0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x20, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC0,
  0x20, 0x20, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x64, 0x54, 0x54, 0x58, 0x00, 0x38, 0x44,
  0x44, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x0F, 0x00, 0x07, 0x08, 0x08, 0xC7, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0xF2, 0x01,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xF2,
  0x01, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00,
  0xC0, 0x30, 0x03, 0x00, 0x00, 0x00, 0x00, 0xC1,
  0x32, 0x02, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x80,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x11, 0x15,
  0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0xB8, 0xA8, 0xA8, 0x48, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE0, 0xE0,
  0x86, 0x8C, 0xB8, 0xE0, 0x40, 0x42, 0x4C, 0x30,
  0x20, 0x20, 0x20, 0x10, 0x10, 0x10, 0x13, 0x0C,
  0x08, 0xC8, 0x08, 0x08, 0x08, 0x07, 0x04, 0x04,
  0x04, 0x04, 0x84, 0x84, 0x82, 0x32, 0x83, 0x82,
  0x02, 0x02, 0x02, 0x02, 0x02, 0x82, 0x82, 0x83,
  0x32, 0x82, 0x82, 0x02, 0x03, 0x02, 0x02, 0x02,
  0x03, 0x02, 0x04, 0x04, 0x04, 0x60, 0x0E, 0x0F,
  0x0E, 0x1E, 0x1F, 0x1C, 0x1C, 0x1C, 0x1E, 0x39,
  0x38, 0x38, 0x38, 0x70, 0x7C, 0x73, 0x70, 0xE0,
  0xF0, 0xEC, 0xC0, 0xC0, 0xC0, 0x80, 0xC0, 0xA0,
  0x18, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x08, 0x08, 0x08, 0x7F, 0x08, 0x08, 0x08,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x40, 0x40, 0x20, 0x10, 0x10, 0x08,
  0x08, 0x84, 0x04, 0x04, 0x02, 0x02, 0x01, 0x01,
  0x01, 0x04, 0x08, 0xC0, 0x20, 0x20, 0xC0, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x1A,
  0x0C, 0x0C, 0x12, 0x12, 0x0C, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x05, 0x05, 0x06, 0x03, 0x04, 0x04,
  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x01,
  0x03, 0x04, 0x04, 0x03, 0x00, 0x00, 0x00, 0x00,
  0x01, 0x0F, 0x00, 0x06, 0x09, 0x09, 0x06, 0x06,
  0x09, 0x09, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03,
  0x07, 0x07, 0x0E, 0x0E, 0x0E, 0x1C, 0x1C, 0x38,
  0x38, 0x70, 0x70, 0xE0, 0x60, 0x20, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x01, 0x02, 0x11, 0x08, 0x04, 0x22, 0x50, 0x20,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x0C,
  0x18, 0x30, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00,
  0x00, 0x00, 0x1E, 0x3E, 0x60, 0x40, 0x40, 0x60,
  0x3E, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

[свернуть]

Файл display.c — bitmap(bmp картинка преобразована в массив точек), рисунок кшалы(он должен лежать там же где и файл ArduinoVuOledMeter.ino). Вот собственно он:

VU Meter bitmap (128*64)
VU Meter bitmap (128*64)

Можно нарисовать свой вариант, «но это уже совсем другая история».

Sketch для Ардуино:

ArduinoVuOledMeter.ino

/*
Статья "Цифровой VU meter с OLED дисплеем. Arduino проект для начинающих":
http://www.techn0man1ac.info/arduino/diy-digital-vumeter-oled-and-arduino
Видео "Arduino проект для начинающих. VU meter с OLED дисплеем."
https://youtu.be/qoLsynwssLI
By Techn0man1ac

За основу взят вот этот проект:
https://forum.arduino.cc/index.php?topic=403234.0
*/

#include <OLED_I2C.h> // Library: OLED_I2C http://www.rinkydinkelectronics.com/library.php?id=79

OLED  myOLED(SDA, SCL, 8);

#define analogInput 0 // В этой строчке задаётся аналоговый пин ардуино;
#define HighSens true // режим высокой чувствительности, достигается за счёт изменения опорного напряжения в 1.1 V, 
//может быть как включено true, так и выключено — false, рекомендую включить;
#define FASTADC true // ускорение работы ADC, для Arduino Nano/Uno/Pro Mini рекомендуется включить(true );
#define Sensitivity 1024 // чувствительность, это значение не может быть больше 1024, если Ваш источник аудиосигнала 
//выдаёт небольшое выходное напряжение, то можете попробовать в 2, 4 раза уменьшить это значение;
#define SampleWindow 15  // количество сэмплов, число в миллисекундах, чем оно меньше, тем шустрее дёргается стрелка, 
//по умолчанию 50, но я для себя подобрал 15-20, больше уже ардуина не тянет.

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

extern uint8_t VUMeter[];

int hMeter = 65;                      // horizontal center for needle animation
int vMeter = 85;                      // vertical center for needle animation (outside of dislay limits)
int rMeter = 80;                      // length of needle animation or arch of needle travel

int sample;

void setup() {

  if (HighSens == true) {  // Включить(true)/выключить(false) режим высокой чувствительности
    analogReference(INTERNAL);  //an built-in reference, equal to 1.1 volts on the ATmega168 or ATmega328 
    // and 2.56 volts on the ATmega8 (not available on the Arduino Mega)
    //INTERNAL1V1: a built-in 1.1V reference (Arduino Mega only)
  } else {
    analogReference(DEFAULT);
  }

#if FASTADC
  // set prescale to 16
  sbi(ADCSRA, ADPS2) ;
  cbi(ADCSRA, ADPS1) ;
  cbi(ADCSRA, ADPS0) ;
#endif

  myOLED.begin();          // needed for SH1106 display
  myOLED.clrScr();                                 // clears display from any library info displayed
}

void loop() {

  unsigned long startMillis = millis();                    // start of sample window
  unsigned int PeaktoPeak = 0;                             // peak-to-peak level
  unsigned int SignalMax = 0;
  unsigned int SignalMin = Sensitivity;

  while ( millis() - startMillis < SampleWindow ) {

    sample = analogRead(analogInput);
    if (sample < Sensitivity) {

      if (sample > SignalMax) {

        SignalMax = sample;                                // saves just the max levels
      }

      else if (sample < SignalMin) {

        SignalMin = sample;                                // saves just the min levels
      }
    }
  }

  PeaktoPeak = SignalMax - SignalMin;                      // max - min = peak-peak amplitude
  float MeterValue = PeaktoPeak * 330 / Sensitivity;              // convert volts to arrow information

  MeterValue = MeterValue - 34;                            // shifts needle to zero position
  //myOLED.clrScr();                                // refresh display for next step
  myOLED.drawBitmap(0, 0, VUMeter, 128, 64);       // draws background
  int a1 = (hMeter + (sin(MeterValue / 57.296) * rMeter)); // meter needle horizontal coordinate
  int a2 = (vMeter - (cos(MeterValue / 57.296) * rMeter)); // meter needle vertical coordinate
  myOLED.drawLine(a1, a2, hMeter, vMeter);         // draws needle
  myOLED.update();
}

[свернуть]

За основу был взят вот этот проект, но меня не устроило быстродействие, поэтому я перевёл его на библиотеку OLED_I2C(есть в архиве к статье). Работает относительно быстро, да и ресурсов потребляет не много.

Как добавить библиотеку в Arduino IDE

Всего пару кликов:

Папка библиотеки OLED_I2C должна появится по пути «C:\Users\пользователь\Documents\Arduino\libraries\»

[свернуть]

Пояснение по настройке скетча для Arduino:

#define analogInput 0 // В этой строчке задаётся аналоговый пин ардуино;
#define HighSens true // режим высокой чувствительности, достигается за счёт изменения опорного напряжения в 1.1 V, 
//может быть как включено true, так и выключено — false, рекомендую включить;
#define FASTADC true // ускорение работы ADC, для Arduino Nano/Uno/Pro Mini рекомендуется включить(true );
#define Sensitivity 1024 // чувствительность, это значение не может быть больше 1024, если Ваш источник аудиосигнала 
//выдаёт небольшое выходное напряжение, то можете попробовать в 2, 4 раза уменьшить это значение;
#define SampleWindow 15  // количество сэмплов, число в миллисекундах, чем оно меньше, тем шустрее дёргается стрелка, 
//по умолчанию 50, но я для себя подобрал 15-20, больше уже ардуина не тянет.

Вся магия осуществляется в этих строчках:

  while ( millis() - startMillis < SampleWindow ) {

    sample = analogRead(analogInput);
    if (sample < Sensitivity) {

      if (sample > SignalMax) {

        SignalMax = sample;                                // saves just the max levels
      }

      else if (sample < SignalMin) {

        SignalMin = sample;                                // saves just the min levels
      }
    }
  }

  PeaktoPeak = SignalMax - SignalMin;                      // max - min = peak-peak amplitude
  float MeterValue = PeaktoPeak * 330 / Sensitivity;              // convert volts to arrow information

По сути, мы получаем показометр Vpp(peak to peak).

Ссылки по проекту

Архив к статье;

Использовал библиотеку OLED_I2C;

За основу взят этот проект;

Ускоряем свою Arduino;

Альбом с фотографиями в хорошем качестве;

Подписывайтесь на YouTube мой канал Techn0man1ac.

Ещё видео с проигрыванием музыки

Так же советую посетить рубрику Что почитать или Arduino на моём сайте.

ФуфлоНе оченьНу, так себеНормальноГодно (6 оценок, среднее: 5,00 из 5)
Загрузка...

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

5 × 1 =