| Ваш IP: 3.219.31.204 | Online(33) - гости: 23, боты: 10 | Загрузка сервера: 1.57 ::::::::::::


DAC CS8416 + CS4398 (Arduino)(2)

Ранее в https://rcl-radio.ru/?p=83845 рассматривался вариант создания внешнего ЦАП на основе ресивера CS8416 и ЦАП на CS4398. В этой статье аналогичный проект, главное отличие его от предыдущего проекта это полностью программное управление ресивером и ЦАП. Управление осуществляется при помощи платы Arduino через шину I2C.

Основное преимущество в программном управлении в отличии от аппаратного, это расширение функциональных возможностей. Например при программном управлении кол-во входов ресивера увеличивается до 8-и, появляется возможность менять выходной формат данных (Left-Justified, Right-Justified, I2S).

Основные параметры ресивера CS8416:

  • Напряжение питания:
    • +3.3 V Analog Supply (VA)
    • +3.3 V Digital Supply (VD)
    • +3.3 V or +5.0 V Digital Interface Supply (VL)
  • Входной формат данных: S/PDIF
  • Выходной формат данных: Left-Justified, Right-Justified, I2S
  • Разрядность 24 бит
  • Частота дискредитации 192 кГц
  • Фильтр De-emphasis:
    • No De-emphasis
    • 32 kHz
    • 48 kHz
    • 44.1 kHz
  • Кол-во входов: 8
  • Управление: I2C

Основные характеристики CS4398:

  • отношение сигнал/шум 120 дБ
  • динамический диапазон 120 дБ
  • уровень гармонических искажений -107 дБ
  • взаимное проникновение каналов 120 дБ
  • входной формат: Left-Justified, Right-Justified, I2S
  • разрядность 24 бит
  • частота дискретизации 192 кГц

С выхода ЦАП звуковой сигнал поступает на фильтр-сумматор собранный на ОУ NE5532:

В состав внешнего ЦАП под управлением Arduino входит:

  • Ресивер CS8416
  • ЦАП CS4398
  • Плата Arduino Nano
  • LCD1602 с модулем I2C
  • Энкодер KY-040

Для питания внешнего ЦАПа рекомендуется использовать три независимых источника питания, который состоит из одного трансформатора с тремя независимыми вторичными обмотками,  одна из которых имеет отвод от середины для двух полярного источника питания. Каждый источник питания имеет свой диодный мост. При этом аналоговая и цифровая земля объединяются через дроссель. Дополнительно как можно ближе к микросхемам по цепи питания устанавливаются фильтрующие конденсаторы 0,1 и 22 мкФ. Подключение к плате Arduino осуществляется тремя проводами (I2C) SDA SCL и GND к DGND цепи питания ЦАП и ресивера.

Управление внешним ЦАП разделено на несколько меню, навигация по меню осуществляется при помощи кнопки энкодера, поворот ручки энкодера меняет выбранный параметр, дополнительно используется одна кнопка для функции MUTE.

  • Меню громкости (99 шагов), индикация выбранного входа, индикатор MUTE и ERROR
  • Меню выбора входа

  • Меню фильтра De-emphasis
  • Меню выбора выходного формата

 

#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(9, 8);//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};
      int a[3],vol,vol_d,menu,in,dem,form;
      byte i,d1,d2,d3,d4,d5,d6,e1,e2,e3;
      unsigned long times,times1,oldPosition  = -999,newPosition;
      bool w,w1,www=1,mute;
      byte dem_dac,dem_res,for_dac,for_res,err,err_old;
 
void setup(){
   Wire.begin();
   delay(100);
   //Serial.begin(9600);
   MsTimer2::set(3, to_Timer);MsTimer2::start();
   lcd.init();lcd.backlight();
   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);
   lcd.setCursor(0,0);lcd.print("CS8416  00");lcd.print(wireRead(0x10,0x7F),BIN);
   lcd.setCursor(0,1);lcd.print("CS4398  0");lcd.print(wireRead(0x4C,0x01),BIN);
   delay(2000);
   pinMode(10,INPUT);// SW 
   pinMode(11,INPUT_PULLUP); // кнопка MUTE
  if(EEPROM.read(100)!=0){for(int i=0;i<101;i++){EEPROM.update(i,0);}}// очистка памяти при первом включении 
  vol = EEPROM.read(0);in = EEPROM.read(1);dem_dac = EEPROM.read(2);dem_res = EEPROM.read(3);for_dac = EEPROM.read(4);for_res = EEPROM.read(5);
// Write 8416
  Wire.beginTransmission(0x10);
  Wire.write (0x00);
//-------------------//
  Wire.write (0b00000000);
  Wire.write (0b10000010);// 128Fs
  Wire.write (0b00000000 + (dem_res << 4));
  Wire.write (0b00000000);
  Wire.write (0b10000000 + (in << 3));
  Wire.write (0b10000000 + (for_res));
  Wire.write (0xFF);
  Wire.write (0x00);
  Wire.write (0x00);
  Wire.write (0x00);
  Wire.endTransmission();
// End Write ////////////////////////////////////
delay(10);
// Write 4398 
  wireWrite(0x4C, 0x02, 0b00000010 + (dem_dac << 2) + (for_dac << 4));
  wireWrite(0x4C, 0x03, 0b00001001);// default
  wireWrite(0x4C, 0x04, 0b11000000);// default
  wireWrite(0x4C, 0x05, vol);
  wireWrite(0x4C, 0x06, vol);
  wireWrite(0x4C, 0x07, 0b10110000);// default
  wireWrite(0x4C, 0x08, 0b01000000);// default
  wireWrite(0x4C, 0x09, 0b00001000);// default
// End Write ////////////////////////////////////
  lcd.clear();
  }
 
void loop(){ 
  /// MENU //////////////////////////////
  if(digitalRead(10)==LOW){menu++;if(menu>3){menu=0;};delay(200);lcd.clear();www=1;}
 
 /// MUTE /////////////////////////////
 if(digitalRead(11)==LOW && mute==0){mute=1;wireWrite(0x4C, 0x04, 0b11011000);delay(300);www=1;} 
 if(digitalRead(11)==LOW && mute==1){mute=0;wireWrite(0x4C, 0x04, 0b11000000);delay(300);www=1;}
 
 /// VOLUME ////////////////////////////
  if(menu==0){
  if (newPosition != oldPosition){oldPosition = newPosition;www=0;
     vol=vol+newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;
      if(vol<0){vol=0;}if(vol>99){vol=99;}
      wireWrite(0x4C, 0x05, vol);
      wireWrite(0x4C, 0x06, vol);
  }
  if(www==1||w==1){www=0;w=0;
      if(mute==1){        lcd.setCursor(0,0);lcd.print("MUTE   ");}
      if(err==0&&mute==0){lcd.setCursor(0,0);lcd.print("VOLUME ");}
      if(err>0&&mute==0){ lcd.setCursor(0,0);lcd.print("ERROR  ");}
 
      lcd.setCursor(0,1);lcd.print("COAX ");lcd.print(in);
     vol_d=99-vol;a[0]=vol_d/10;a[1]=vol_d%10;
      for(i=0;i<2;i++){
      switch(i){
        case 0: e1=9,e2=10,e3=11;break;
        case 1: e1=12,e2=13,e3=14;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>7){in=7;}
  Wire.beginTransmission(0x10);
  Wire.write (0x00);
  Wire.write (0b00000000);
  Wire.write (0b10000010);
  Wire.write (0b00000000 + (dem_res << 4));
  Wire.write (0b00000000);
  Wire.write (0b10000000 + (in << 3));
  Wire.write (0b10000000 + (for_res));
  Wire.write (0xFF);
  Wire.write (0x00);
  Wire.write (0x00);
  Wire.write (0x00);
  Wire.endTransmission();}
  delay(10);
  if(www==1||w==1){www=0;w=0;
  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;times=millis();w=1;w1=1;
      if(dem<0){dem=0;}if(dem>3){dem=3;}
 
  Wire.beginTransmission(0x10);
  Wire.write (0x00);
  Wire.write (0b00000000);
  Wire.write (0b10000010);
  Wire.write (0b00000000 + (dem_res << 4));
  Wire.write (0b00000000);
  Wire.write (0b10000000 + (in << 3));
  Wire.write (0b10000000 + (for_res));
  Wire.write (0xFF);
  Wire.write (0x00);
  Wire.write (0x00);
  Wire.write (0x00);
  Wire.endTransmission();
  delay(10);
  wireWrite(0x4C, 0x02, 0b00000010 + (dem_dac << 2) + (for_dac << 4));
  delay(10);
  }
  if(www==1||w==1){www=0;w=0;
  lcd.setCursor(0,0);lcd.print("DE-EMPHASIS SEL");  
  lcd.setCursor(0,1);
  switch(dem){
  case 0: lcd.print("No De-emphasis");dem_dac=0;dem_res=0;break;
  case 1: lcd.print("44.1 kHz      ");dem_dac=1;dem_res=2;break;
  case 2: lcd.print("48.0 kHz      ");dem_dac=2;dem_res=3;break;
  case 3: lcd.print("32.0 kHz      ");dem_dac=3;dem_res=1;break;
  }
  }
  }
 
  /// Serial Format Select //////////////////////////////////
  if(menu==3){
    if (newPosition != oldPosition){oldPosition = newPosition;
     form=form-newPosition;myEnc.write(0);newPosition=0;times=millis();w=1;w1=1;
      if(form<0){form=0;}if(form>2){form=2;}
 
  Wire.beginTransmission(0x10);
  Wire.write (0x00);
  Wire.write (0b00000000);
  Wire.write (0b10000010);
  Wire.write (0b00000000 + (dem_res << 4));
  Wire.write (0b00000000);
  Wire.write (0b10000000 + (in << 3));
  Wire.write (0b10000000 + (for_res));
  Wire.write (0xFF);
  Wire.write (0x00);
  Wire.write (0x00);
  Wire.write (0x00);
  Wire.endTransmission();
  delay(10);
  wireWrite(0x4C, 0x02, 0b00000010 + (dem_dac << 2) + (for_dac << 4));
  delay(10);
  }
  if(www==1||w==1){www=0;w=0;
  lcd.setCursor(0,0);lcd.print("FORMAT SELECT");  
  lcd.setCursor(0,1);
  switch(form){
  case 0: lcd.print("L-Just 24 bit");for_dac=0;for_res=0;break;
  case 1: lcd.print("I2S    24 bit");for_dac=1;for_res=5;break;
  case 2: lcd.print("R-Just 24 bit");for_dac=3;for_res=8;break;
  }
  }
  }
  ////////////////////////////////////////////////////////
 
  delay(100);
 
  if(millis()-times1>1000){times1=millis();err = wireRead(0x10,0x0C);delay(10);}
  if(err!=err_old){err_old = err;www=1;}
 
  if(millis()-times>10000 && w1==1){w1=0;EEPROM.update(0,vol);EEPROM.update(1,in);
  EEPROM.update(2,dem_dac);EEPROM.update(3,dem_res);EEPROM.update(4,for_dac);EEPROM.update(5,for_res);
  menu=0;www=1;lcd.clear();}
 
  }  
 
void wireWrite(byte addr, byte reg, byte data){
  Wire.beginTransmission(addr);
  Wire.write (reg);
  Wire.write (data);
  Wire.endTransmission();
  }
 
byte wireRead(int addr, int reg){
  Wire.beginTransmission(addr);
  Wire.write (reg);
  Wire.endTransmission();
  delay(10);
  Wire.requestFrom(addr,1);
  while(Wire.available()<1);
  byte value = Wire.read();
  return value;
  }  
 
void to_Timer(){newPosition = myEnc.read()/4;}

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

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

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

  • Коммутатор для водяного насоса и клапана

    В домашнем хозяйстве частного сектора, а также в теплицах для подачи воды, отопления и полива зачастую используют водяной насос совместно с водяным клапаном, управляемым напряжением. При включении и выключении насоса и клапана необходимо строго соблюдать соответствующий порядок включения, чтобы предотвратить гидроудар, возникающий при резком срабатывании клапана и вращающемся двигателе насоса. …Подробнее...
  • MP3302 — мощный светодиодный драйвер

    MP3302 — мощный светодиодный драйвер

    MP3302 — мощный светодиодный драйвер, микросхема представляет собой повышающий преобразователь способный управлять 27 светодиодами (9 строк по 3 светодиода). КПД преобразователя 88%, частота преобразования 1,3 МГц, максимальный ток 1,33 А. Управление преобразователем происходит при помощи входа EN микросхемы MP3302. При напряжении меньше 0,4В преобразователь выключится, при напряжении 0,7 включится. Для плавной …Подробнее...
  • Кроссовер для трехканальной стерео системы

    Кроссовер для трехканальной стерео системы

    Назначение: формирование из обычного двух канального стерео-сигнала ЗЧ, сигнала для работы с трех канальным усилителем стереоситемы, то есть два канала средне-высокочастотные и один канал НЧ. Кроссовер имеет набор регуляторов: регулятор частоты среза ФВЧ НЧ канала с установкой нижней границы НЧ канала в пределах 10-130Гц, регулятор ФНЧ НЧ канала с регулировкой …Подробнее...
  • УМЗЧ 20Вт на TDA2052

    УМЗЧ 20Вт на TDA2052

    УМЗЧ на TDA2052 предназначен для использования в бытовой аудио аппаратуре HI-FI класса, усилитель относится к классу АВ, микросхема имеет тепловую защиту и защиту от КЗ выхода на корпус и шину питания. В микросхеме TDA2052 имеется система MUTE и STAD-BY  которая позволяет избежать шумов при включении и выключении питающего напряжения. Усилитель …Подробнее...
  • Отпугиватель мышей и насекомых на NE556

    Отпугиватель мышей и насекомых на NE556

    На рисунке показана схема простого отпугивателя мышей и насекомых. Уст-во представляет собой генератор изменяющейся частоты в диапазоне от 22 кГц до 56 кГц. Высокочастотные звуки в пределах 30 кГц до 70 кГц человеческое ухо не воспринимает, а многие виды мышей и крыс, тараканы и прочие вредители начинают ощущать дискомфорт. Звуковой …Подробнее...