| Ваш IP: 44.192.70.216 | Online(38) - гости: 12, боты: 26 | Загрузка сервера: 0.44 ::::::::::::

Внешний ЦАП WM8805 + PCM1753 (Arduino)

ЦАП — цифро-аналоговый преобразователь — это устройство, которое преобразует информацию из цифрового вида  в аналоговые сигналы, при этом максимально точно и без искажений.

Собрать внешний ЦАП на компонентах предложных в статье не сложно, он содержит несколько недорогих компонентов и в настройке практически не нуждается.

Входной цифровой сигнал имеет формат S/PDIF (цифровой аудио интерфейс разработанный фирмами SONY/PHILIPS, предназначен для передачи цифрового сигнала между аудио устройствами), ЦАП PCM1753 не поддерживает такой формат, для преобразования S/PDIF необходим ресивер на WM8805 который преобразует S/PDIF в цифровой сигнал в формат I2S. С выхода ЦАП звуковой сигнал поступает на фильтр-сумматор собранный на ОУ NE5532, а с выхода фильтра звуковой сигнал можно подавать на наушники с минимальным сопротивлением 32 Ом .

Внешний звуковой ЦАП содержит несколько основных компонента:

  • Плата Arduino Nano
  • Ресивер на WM8805 (24 бит 196 кГц)
  • ЦАП на PCM (24 бит 196 кГц)
  • Фильтр-сумматор на NE5532
  • LCD1602
  • Энкодер KY-040

Характеристики основных компонентов внешнего ЦАПа:

  • WM8805
    • Входной формат — S/PDIF
    • Кол-во входов … 8 (программно ограничено до 4-х)
    • Выходной формат:
      • 16-bit, MSB-first, right-justified
      • 24-bit, MSB-first, right-justified
      • 24-bit, MSB-first, left-justified
      • 24-bit, MSB-first, I2S
    • Напряжение питания
      • Digital power supply … 3,3 В
      • Digital power supply … 3,3 В
    • Диапазон частот дискретизации входного сигнала 32 — 196 кГц

Управление ресивером WM8805 программное, ресивер настроен на выходной сигнал формата 24 bit / I2S / 196 kHz.

  • PCM1753
    • Входные форматы:
      • I2S, left-justified / 16-, 18-, 20-, 24-bit
    • De-emphasis filter
      • 38 кГц
      • 44,1 кГц
      • 48 кГц
    • Digital Filter Rolloff
      • Sharp rolloff
      • Slow rolloff
    • Напряжение питания … 5 В
    • Коэффициент гармоник от 0.002% до 0,004% на уровне 0 дБ
    • Динамический диапазон 102 …106 дБ (192 … 44,1 кГц)
    • Отношение сигнал/шум  102 …106 дБ (192 … 44,1 кГц)
    • Частота дискретизации до 192 кГц
    • Работает совместно с фильтром-сумматоров на NE5532

Управление ЦАП PCM1753 программное, настроен на входной сигнал формата 24 bit / I2S / 196 kHz.

Схема стабилизаторов питания

Рекомендуется как можно ближе к микросхемам по цепи питания устанавливаются фильтрующие конденсаторы 0,1 и 22 мкФ.

Подключение к плате Arduino

Во внешнем ЦАПе использован энкодер KY-040 для управления громкостью, коммутатором входов, фильтрами De-emphasis и Digital Filter Rolloff, дополнительно используется кнопка для активации режима MUTE. Информация о режимах работы внешнего ЦАП выводится на LCD дисплея LCD1602 на базе контроллера HD44780 совместно с модулем I2C. I2C модуль на базе микросхемы PCF8574 позволяют подключить символьный дисплей 1602 к плате Arduino всего по двум проводам SDA и SCL (А4 и А5), что дает возможность не использовать цифровые выходы Arduino при подключении дисплея.

Меню внешнего ЦАПа состоит из 4-х пунктов:

  • Регулятор громкости от -78 до 0 дБ

  • Коммутатор входов SPDIF

  • De-emphasis filter — 38 кГц | 44,1 кГц | 48 кГц

  • Digital Filter Rolloff Control

На главное меню помимо громкости выводится выводится дополнительная информация:

  1. Номер входа SPDIF
  2. De-emphasis filter — 38 кГц | 44,1 кГц | 48 кГц | 192 кГц (фильтр отключен)
  3. Digital Filter Rolloff Control, режимы Sharp rolloff и Slow rolloff
  4. Уровень громкости от 0 до 99 значений (шаг 0,5 дБ)
  5. Индикатор отображает режимы VOLUME, MUTE, NO SOUND — если на входе SPDIF нет сигнала или кабель не подключен
#define ML 2
#define MC 3
#define MD 4
 
#define CLK    A0 // CLK ENCODER
#define DT     A1 // DT  ENCODER
#define SW     A2 // SW  ENCODER
 
#define CSB   11 // CSB   WM8805
#define SCLK  8  // SCLK  WM8805
#define SDIN  9  // SDIN  WM8805
#define SDOUT 10 // SDOUT WM8805
 
#define MUTE 5
 
// LCD1602 I2C A4 = SDA, A5 = SCL
 
#include <Wire.h> 
#include <EEPROM.h>
#include <Encoder.h>  // https://rcl-radio.ru/wp-content/uploads/2019/05/Encoder.zip
#include <MsTimer2.h> // https://rcl-radio.ru/wp-content/uploads/2018/11/MsTimer2.zip
#include <LiquidCrystal_I2C.h> //Библиотека -  http://forum.rcl-radio.ru/misc.php?action=pan_download&item=45&download=1
  LiquidCrystal_I2C lcd(0x27,16,2);  // Устанавливаем дисплей 
  Encoder myEnc(CLK, DT);
 
    byte v1[8] = {0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07};
    byte v2[8] = {0x07,0x07,0x00,0x00,0x00,0x00,0x00,0x00};      
    byte v3[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x1F};
    byte v4[8] = {0x1F,0x1F,0x00,0x00,0x00,0x00,0x1F,0x1F};
    byte v5[8] = {0x1C,0x1C,0x00,0x00,0x00,0x00,0x1C,0x1C};
    byte v6[8] = {0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C,0x1C};
    byte v7[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x07};
    byte v8[8] = {0x1F,0x1F,0x00,0x00,0x00,0x00,0x00,0x00}; 
  unsigned long times,oldPosition  = -999,newPosition,times1;
  byte i,d1,d2,d3,d4,d5,d6,e1,e2,e3;
  int vol,w,w1,w2=1,menu,mute,dem,a[3],dem_on,roll,in,err;
 
 
void setup(){
  pinMode(ML,OUTPUT);
  pinMode(MC,OUTPUT);
  pinMode(MD,OUTPUT);
  pinMode(SW,INPUT);
  pinMode(MUTE,INPUT_PULLUP);
  pinMode(CSB,OUTPUT);  // CSB   WM8805
  pinMode(SCLK,OUTPUT); // SCLK  WM8805
  pinMode(SDIN,OUTPUT); // SDIN  WM8805
  pinMode(SDOUT,INPUT); // SDOUT WM8805
  Wire.begin();Serial.begin(9600);
  lcd.init();lcd.backlight();
  MsTimer2::set(1, to_Timer);MsTimer2::start();
  lcd.createChar(1, v1);lcd.createChar(2, v2);lcd.createChar(3, v3);lcd.createChar(4, v4);lcd.createChar(5, v5);lcd.createChar(6, v6);lcd.createChar(7, v7);lcd.createChar(8, v8);
  delay(100);
  if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}// очистка памяти при первом включении 
  vol = EEPROM.read(0);dem = EEPROM.read(1);roll = EEPROM.read(2);in = EEPROM.read(3);
  if(dem<3){dem_on=1;}else{dem_on=0;}
  // Write WM8805 SPI
  WM8805Write(0x00, 0x01); // RESET
  WM8805Write(0x03, 0xBA); // PPL_K 0xBA
  WM8805Write(0x04, 0x49); // PPL_K 0x49
  WM8805Write(0x05, 0x0C); // PPL_K 0x0C
  WM8805Write(0x06, 0x08); // PLL_N 0x08
  WM8805Write(0x07, 0b00101000);// 00 CLKOUTDIV[1:0] MCLKDIV FRACEN>!!! FREQMODE[1:0]
  WM8805Write(0x08, 0b01110000 + in);// MCLKSRC ALWAYSVALID FILLMODE CLKOUTDIS CLKOUTSRC RXINSEL[2:0]>000:PX0
  WM8805Write(0x09, 0b11111111);// SPDIFINMODE[7:0]>gain
  WM8805Write(0x0A, 0b00000000);// MASK[7:0]
  WM8805Write(0x12, 0b00000000);// CHSTMODE[1:0] DEEMPH[2:0] CPY_N AUDIO_N CON/PRO
  WM8805Write(0x13, 0b00000000);// CATCODE[7:0]
  WM8805Write(0x14, 0b00000000);// CHNUM2[1:0] CHNUM1[1:0] SRCNUM[3:0]
  WM8805Write(0x15, 0b01110001);// TXSTATSRC TXSRC CLKACU[1:0] FREQ[3:0] // default
  WM8805Write(0x16, 0b00001011);// ORGSAMP[3:0] TXWL[2:0]>101:24bit MAXWL>1:24bit_max
  WM8805Write(0x1B, 0b00001010);// 00 AIFTX_LRP AIFTX_BCP AIFTX_WL[1:0] AIFTX_FMT[1:0]
  WM8805Write(0x1C, 0b01001010);// SYNC_OFF>0:no_sound AIF_MS>1:master AIFRX_LRP AIFRX_BCP AIFRX_WL[1:0]>11:24bit AIFRX_FMT[1:0]>10:I2S
  WM8805Write(0x1D, 0b11000000);// SPD_192K_EN WL_MASK SPDGPO WITHFLAG CONT READMUX[2:0]
  WM8805Write(0x1E, 0b00000100);// 00 TRIOP AIFPD OSCPD SPDIFTXPD SPDIFRXPD PLLPD
  delay(1000);
  audio();  
  }
 
void loop(){
  /// MENU //////////////////////////////
  if(digitalRead(SW)==LOW){menu++;if(menu>3){menu=0;};delay(200);lcd.clear();w=1;times=millis();w2=1;}
   /// MUTE ///////////////////
 if(digitalRead(MUTE)==LOW&&mute==0){mute=1;audio();delay(200);}
 if(digitalRead(MUTE)==LOW&&mute==1){mute=0;audio();delay(200);}  
  /// VOLUME ///////////////////////////////////////////////////
 if(menu==0){
   if (newPosition != oldPosition){oldPosition = newPosition;
     vol=vol+newPosition;myEnc.write(0);newPosition=0;w=1;times=millis();w2=1;vol_func();
     Serial.println(vol);
     audio();}
      lcd.setCursor(0,0);
      if(mute==1){lcd.print("MUTE     ");}
      if(err==0&&mute==0){lcd.print("VOLUME ");lcd.print("C");lcd.print(in);}
      if(err>0&& mute==0){lcd.print("NO SOUND ");} 
      lcd.setCursor(0,1);
      switch(dem){
        case 0: lcd.print("44.1k");break;
        case 1: lcd.print("48.0k");break;
        case 2: lcd.print("32.0k");break;
        case 3: lcd.print("192 k");break;
  }
        switch(roll){
        case 0: lcd.print("  SH ");break;
        case 1: lcd.print("  SL ");break;
  }
 
if(w2==1){w2=0;
     a[0]=(vol-156)/10;a[1]=(vol-156)%10;
      for(i=0;i<2;i++){
      switch(i){
        case 0: e1=10,e2=11,e3=12;break;
        case 1: e1=13,e2=14,e3=15;break;
        }
      switch(a[i]){
        case 0: d1=1,d2=8,d3=6,d4=1,d5=3,d6=6;break;
        case 1: d1=32,d2=2,d3=6,d4=32,d5=32,d6=6;break;
        case 2: d1=2,d2=8,d3=6,d4=1,d5=4,d6=5;break;
        case 3: d1=2,d2=4,d3=6,d4=7,d5=3,d6=6;break;
        case 4: d1=1,d2=3,d3=6,d4=32,d5=32,d6=6;break;
        case 5: d1=1,d2=4,d3=5,d4=7,d5=3,d6=6;break;
        case 6: d1=1,d2=4,d3=5,d4=1,d5=3,d6=6;break;
        case 7: d1=1,d2=8,d3=6,d4=32,d5=32,d6=6;break;
        case 8: d1=1,d2=4,d3=6,d4=1,d5=3,d6=6;break;
        case 9: d1=1,d2=4,d3=6,d4=7,d5=3,d6=6;break;
    }
      lcd.setCursor(e1,0);lcd.write((uint8_t)d1);lcd.setCursor(e2,0);lcd.write((uint8_t)d2);lcd.setCursor(e3,0);lcd.write((uint8_t)d3);
      lcd.setCursor(e1,1);lcd.write((uint8_t)d4);lcd.setCursor(e2,1);lcd.write((uint8_t)d5);lcd.setCursor(e3,1);lcd.write((uint8_t)d6);
 }} 
 }
 
//////// INPUT ////////////////////////////////////  
  if(menu==1){
    if (newPosition != oldPosition){oldPosition = newPosition;
     in=in+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;
      if(in<0){in=0;}if(in>3){in=3;}
      WM8805Write(0x08, 0b01110000 + in);}
 
  lcd.setCursor(0,0);lcd.print("INPUT SELECTOR");  
  lcd.setCursor(0,1);lcd.print("COAXIAL "); lcd.print(in);lcd.print(" ");
  }
 
 /// DE-EMPHASIS //////////////////////////////////
  if(menu==2){
     if (newPosition != oldPosition){oldPosition = newPosition;
     dem=dem+newPosition;myEnc.write(0);newPosition=0;w=1;times=millis();w2=1;
      if(dem<0){dem=3;}if(dem>3){dem=0;}
      if(dem<3){dem_on=1;}else{dem_on=0;}
      audio();}
 
  if(w2==1){w2=0;
  lcd.setCursor(0,0);lcd.print("DE-EMPHASIS FILT");  
  lcd.setCursor(0,1);
  switch(dem){
    case 0: lcd.print(" 44.1 kHz");break;
    case 1: lcd.print(" 48.0 kHz");break;
    case 2: lcd.print(" 32.0 kHz");break;
    case 3: lcd.print(" 192  kHz");break;
  }}} 
 
   /// Roll-off Filter //////////////////////////////////
  if(menu==3){
     if (newPosition != oldPosition){oldPosition = newPosition;
     roll=roll+newPosition;myEnc.write(0);newPosition=0;w=1;times=millis();w2=1;
     if(roll<0){roll=1;}if(roll>1){roll=0;}
     audio();}
 
  if(w2==1){w2=0;
  lcd.setCursor(0,0);lcd.print("Roll-off Filter");  
  lcd.setCursor(1,1);
  switch(roll){
    case 0: lcd.print("Sharp");break;
    case 1: lcd.print("Slow ");break;
  }}} 
 
  /// NO SOUND /////////////////////
  if(millis()-times1>500){times1=millis();err = WM8805Read(0x0B);}
 
 
  //////// EEPROM //////////////////////////////////////////////////
  if(millis()-times>10000 && w==1 && mute == 0){EEPROM.update(0,vol);EEPROM.update(1,dem);EEPROM.update(2,roll);EEPROM.update(3,in);w=0;w2=1;menu=0;lcd.clear();}
  }// loop
 
 
void WritePCM(byte reg, byte data){  // WRITE_REG SPI
   digitalWrite(MC,HIGH);digitalWrite(ML,LOW);
     for(int i = 7; i >= 0; i--){
        digitalWrite(MC,LOW);
        digitalWrite(MD, (reg >> i) & 0x01);
        digitalWrite(MC,HIGH);
        }
     for(int i = 7; i >= 0; i--){
        digitalWrite(MC,LOW);
        digitalWrite(MD, (data >> i) & 0x01);
        digitalWrite(MC,HIGH);
        }
    digitalWrite(MC,HIGH);digitalWrite(ML,HIGH);delay(1);
  }
 
void WM8805Write(byte reg, byte dout){  // WRITE_REG 
  digitalWrite(SCLK,LOW);digitalWrite(CSB,LOW);
     for(int i = 7; i >= 0; i--){
        digitalWrite(SCLK,LOW);
        digitalWrite(SDIN, (reg >> i) & 0x01);
        digitalWrite(SCLK,HIGH);
        }
     for(int i = 7; i >= 0; i--){
        digitalWrite(SCLK,LOW); 
        digitalWrite(SDIN, (dout >> i) & 0x01);
        digitalWrite(SCLK,HIGH);
        }
        digitalWrite(SCLK,LOW);digitalWrite(CSB,HIGH);  
  }  
 
byte WM8805Read(byte reg){   // READ_REG  
  byte dat[8],data = 0;
  reg = reg + (1 << 7);
   digitalWrite(SCLK,LOW);digitalWrite(CSB,LOW);
     for(int i = 7; i >= 0; i--){
        digitalWrite(SCLK,LOW);
        digitalWrite(SDIN, (reg >> i) & 0x01);
        digitalWrite(SCLK,HIGH);
        }
     for(int i = 7; i >= 0; i--){
        digitalWrite(SCLK,LOW);
        dat[i] = digitalRead(SDOUT);
        data = data + (dat[i] << i);
        digitalWrite(SCLK,HIGH);
        } 
        digitalWrite(SCLK,LOW);digitalWrite(CSB,HIGH);
    return data;
  }      
 
void audio(){  
  WritePCM(0x10, vol);//r16 [7:0]att 0-min 255-max
  WritePCM(0x11, vol);//r17 [7:0]att 0-min 255-max
  WritePCM(0x12, 0b01000000 + (mute << 1) + mute);//r18 [6]x128 [1:0]mute
  WritePCM(0x13, 0b00000000 + (dem_on << 4) + (dem << 5));//r19 [1:0]dac_on [4]De-Emphasis [6:5] De-Emphasis Sample Rate Selection
  WritePCM(0x14, 0b00000100 + (roll << 5));//r20 [2:0]100=I2S_24 [5]Filter Rolloff
  WritePCM(0x16, 0B00000001);//r22
  }  
 
void to_Timer(){newPosition = myEnc.read()/4;}  
void vol_func(){if(vol<156){vol=156;}if(vol>255){vol=255;}}

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

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

Случайные статьи

  • УМЗЧ класса D на TPA3122D2

    УМЗЧ класса D на TPA3122D2

    На ИМС TPA3122D2 можно собрать усилитель звуковой частоты класса D. Выходная мощность усилителя 15В (при напряжении питания 28В и сопротивлении нагрузки 8 Ом) на канал. Из-за высокого КПД микросхеме TPA3122D2 не нужен радиатор охлаждения. Так же микросхему TPA3122D2 можно использовать в мостовом соединении каналов. МикросхемаTPA3122D2 работает в диапазоне напряжений от 10 …Подробнее...
  • LED светильник с регулируемой яркостью (18 светодиодов)

    LED светильник с регулируемой яркостью (18 светодиодов)

    На регуляторе напряжения LM2941C можно сделать простой светодиодный светильник рассчитанный на 18 светодиодов. Яркость свечения светодиодов можно регулировать пока входное напряжение будет выше 10,5В. Источник: http://www.solorb.com/elect/solarcirc/18ledlit/index.html lm2941.pdfПодробнее...
  • Микросхемы-регуляторы громкости

    LA1362 — одно канальный регулятор громкости Ток потребления 40мА Коэффициент регулировки -70…+22дБ Частотный диапазон от 20 до 20000Гц К гармоник не более 0,5% Входное/выходное сопротивление 75/10кОм Напряжение питания 9…18В Uвх/Uвых 1/1,5В Корпус типа SIL9 LA2600 — двух канальный регулятор громкости Ток потребления 40мА Коэффициент регулировки -70…+22дБ Частотный диапазон от 20 …Подробнее...
  • Акустический выключатель для люстры

    Данная схема управляется хлопками в ладоши. Это переключатель для 2-х групп ламп с суммарной мощностью 300Вт. Акустические импульсы воспринимаются электретным микрофоном М1. Питание на него подается через R1, который одновременно служит его нагрузкой. Далее следует усилитель на VT1. Усиленные импульсы поступают на формирователь лог. импульсов, выполненный на интегральном таймере D1. …Подробнее...
  • К1460УД2х — СДВОЕННЫЙ МОЩНЫЙ ОПЕРАЦИОННЫЙ УСИЛИТЕЛЬ

    К1460УД2х — СДВОЕННЫЙ МОЩНЫЙ ОПЕРАЦИОННЫЙ УСИЛИТЕЛЬ

    К1460УД2х – интегральная микросхема представляет собой сдвоенный мощный операционный усилитель, пригодная для использования в качестве мощного ОУ в широком диапазоне областей применения, хорошо подходит для управления индуктивными нагрузками, в частности, для управления электродвигателями постоянного тока. Микросхема К1460УД2Рх является прямым аналогом микросхемы TCA0372 фирмы «MOTOROLA». ОСОБЕННОСТИ • Выходной ток до 1.0 А • Скорость нарастания …Подробнее...