Анализатор спектра на SH1106 OLED 1.3″ (Arduino)

SH1106 OLED 1.3″ — OLED-дисплей с контроллером SH1106. Этот дисплей имеет разрешение 128×64 пикселей и может отображать монохромную графику и текст. Он может использоваться для различных проектов, где нужно отобразить информацию компактным и энергосберегающим способом. Дисплей легко подключается к микроконтроллерам и одноплатным компьютерам, таким как Arduino или Raspberry Pi, используя интерфейс SPI или I2C.

На OLED дисплее можно сделать простой анализатор спектра аудио сигнала.

Анализатор спектра выполнен на базе микроконтроллера LGT8F328P. Используется плата разработчика LGT8F328P-LQFP32 MiniEVB.

Плата LGT8F328P-LQFP32 MiniEVB 

LGT8F328P-LQFP32 MiniEVB — это миниатюрная платформа разработки с микроконтроллером LGT8F328P в корпусе LQFP32. Этот микроконтроллер совместим с ATmega328P, имеет тактовую частоту до 32 МГц и 32 Кб флэш-памяти. MiniEVB оснащена USB-интерфейсом, который позволяет программировать и отлаживать микроконтроллер, а также подключить его к компьютеру. Кроме того, на плате есть разъемы для питания, монтажа дополнительных периферийных устройств и раздельного доступа к пинам микроконтроллера. Эта платформа разработки может быть использована для создания различных электронных проектов, начиная от простых LED-мигалок до сложных устройств на базе микроконтроллера.

Как добавить поддержку LGT8F328P (плата) в Arduino IDE и прошить микроконтроллер написано в LGT8F328P-LQFP32 MiniEVB в Arduino IDE.

#define AUTO_GAIN 1       // автонастройка по громкости (экспериментальная функция)
#define VOL_THR 25        // порог тишины (ниже него отображения на матрице не будет)
#define LOW_PASS 20       // нижний порог чувствительности шумов (нет скачков при отсутствии звука)
#define DEF_GAIN 80       // максимальный порог по умолчанию (при GAIN_CONTROL игнорируется)
#define FHT_N 256         // ширина спектра х2
#define LOG_OUT 1

// вручную забитый массив тонов, сначала плавно, потом круче
byte posOffset[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};//1500 Hz
//byte posOffset[16] = {1, 2, 3, 4, 6, 8, 10, 13, 16, 20, 25, 30, 35, 40, 45, 50};//4000 Hz

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))

#include <Wire.h>
#include <U8glib.h>  // http://rcl-radio.ru/wp-content/uploads/2023/04/U8glib.zip
#include <FHT.h>     // http://forum.rcl-radio.ru/misc.php?action=pan_download&item=297&download=1

U8GLIB_SH1106_128X64 myOLED(U8G_I2C_OPT_DEV_0|U8G_I2C_OPT_FAST);  // Dev 0, Fast I2C / TWI
 
  byte gain = DEF_GAIN;   
  unsigned long gainTimer,times;
  byte maxValue, maxValue_f;
  float k = 0.1;
  byte ur[16],urr[16];
  
void setup() {
  delay(100); 
  sbi(ADCSRA, ADPS2);
  cbi(ADCSRA, ADPS1);
  sbi(ADCSRA, ADPS0);
  Serial.begin(9600);
  Wire.begin();Wire.setClock(800000L);
  myOLED.begin();
 // myOLED.setRot180();
  myOLED.setFont(u8g_font_profont11r);
  analogReadResolution(10);// АЦП 10 БИТ
  analogReference(INTERNAL1V024);
  pinMode(A0,INPUT); // INPUT AUDIO
}
 
void loop() {
 analyzeAudio();
/////// PRINT OLED /////////////////////////////////
 myOLED.firstPage();  
  do {
 for (int pos = 0; pos < 128; pos+=8) {
 int posLevel = map(fht_log_out[posOffset[pos/8]], LOW_PASS, gain, 0, 60);
   posLevel = constrain(posLevel, 0, 60);
   if(millis()-times<2000){posLevel=60;}     
     urr[pos] = posLevel;
     if(urr[pos]<ur[pos]){ur[pos]=ur[pos]-1;}
      else{ur[pos] = posLevel;}
      delayMicroseconds(200); 
 for (int v_pos=0; v_pos<ur[pos]+4;v_pos+=4){myOLED.drawBox(pos, 61-v_pos, 6, 2);}}
  } while( myOLED.nextPage() );
//////////////////////////////////
 if (AUTO_GAIN) {
    maxValue_f = maxValue * k + maxValue_f * (1 - k);
    if (millis() - gainTimer > 1500) {      // каждые 1500 мс
      // если максимальное значение больше порога, взять его как максимум для отображения
      if (maxValue_f > VOL_THR) gain = maxValue_f;
      // если нет, то взять порог побольше, чтобы шумы вообще не проходили
      else gain = 100;
      gainTimer = millis();
    }
  }
}// end loop
 
void analyzeAudio() {
  for (int i = 0 ; i < FHT_N ; i++) {
    int sample = analogRead(A0);
    fht_input[i] = sample; // put real data into bins
  }
  fht_window();  // window the data for better frequency response
  fht_reorder(); // reorder the data before doing the fht
  fht_run();     // process the data in the fht
  fht_mag_log(); // take the output of the fht
}

Comments

  1. Приветствую!
    Третий столбец живет своей жизнью, при закрытом входе шкалит, что может быть?
    Платы LGT8F и лиловые и зеленые ведут себя одинаково, как собственно и обычная ардуино нано.

      1. Даже при питании от аккумулятора и закороченном на землю нулевом пине, столбик бегает и в двух местах имеет разрывы. Точно не наводка. Может библиотека какая кривовата?

        1. 1.Можно попробовать поменять вход. Исправьте А0 на А3 (в двух местах скетча)
          2.изменить диапазон
          byte posOffset[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};//1500 Hz
          //byte posOffset[16] = {1, 2, 3, 4, 6, 8, 10, 13, 16, 20, 25, 30, 35, 40, 45, 50};//4000 Hz
          заменить на
          //byte posOffset[16] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};//1500 Hz
          byte posOffset[16] = {1, 2, 3, 4, 6, 8, 10, 13, 16, 20, 25, 30, 35, 40, 45, 50};//4000 Hz
          3. изменить настройки анализатора
          #define VOL_THR 25 // порог тишины (ниже него отображения на матрице не будет)
          #define LOW_PASS 20 // нижний порог чувствительности шумов (нет скачков при отсутствии звука)
          #define DEF_GAIN 80 // максимальный порог по умолчанию (при GAIN_CONTROL игнорируется)

          увеличить некоторые параметры
          например
          #define VOL_THR 45 // порог тишины (ниже него отображения на матрице не будет)
          #define LOW_PASS 40 // нижний порог чувствительности шумов (нет скачков при отсутствии звука)
          #define DEF_GAIN 120 // максимальный порог по умолчанию (при GAIN_CONTROL игнорируется)

          1. Доброго, короче, в 47й строке «for (int pos = 0; pos < 128; pos+=8)" заменил на "for (int pos = 0; pos < 128; pos+=10)", при этом потерял три столбика, (что компенсировал их шириной), но проблема ушла. Третий столбик глючить перестал и устройство заработало красиво. Спасибо за помощь!

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

Войти с помощью: