Визуализатор спектра

Тема в разделе "Arduino & Shields", создана пользователем rbibokon, 23 май 2017.

  1. rbibokon

    rbibokon Нерд

    Сделанно
     
  2. rbibokon

    rbibokon Нерд

    Че то у меня с этим миниджеком вообще перестали собачки показываться. каку то ахине показыват
     
  3. mcureenab

    mcureenab Гуру

    Может сигнал слабый? Не знаю, в Left или в Right MONO сигнал передается.
     
  4. rbibokon

    rbibokon Нерд

    Го в скайп я все покажу
     
  5. rbibokon

    rbibokon Нерд

    rbibokosha логин скайп
     
  6. rbibokon

    rbibokon Нерд

    Хах разобрался я что было. в итоге начал прозванивать минидеки с двух сторон оказалось что я толи спалил то ли замкнул и в итоге с одной стороны небыло левого канала. в итоге из телефона с лева идет сигнал а приходит на правый. но это мелочи. Все равно не получалось. в итоге понял что на вот этот модуле вход миниджек распиновка там не правильная. Там распиновка идет Земля правый левый от конца. а не наоборот левый правый земля(от провода) В итоге заработали собачки. но погоды это сильно не сделало так как все равно не могу поймать частоты на 1 столбец
     
  7. mcureenab

    mcureenab Гуру

    1 столбец получается когда частота сигнала совпадает с частотой ряда Фурье. Если сигнал промежуточной частоты, его нужно складывать из нескольких элементов ряда Фурье.

    но частота сэмплирования немного дрожит, поэтому алгоритм FFT "видит" не чистый синус, а некий сигнал переменной частоты.

    придётся привлекать аппаратные средства.
     
  8. rbibokon

    rbibokon Нерд

    поможешь?
     
  9. mcureenab

    mcureenab Гуру

    Не заводится пока. Сигнал готовности одиночных сэмплов удалось получить. Но результат первого запроса до запуска замера 0 и первый замер долгий (как по доке написано), результат всех остальных 1023, а должно быть 600-700. Похоже, что у меня коды пинов перепутаны.

    Для free run видимо прерывание нужно делать. Флаг прерывания без прерывания не понятно что делает.
     
  10. mcureenab

    mcureenab Гуру

    Удалось запустить сэмплирование в фоновом режиме free run.
    Действительно замеры идут с равными интервалами. Частоту замеров можно увеличивать за счёт потери разрядов. В отличии от analogRead во время замера можно выполнить какие нибудь вычисления и впасть в спячку. Важно не пропустить момент, когда результат будет готов.

    Вечером доделаю счетч с FFT.
    Сразу не разобрался, что analogRead так же настраивает источник опорного напряжения.
     
  11. rbibokon

    rbibokon Нерд

    ок жду)
     
  12. mcureenab

    mcureenab Гуру

    Код (C++):
    // Dump_A0 FREE RUN ADC
    //

    #define prog_int8_t int8_t

    #include "fix_fft.h"

    #define BITS (7)

    // Для релиза строчку закоментировать
    #define DEBUG


    #ifdef DEBUG
    #define SER
    #else
    #define SER //
    #endif


    #define ASIZE (1<<BITS)

    namespace ADC_module
    {
      // Free Running Conversion
    // ADHSM bit in ADCSRB allows an increased ADC clock frequency
    // prescaling is set by the ADPS bits in ADCSRA
    //  prescaler keeps running for as long as the ADEN bit is set
    //  left adjusted by setting the ADLAR bit in ADMUX
    // no more than 8-bit precision is required, it is sufficient to read ADCH
    // ADCL must be read first, then ADCH

    // e ADC Start Conversion bit, ADSC
    // Auto Triggering is enabled by setting the ADC Auto Trigger Enable bit, ADATE in ADCSRA.
    // trigger source is selected by setting the ADC Trigger Select bits, ADTS in ADCSRB
    // ADC Interrupt Flag as a trigger source makes the ADC start a new conversion as soon as the ongoing
    // conversion has finished. The ADC then operates in Free Running mode
    //  ADSC can also be used to determine if a conversion is in progress.

    enum PS : uint8_t
    {
      PS1   = 0,
      PS2   =                       _BV(ADPS0),
      PS4   =            _BV(ADPS1),
      PS8   =            _BV(ADPS1)|_BV(ADPS0),
      PS32 = _BV(ADPS2)           |_BV(ADPS0),
      PS64  = _BV(ADPS2)|_BV(ADPS1)           ,
      PS128 = _BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0),
      ADCSRA_PS0 = _BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0)
    };

    void clock_source ( PS cs_ )
    {
      ADCSRA = ADCSRA & ~ADCSRA_PS0 | cs_;
    }

    void no_interrupt () //  ADC Interrupt Disable
    {
      ADCSRA &= ~_BV(ADIE);
    }

    bool conversion_complete () // ADC Interrupt Flag
    {
    //  uint8_t res = ADCSRA;
      if ( ADCSRA & _BV(ADIF) )
      {
        ADCSRA |= _BV(ADIF);
        return true;
      }
      return false;
    }

    enum ACHNL : uint8_t {
      ADC0    = 0,
      ADC1    =                                                   _BV(MUX0),
      ADC4    =                               _BV(MUX2),
      ADC5    =                               _BV(MUX2)|          _BV(MUX0),
      ADC6    =                               _BV(MUX2)|_BV(MUX1)          ,
      ADC7    =                               _BV(MUX2)|_BV(MUX1)|_BV(MUX0),
      ACD10x1   =         _BV(MUX4),
      ACD10x10  =                   _BV(MUX3)|                    _BV(MUX0),
      ACD10x40  =_BV(MUX5)|                   _BV(MUX2)|_BV(MUX1)          ,
      ACD10x200 =                   _BV(MUX3)|          _BV(MUX1)|_BV(MUX0),
      ADMUX_  =           _BV(MUX4)|_BV(MUX3)|_BV(MUX2)|_BV(MUX1)|_BV(MUX0),
      GND     =           _BV(MUX4)|_BV(MUX3)|_BV(MUX2)|_BV(MUX1)|_BV(MUX0),
      ADCSRB_ = _BV(MUX5),
      ADC8    = _BV(MUX5),
      ADC9    = _BV(MUX5)|                              _BV(MUX0),
      TSENSR  = _BV(MUX5)|          _BV(MUX2)|_BV(MUX1)|_BV(MUX0), // Temperature Sensor
      A0      =  ADC7,
      A1      =  ADC6,
      A2      =  ADC5,
      A3      =  ADC4,
      A4      =  ADC1,
      A5      =  ADC0,
      A4_5x1  = ACD10x1,
      A4_5x10 = ACD10x10,
      A4_5x40 = ACD10x40,
      A4_5x200= ACD10x200,
    };

    void analog_channel ( ACHNL chnl_ ) // set input channel configuration
    {
        ADMUX  = ADMUX  & ~ADMUX_  | chnl_ & ADMUX_;
        ADCSRB = ADCSRB & ~ADCSRB_ | chnl_ & ADCSRB_;
    }

    enum REFS : uint8_t
    {
      EXT_AREF     = 0, // 0 0 AREF, Internal VREF turned off
      AVCC         =              _BV(REFS0), //  0 1 AVCC with external capacitor on AREF pin
      INTERNAL_256 = _BV(REFS1) | _BV(REFS0), //  1 1 Internal 2.56V Voltage Reference with external capacitor on AREF pin
      REFS_ = INTERNAL_256
    };

    void reference ( REFS rf_ )
    {
        ADMUX = ADMUX & ~REFS_ | rf_ ; // Vcc
    }

    void enable () // ADC Enable
    {
        ADCSRA |= _BV(ADEN);
    }
    void start() // ADC Start Conversion
    {
        ADCSRA |= _BV(ADSC);
    }

    bool in_progress () // A conversion is in progress
    {
        return ADCSRA & _BV(ADSC);
    }

    void auto_trigger () // ADC Auto Trigger Enable
    {
        ADCSRA |= _BV(ADATE);
    }

    enum ATSRC : uint8_t
    {
      FREE_RUN = 0, // Free Running mode
      ADCSRB_ADTS0 = _BV(ADTS3)|_BV(ADTS2)|_BV(ADTS1)|_BV(ADTS0)
    };

    void auto_trigger_src ( ATSRC src_ ) // ADC Auto Trigger Source
    {
        ADCSRB = ADCSRB & ~ADCSRB_ADTS0 | src_;
    }

    void high_speed () //  : ADC High Speed Mode
    {
        ADCSRB |= _BV(ADHSM);
    }

    template <class T> void value_type();
    template <class T> T value(); // ADC conversion is complete, the result is found in these two registers

    template <> void value_type<uint8_t>() // ADC Left Adjust Result
    {
      ADMUX |= _BV(ADLAR);
    }

    template<> uint8_t value<uint8_t> () //  ADC Left Adjust Result 8 bit
    {
      return ADCH; // ignore 2 bis from ADCL
    }

    template <> void value_type<uint16_t>() // ADC Right Adjust Result
    {
      ADMUX &= ~_BV(ADLAR);
    }

    template<> uint16_t value<uint16_t> () //  ADC Right Adjust Result 10 bit
    {
    volatile uint8_t h, l;
      l = ADCL;
      h = ADCH;
      return h << 8 | l;
    }


    };

    const size_t buket_sz[9] = { 1, 1, 2, 2, 4, 6, 10, 14, 20 };

    namespace AD = ADC_module;

    typedef uint16_t val_t;

    void setup() {
      // put your setup code here, to run once:
    SER Serial.begin(250000);
    SER while(!Serial){  }
    SER Serial.println(F("Starting..."));
        AD::reference(AD::AVCC);
        AD::value_type<val_t>(); // тип значения - 8 / 10 бит
        AD::auto_trigger_src( AD::FREE_RUN ); // источник автоматического пускателя
        AD::auto_trigger();  // автоматический запуск ADC
        AD::analog_channel( AD::A0 ); // пин
        AD::high_speed();  //  дополнительное питание для повышения разрядности
        AD::clock_source(AD::PS32); // делитель частоты 16000000 МГц / 32. Нормальная частота сэмплирования  16000000 МГц / 32 / 13 = 38461 Гц. Столбик 300.48077 Гц.
        AD::no_interrupt(); // без прерываний от ADC.
        AD::enable();    // включаем ADC
        AD::start();     // запускаем замеры
    }

    void loop() {
        char re[ASIZE]; //
        char im[ASIZE]; // мнимая часть
        char disp[8];   // дисплей
        uint8_t overload(0);
        for ( uint8_t j = 0 ; j < ASIZE ; ++j )
        {
          while ( ! AD::conversion_complete() ) { }; // ждем сигнала готовности
          re[j] = AD::value<val_t>() - 511;
          im[j] = 0;
          overload = max( overload, abs(re[j]) ); // детектор перегрузки
        }
        if ( 120 < overload )
        {
    SER    Serial.print("OVL\t");
        }
    SER Serial.println((int)overload);
        fix_fft(re, im, BITS, 0);
        for ( size_t i = 0 ; i < ASIZE / 2 ; ++i )
        {
          re[i] = sqrt(re[i] * re[i] + im[i] * im[i]); // Расчет амплитуды комплексного ряда.
        }
    SER Serial.print("Hz:");
    SER for ( size_t i = 0 ; i < ASIZE / 2 ; ++i )
    SER {
    SER   Serial.print('\t');
    SER   Serial.print(16000000L / 32 / 13 * i / 128);
    SER }
    SER Serial.println("");
    SER for ( size_t i = 0 ; i < ASIZE / 2 ; ++i )
    SER {
    SER   Serial.print('\t');
    SER   Serial.print((int)re[i]);
    SER }
    SER Serial.println("");
        size_t *bp = buket_sz;
        size_t k = *(bp++);
        for( uint8_t i = 0; i < 8 ; ++i, ++bp )
        {
          unsigned long datum = 0;
          for ( uint8_t j = 0 ; j < *bp; ++j, ++k )
          {
    //        datum += re[k];
              datum = max(datum, re[k]); // для тестовых сигналов лучше пиковое значение
          }
          disp[i] = datum; //  / buket_sz[i];
    SER   Serial.print('\t');
    SER   Serial.print((int)disp[i]);
        }
    SER Serial.println(F("\n\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@"));
        for ( uint8_t j = 0 ; j < 16 ; ++j ) // заполняем матрицу
        {
          for ( size_t i = 0 ; i < 8 ; ++i )
          {
            if ( j < disp[i] / 5 )
            {
    SER        Serial.print(F("\t@@@@@@"));  // включаем ячейку
            } else {
    SER        Serial.print(F("\t")); // выключаем ячейку
            }      
          }
    SER   Serial.println(F("\t-"));
        }
    SER delay(500); // Задержка чтобы монитор порта не перегружать
    }
     
     
  13. mcureenab

    mcureenab Гуру

    Анализатор спектра звуковых частот
    Мониторит диапазон до 18930 Гц с шагом 300.5 Гц.
    Выводит строкой амплитуду каждой гармоники и столбчатую диаграмму.
    Фиксирует пиковое значение и выводит в Serial признак перегрузки.
    Собирает пиковые значения из диапазонов частот в массив из 8 элементов .
    Не выводит частоту 0 Гц.
     
  14. mcureenab

    mcureenab Гуру

    частота 1417 Гц спектр размыт

    https://drive.google.com/open?id=0B_e3qefdqWwfMk5KWEhaVHRMVE0

    поясню. строка Hz это частоты гармоник.
    под ней числа - амплитуды гармоник.

    дальше строка амплитуды гармоник с группировкой в 8 столбцов для построения гистограммы

    и под ними столбики гистограммы. я их тут широкими сделал на ширину табуляции

    над строкой Hz максимальная амплитуда сигнала. если сигнал слишком мощный появляется слово OVL - перегрузка.
     
    Последнее редактирование: 3 июн 2017
  15. mcureenab

    mcureenab Гуру

    Последнее редактирование: 3 июн 2017
  16. rbibokon

    rbibokon Нерд

    ого, картинки только не загружаются. что для подключения надо?
     
  17. mcureenab

    mcureenab Гуру

    https://drive.google.com/open?id=0B_e3qefdqWwfWVNtT2NubmRrNTQ


    Схема подключения не поменялась. На A0 сигнал с уровнем тишины = 2.5 Вольт. Частота до 20000Гц.

    Шаг частот 300.5 Гц. В басах этого многовато. Я хотел увеличить массив до 256 , тогда разбивка будет по 150 Гц, но скетч завис.

    Тут можно выбрать деление частоты ADC на 64 или 128 (как в analogRead используется). Тогда частота сэмплирования станет меньше в 2 или в 4 раза от нынешней. Но и частотный диапазон анализаторв сожмется.

    Код (C++):
      AD::clock_source(AD::PS32); // делитель частоты 16000000 МГц / 32. Нормальная частота сэмплирования  16000000 МГц / 32 / 13 = 38461 Гц. Столбик 300.48077 Гц.
    Ссылки на фотки поправил. Должны открываться.
     
  18. mcureenab

    mcureenab Гуру

    Вы где библиотеку FFT скачали? Я какую то старую нашел, она даже не собиралась.
     
  19. mcureenab

    mcureenab Гуру

    распиновка аналоговых входов сделана для Leonardo и то не полностью.

    Код (C++):
    enum ACHNL : uint8_t {
    ...
      A0      =  ADC7,
      A1      =  ADC6,
      A2      =  ADC5,
      A3      =  ADC4,
      A4      =  ADC1,
      A5      =  ADC0,
      A4_5x1  = ACD10x1,
      A4_5x10 = ACD10x10,
      A4_5x40 = ACD10x40,
      A4_5x200= ACD10x200,
    };
    по карте
    https://www.arduino.cc/en/Hacking/PinMapping32u4

    для UNO распиновка отличается.
    https://www.arduino.cc/en/Hacking/PinMapping168

    здесь может быть проще выбрать по карте посмотреть како ADCx подключен к Az и указать вместо Az - ADCx

    Код (C++):
        AD::analog_channel( AD::A0 ); // пин
     
  20. mcureenab

    mcureenab Гуру

    Анализатор спектра звукового диапазона (до 18930 Гц) с высокой стабильностью частоты сэмплирования 38461.5 sps.
    Вывод результата в Serial.

    Код (C++):
    // Dump_A0
    // Arduino/Genuino Leonardo, micro ATmega16U4/32U4 FREE RUN MODE Analog Digital Conversion (ADC) 38461.5 sps (sample per second)
    // 8 bit Fix fast Fourier transform 128 samples array 18930 Hz Nyquist frequency. 300.45 Hz step.

    #define prog_int8_t int8_t

    #include "fix_fft.h"

    #define BITS (7)

    // Для релиза строчку закоментировать
    #define DEBUG


    #ifdef DEBUG
    #define SER
    #else
    #define SER //
    #endif


    #define ASIZE (1<<BITS)

    namespace ADC_module
    {
    #define GB( mask, pos, bit )  ( _BV(bit) * ( ( 0b##mask >> pos ) & 1) )

    enum PS : uint8_t
    {
    #define bits( m ) ( GB(m, 2, ADPS2) | GB(m, 1, ADPS1) | GB(m, 0, ADPS0) )
      PS2_  = bits(000),
      PS2   = bits(001),
      PS4   = bits(010),
      PS8   = bits(011),
      PS16  = bits(100),
      PS32  = bits(101),
      PS64  = bits(110),
      PS128 = bits(111),
      ADCSRA_PS1 = bits(111),
    #undef bits
    };


    void clock_source ( PS cs_ )
    {
      ADCSRA = ADCSRA & ~ADCSRA_PS1 | cs_;
    }

    void no_interrupt () //  ADC Interrupt Disable
    {
      ADCSRA &= ~_BV(ADIE);
    }

    inline uint8_t conversion_complete () // ADC Interrupt Flag
    {
        return ADCSRA & _BV(ADIF);
    }

    inline uint8_t wait_conversion () // ADC Interrupt Flag
    {
      uint8_t res(0);
      while( !( ADCSRA & _BV(ADIF) ) ) { if( !(++res) ) { res = 255; } };
      ADCSRA |= _BV(ADIF);
      return res;
    }

    enum ACHNL : uint8_t {

    #define bits( m ) ( GB(m, 5, MUX5) | GB(m, 4, MUX4) | GB(m, 3, MUX3) | GB(m, 2, MUX2) | GB(m, 1, MUX1) | GB(m, 0, MUX0) )
    //                 543210
      ADC0      = bits(000000),
      ADC1      = bits(000001),
      ADC4      = bits(000100),
      ADC5      = bits(000101),
      ADC6      = bits(000110),
      ADC7      = bits(000111),
      ADC8      = bits(100000),
      ADC9      = bits(100001),
      ADC10     = bits(100010), //  ADC10
      ADC11     = bits(100011), //  ADC11
      ADC12     = bits(100100), //  ADC12
      ADC13     = bits(100101), //  ADC13
      TSENSR    = bits(100111), // Temperature Sensor

    // //////////
      ACD41x1   = bits(010100), //   ADC4 ADC1 1x
      ACD51x1   = bits(010101), //   ADC5 ADC1 1x
      ACD61x1   = bits(010110), //   ADC6 ADC1 1x
      ACD71x1   = bits(010111), //   ADC7 ADC1 1x
      ACD40x10  = bits(101000), //  ADC4 ADC0 10x
      ACD50x10  = bits(101001), //  ADC5 ADC0 10x
      ACD60x10  = bits(101010), //  ADC6 ADC0 10x
      ACD70x10  = bits(101011), //  ADC7 ADC0 10x
      ACD41x10  = bits(101100), //  ADC4 ADC1 10x
      ACD51x10  = bits(101101), //  ADC5 ADC1 10x
      ACD61x10  = bits(101110), //  ADC6 ADC1 10x
      ACD71x10  = bits(101111), //  ADC7 ADC1 10x
      ACD40x40  = bits(110000), //  ADC4 ADC0 40x
      ACD50x40  = bits(110001), //  ADC5 ADC0 40x
      ACD60x40  = bits(110010), //  ADC6 ADC0 40x
      ACD70x40  = bits(110011), //  ADC7 ADC0 40x
      ACD41x40  = bits(110100), //  ADC4 ADC1 40x
      ACD51x40  = bits(110101), //  ADC5 ADC1 40x
      ACD61x40  = bits(110110), //  ADC6 ADC1 40x
      ACD71x40  = bits(110111), //  ADC7 ADC1 40x
      ACD40x200 = bits(111000), //  ADC4 ADC0 200x
      ACD50x200 = bits(111001), //  ADC5 ADC0 200x
      ACD60x200 = bits(111010), //  ADC6 ADC0 200x
      ACD70x200 = bits(111011), //  ADC7 ADC0 200x
      ACD41x200 = bits(111100), //  ADC4 ADC1 200x
      ACD51x200 = bits(111101), //  ADC5 ADC1 200x
      ACD61x200 = bits(111110), //  ADC6 ADC1 200x
      ACD71x200 = bits(111111), //  ADC7 ADC1 200x

    // /////////
      ACD10x1   = bits(001000),
      ACD10x10  = bits(001001),
      ACD10x40  = bits(100110), // ADC1 ADC0 40x
      ACD10x200 = bits(001011),
      V1_1      = bits(011110), // 1.1V (VBand Gap)
      V0        = bits(011111), // 0V (GND)
      GND       = bits(011111),
      ADMUX_MUX1= bits(011111),
      ADCSRB_MUX1=bits(100000),
      A0      =  ADC7,
      A1      =  ADC6,
      A2      =  ADC5,
      A3      =  ADC4,
      A4      =  ADC1,
      A5      =  ADC0,
      A4_5x1  = ACD10x1,
      A4_5x10 = ACD10x10,
      A4_5x40 = ACD10x40,
      A4_5x200= ACD10x200,
    };

    void analog_channel ( ACHNL chnl_ ) // set input channel configuration
    {
        ADMUX  = ADMUX  & ~ADMUX_MUX1  | chnl_ & ADMUX_MUX1;
        ADCSRB = ADCSRB & ~ADCSRB_MUX1 | chnl_ & ADCSRB_MUX1;
    }

    enum REFS : uint8_t
    {
    #define bits( m ) ( GB(m, 1, REFS1) | GB(m, 0, REFS0) )
      EXT_AREF     = bits(00), // 0 0 AREF, Internal VREF turned off
      AVCC         = bits(01), // 0 1 AVCC with external capacitor on AREF pin
      INTERNAL_256 = bits(11), // 1 1 Internal 2.56V Voltage Reference with external capacitor on AREF pin
      ADMUX_REFS1  = bits(11)
    #undef bits
    };

    void reference ( REFS rf_ )
    {
        ADMUX = ADMUX & ~ADMUX_REFS1 | rf_ ; // Vcc
    }

    void enable () // ADC Enable
    {
        ADCSRA |= _BV(ADEN);
    }

    void start() // ADC Start Conversion
    {
        ADCSRA |= _BV(ADSC);
    }

    bool in_progress () // A conversion is in progress
    {
        return ADCSRA & _BV(ADSC);
    }

    void auto_trigger () // ADC Auto Trigger Enable
    {
        ADCSRA |= _BV(ADATE);
    }

    enum ATSRC : uint8_t
    {
      FREE_RUN = 0, // Free Running mode
      ADCSRB_ADTS0 = _BV(ADTS3)|_BV(ADTS2)|_BV(ADTS1)|_BV(ADTS0)
    };

    void auto_trigger_src ( ATSRC src_ ) // ADC Auto Trigger Source
    {
        ADCSRB = ADCSRB & ~ADCSRB_ADTS0 | src_;
    }

    void high_speed () //  : ADC High Speed Mode
    {
        ADCSRB |= _BV(ADHSM);
    }

    template <class T> void value_type();
    template <class T> inline T value(); // ADC conversion is complete, the result is found in these two registers

    template <> void value_type<uint8_t>() // ADC Left Adjust Result
    {
      ADMUX |= _BV(ADLAR);
    }

    template<> inline uint8_t value<uint8_t> () //  ADC Left Adjust Result 8 bit
    {
      return ADCH; // ignore 2 bis from ADCL
    }

    template <> void value_type<uint16_t>() // ADC Right Adjust Result
    {
      ADMUX &= ~_BV(ADLAR);
    }

    template<> inline uint16_t value<uint16_t> () //  ADC Right Adjust Result 10 bit
    {
      return ADC;
    }


    };

    const size_t buket_sz[9] = { 1, 1, 2, 2, 4, 6, 10, 14, 20 };
    const char   height[8]   = { 3, 4, 6, 8, 11, 15, 21, 30 };  // порог амплитуды для высоты столбика. логарифмическая шкала 41/1.39

    namespace AD = ADC_module;

    typedef uint16_t val_t;

    void setup() {
      // put your setup code here, to run once:
    SER Serial.begin(250000);
    SER while(!Serial){  }
    SER Serial.println(F("Starting..."));
        AD::reference(AD::AVCC);
        AD::value_type<val_t>(); // тип значения - 8 / 10 бит
        AD::auto_trigger_src( AD::FREE_RUN ); // источник автоматического пускателя
        AD::auto_trigger();  // автоматический запуск ADC
        AD::analog_channel( AD::A0 ); // пин
        AD::high_speed();  //  дополнительное питание для повышения разрядности
        AD::clock_source( AD::PS32 ); // делитель частоты 16000000 МГц / 32. Нормальная частота сэмплирования  16000000 МГц / 32 / 13 = 38461 Гц. Столбик 300.48077 Гц.
        AD::no_interrupt(); // без прерываний от ADC.
        AD::enable();    // включаем ADC
        AD::start();     // запускаем замеры
    }

    void loop() {
        char re[ASIZE]; //
        char im[ASIZE]; // мнимая часть
        char disp[8];   // дисплей
        uint8_t overload(0);  // Пиковый уровень сигнала для детектора перегрузки;
        uint8_t overtime(255);  // Минимальное время ожидания готовности.
        char *pre = re;
        char *pim = im;
        AD::wait_conversion();  // тут фактически только сброс флага готовности, но очередной сэмпл может быть на подходе
        AD::wait_conversion();  // для рассчёта overtime дождёмся начала сэмпла
        for ( uint8_t j = ASIZE ; --j ; )
        {
          uint8_t wait(
              AD::wait_conversion()
            );
          char v = (AD::value<val_t>() - 511)>>1;
          *(pre++) = v;
          *(pim++) = 0;
          v = abs(v);
          overload = max( overload, v ); // детектор перегрузки
          overtime = min( overtime, wait );
        }
        if ( 120 < overload )
        { // что то делаем в случае перегрузки. если 127 <= overload FFT может выдавать искаженный результат.
    SER    Serial.print(" OLD");
        }
    SER Serial.print('\t');
    SER Serial.print((int)overload);
        if ( 0 == overtime )
        { // что то делаем в случае недостаточной скорости чтения сэмплов
    SER    Serial.print(" OTM");
        }
    SER Serial.print('\t');
    SER Serial.println((int)overtime);
    /*
        pim = im;
        for ( uint8_t j = ASIZE ; --j ; )
        {
          Serial.print('\t');
          Serial.print((int)*(pim++));
        }
        Serial.print('\n');
     
        memset ( im, 0, ASIZE);
    */

        fix_fft(re, im, BITS, 0);
        for ( size_t i = 0 ; i < ASIZE / 2 ; ++i )
        {
          re[i] = sqrt(re[i] * re[i] + im[i] * im[i]); // Расчет амплитуды комплексного ряда.
        }
    SER Serial.print("Hz:");
    SER for ( size_t i = 0 ; i < ASIZE / 2 ; ++i )
    SER {
    SER   Serial.print('\t');
    SER   Serial.print(16000000L / 32 / 13 * i / 128);
    SER }
    SER Serial.println("");
    SER for ( size_t i = 0 ; i < ASIZE / 2 ; ++i )
    SER {
    SER   Serial.print('\t');
    SER   Serial.print((int)re[i]);
    SER }
    SER Serial.println("");
        size_t *bp = buket_sz;
        size_t k = *(bp++);
        for( uint8_t i = 0; i < 8 ; ++i, ++bp )
        {
          unsigned long datum = 0;
          for ( uint8_t j = 0 ; j < *bp; ++j, ++k )
          {
    //        datum += re[k];
              datum = max(datum, re[k]); // для тестовых сигналов лучше пиковое значение
          }
          disp[i] = datum; //  / buket_sz[i];
    SER   Serial.print('\t');
    SER   Serial.print((int)disp[i]);
        }
    SER Serial.println(F("\n\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@\t@@@@@@"));
        for ( uint8_t j = 0 ; j < 8 ; ++j ) // заполняем матрицу
        {
          for ( uint8_t i = 0 ; i < 8 ; ++i )
          {
            if ( height[j] <= disp[i] )
            {
    SER        Serial.print(F("\t@@@@@@"));  // включаем ячейку
            } else {
    SER        Serial.print(F("\t")); // выключаем ячейку
            }    
          }
    SER   Serial.println(F("\t-"));
        }
    SER delay(500); // Задержка чтобы монитор порта не перегружать
    }
     
     
    Последнее редактирование: 4 июн 2017