====== 簡易電子ボリューム(LM1972) ====== ===== 概要 ===== 安価で高性能な電子ボリューム用のIC(LM1972)が手に入りましたので、早速、簡易な電子ボリュームを製作してみました。 <簡易電子ボリュームの仕様> * チャネルは、RとLの2チャネルとします。 * RとLを、単独にボリュームのアップおよびダウンを可能とします。 * 表示は、dB表示とバー表示を切り替え可能とします。 * ミュート(104dB)機能を搭載します。 * RとLの、ボリューム値はEEPROMに保存し、起動時には保存されたボリューム値を設定します。 * 全高調波歪み+ノイズ0.003%(最大) * 周波数特性100kHz(- 3dB)(最小) * 減衰範囲(ミュートを除く) 78dB(代表値) * 減衰誤差± 0.25dB(最大) * SN 比(4Vrms を基準) 110dB(最小) * チャネル・セパレーション100dB(最小) * 3 線シリアル・インタフェース * デイジーチェーン接続が可能 * 減衰量104dB のミュート機能 * 減衰量変更によるポップ/ クリック音を生じない。 {{:imgpaste:202004:htmikan-20200430-153423.png}} {{:imgpaste:202004:htmikan-20200430-153428.png}} ===== 動作原理 ===== PICで電子ボリューム(LM1972)を制御し、その時の制御値をLCDに表示します。 ===== 動作原理(ハードウェア) ===== ◎電子ボリューム * LM1972を、3線シリアル・インタフェースで制御します。(ソフト制御) * 出力側は、単なるコンデンサ出力としましたが、オペアンプのボルテージフォロアでの出力を推奨します。 ◎dB表示&バー表示 * dB表示(減衰量を数値dBで表示します) * バー表示(減衰量をLCDのバー(70点)で表示します。) ◎ボリューム値の設定 * Rチャネルのボリューム値のアップ&ダウンは、スイッチ(SW_R_UP、SW_R_DOWN)を使用します。 * Lチャネルのボリューム値のアップ&ダウンは、スイッチ(SW_L_UP、SW_L_DOWN)を使用します。 * ミュートは、スイッチ(SW_MUTE)を使用します。 ===== 動作原理(ソフトウェア) ===== ◎LM1972の制御(初期化) * ポートの向き(I/O)を設定します。 * LOAD信号を、high(1)に設定します。 * CLOCK信号を、low(0)に設定します。 ◎LM1972の制御(ボリューム設定) * LOAD信号を、low(0)に設定します。 * チャネル番号(8ビット)のMSB(Most Significant Bit)から、順次クロックと同期させながら8ビット分出力します。 * ボリューム値(8ビット)のMSB(Most Significant Bit)から、順次クロックと同期させながら8ビット分出力します。 * LOAD信号を、high(1)に設定します。 ◎ボリューム値→dB変換 * ボリューム値が、127以上であれば、-100dBとします。 * ボリューム値が、0~96であれば、-(ボリューム値×0.5dB)とします。 * ボリューム値が、97~126であれば、-((ボリューム値-97)+49dB)とします。 ◎表示モード切替 * スイッチ(SW_MODE)が、high(1)であれば、dB表示します。 * スイッチ(SW_MODE)が、low(0)であれば、バー表示します。 ◎ミュート動作 * スイッチ(SW_MUTE)が、押下されると、ミュート(127)に設定します。 * スイッチ(SW_MUTE)が、再度押下されると、ミュートを解除します。 ◎ボリューム値のアップ&ダウン * スイッチ(SW_R_UP、SW_R_DOWN)の操作で、Rチャネルのボリューム値をアップ&ダウンさせます。 * スイッチ(SW_L_UP、SW_L_DOWN)の操作で、LRチャネルのボリューム値をアップ&ダウンさせます。 ◎ボリューム値の書き込みと読み出し * ボリューム値が、変更されるとその時の内容をEEPROMに書き込みます。 * 起動時に、EEPROMからボリューム値を読み出し、ボリューム値を設定します。 {{:imgpaste:202004:htmikan-20200430-153536.png?500}} {{:imgpaste:202004:htmikan-20200430-153544.png?500}} {{:imgpaste:202004:htmikan-20200430-153552.png}} ===== 回路図 ===== {{:imgpaste:202004:htmikan-20200430-153604.png}} ===== ソースコード ===== //********************************************************************** /*   <電子ボリュームV2> */ //********************************************************************** #define BYTE unsigned short #define WORD unsigned int #define DWORD unsigned long // #define SW_R_UP PORTA.B0 #define SW_R_DOWN PORTA.B1 #define SW_L_UP PORTA.B2 #define SW_L_DOWN PORTA.B3 #define SW_MUTE PORTA.B4 #define SW_MODE PORTA.B5 // #define CH_R 0 #define CH_L 1 //********************************************************************** const char character0[] = { 0, 0, 0, 0, 0, 0, 0, 0}; const char character1[] = { 0,16,16,16,16,16, 0, 0}; const char character2[] = { 0,24,24,24,24,24, 0, 0}; const char character3[] = { 0,28,28,28,28,28, 0, 0}; const char character4[] = { 0,30,30,30,30,30, 0, 0}; const char character5[] = { 0,31,31,31,31,31, 0, 0}; // void RegistCustomChar() { char i; // LCD_Cmd(64); for (i = 0; i<=7; i++) { LCD_Chr_Cp(character0[i]); } for (i = 0; i<=7; i++) { LCD_Chr_Cp(character1[i]); } for (i = 0; i<=7; i++) { LCD_Chr_Cp(character2[i]); } for (i = 0; i<=7; i++) { LCD_Chr_Cp(character3[i]); } for (i = 0; i<=7; i++) { LCD_Chr_Cp(character4[i]); } for (i = 0; i<=7; i++) { LCD_Chr_Cp(character5[i]); } LCD_Cmd(_LCD_RETURN_HOME); } //********************************************************************** void BarDisp(char row, char column, short mode, unsigned int dat) { short i, j, k, cnt; // if (mode == 0) { i = dat / 1.79; } else { i = dat; } j = i / 5; k = i - (j * 5); // if (row == 1) Lcd_Cmd(_LCD_FIRST_ROW); else Lcd_Cmd(_LCD_SECOND_ROW); // for (cnt = 1; cnt < column; cnt++) { Lcd_Cmd(_LCD_MOVE_CURSOR_RIGHT); } // for (cnt = 0; cnt < j; cnt++) { Lcd_Chr_Cp(5); } Lcd_Chr_Cp(k); for (cnt++; cnt < 10; cnt++) { Lcd_Chr_Cp(' '); } } //********************************************************************** sbit LCD_RS at RA6_bit; sbit LCD_EN at RA7_bit; sbit LCD_D7 at RB7_bit; sbit LCD_D6 at RB6_bit; sbit LCD_D5 at RB5_bit; sbit LCD_D4 at RB4_bit; sbit LCD_RS_Direction at TRISA6_bit; sbit LCD_EN_Direction at TRISA7_bit; sbit LCD_D7_Direction at TRISB7_bit; sbit LCD_D6_Direction at TRISB6_bit; sbit LCD_D5_Direction at TRISB5_bit; sbit LCD_D4_Direction at TRISB4_bit; // void init_lcd() { short cnt; // Lcd_Init(); RegistCustomChar(); Lcd_Cmd(_LCD_CURSOR_OFF); Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1, 1, "e-volume V2.0"); for (cnt = 0; cnt <= 80; cnt++) { BarDisp(2, 1, 1, cnt); Delay_ms(10); } Lcd_Cmd(_LCD_CLEAR); } //********************************************************************** sbit LM1972_CLOCK at RB1_bit; sbit LM1972_LOAD at RB2_bit; sbit LM1972_DATA at RB3_bit; sbit LM1972_CLOCK_Direction at TRISB1_bit; sbit LM1972_LOAD_Direction at TRISB2_bit; sbit LM1972_DATA_Direction at TRISB3_bit; // void init_volume() { LM1972_CLOCK_Direction = 0; LM1972_LOAD_Direction = 0; LM1972_DATA_Direction = 0; // LM1972_LOAD = 1; LM1972_CLOCK = 0; } //********************************************************************** void set_volume(BYTE channel, BYTE attenuation) { short cnt; // LM1972_LOAD = 0; for (cnt = 0; cnt < 8; cnt++) { LM1972_DATA = (channel & 0x80) != 0 ? 1 : 0; LM1972_CLOCK = 1; LM1972_CLOCK = 0; channel <<= 1; } for (cnt = 0; cnt < 8; cnt++) { LM1972_DATA = (attenuation & 0x80) != 0 ? 1 : 0; LM1972_CLOCK = 1; LM1972_CLOCK = 0; attenuation <<= 1; } LM1972_LOAD = 1; } //********************************************************************** void db_cnv(BYTE dt, char* result) { int tmp; // tmp = dt; if (tmp >= 127) { IntToStr(-1000, result); result[9] = 0x00; result[8] = 'B'; result[7] = 'd'; result[6] = result[5]; result[5] = '.'; return; } if (tmp <= 96) { tmp *= 5; IntToStr(tmp * -1, result); result[9] = 0x00; result[8] = 'B'; result[7] = 'd'; result[6] = result[5]; result[5] = '.'; return; } tmp = 490 + ((tmp - 97) * 10); IntToStr(tmp * -1, result); result[9] = 0x00; result[8] = 'B'; result[7] = 'd'; result[6] = result[5]; result[5] = '.'; } //********************************************************************** void main() { BYTE R_data, L_data; char buf[16]; short mute_flg = 0; // OSCCON = 0b01110000; CMCON = 0b00000111; ANSEL = 0b00000000; TRISA = 0b11111111; // init_lcd(); Lcd_Out(1, 1, "R:"); Lcd_Out(2, 1, "L:"); // init_volume(); // R_data = EEPROM_Read(0); R_data = R_data > 127 ? 127 : R_data; L_data = EEPROM_Read(1); L_data = L_data > 127 ? 127 : L_data; set_volume(CH_R, R_data); set_volume(CH_L, L_data); db_cnv(R_data, buf); Lcd_Out(1, 3, &buf[1]); db_cnv(L_data, buf); Lcd_Out(2, 3, &buf[1]); // while (1) { //(R)ボリュームUP! if (SW_R_UP == 0) { Delay_ms(100); if (R_data > 0) { R_data--; EEPROM_Write(0, R_data); } set_volume(CH_R, R_data); } //(R)ボリュームDOWN! if (SW_R_DOWN == 0) { Delay_ms(100); if (R_data < 127) { R_data++; EEPROM_Write(0, R_data); } set_volume(CH_R, R_data); } //(L)ボリュームUP! if (SW_L_UP == 0) { Delay_ms(100); if (L_data > 0) { L_data--; EEPROM_Write(1, L_data); } set_volume(CH_L, L_data); } //(L)ボリュームDOWN! if (SW_L_DOWN == 0) { Delay_ms(100); if (L_data < 127) { L_data++; EEPROM_Write(1, L_data); } set_volume(CH_L, L_data); } //表示モード切替(dB表示、バー表示) if (SW_MODE == 1) { db_cnv(R_data, buf); Lcd_Out(1, 3, &buf[1]); Lcd_Out(1, 11, " "); db_cnv(L_data, buf); Lcd_Out(2, 3, &buf[1]); Lcd_Out(2, 11, " "); } else { BarDisp(1, 3, 0, 127 - R_data); BarDisp(2, 3, 0, 127 - L_data); } //ミュート動作 if (SW_MUTE == 0) { Delay_ms(100); if (mute_flg == 0) { mute_flg = 1; Lcd_Chr(1, 2, '_'); Lcd_Chr(2, 2, '_'); set_volume(CH_R, 127); set_volume(CH_L, 127); } else { mute_flg = 0; Lcd_Chr(1, 2, ':'); Lcd_Chr(2, 2, ':'); set_volume(CH_R, R_data); set_volume(CH_L, L_data); } } } } //********************************************************************** ===== 動作確認 ===== {{:imgpaste:202004:htmikan-20200430-153704.png}}{{:imgpaste:202004:htmikan-20200430-153707.png}} 左側:dB表示、右側:バー表示 {{:imgpaste:202004:htmikan-20200430-153853.png}}{{:imgpaste:202004:htmikan-20200430-153719.png}} (編者注:破損した画像しかありませんでした) 左側から、ミュート、10Hz正弦波、100Hz正弦波 {{:imgpaste:202004:htmikan-20200430-153725.png}}{{:imgpaste:202004:htmikan-20200430-153729.png}}{{:imgpaste:202004:htmikan-20200430-153734.png}} 左側から、1KHz正弦波、10kHz、100KHz正弦波 {{:imgpaste:202004:htmikan-20200430-153740.png}}{{:imgpaste:202004:htmikan-20200430-153743.png}}{{:imgpaste:202004:htmikan-20200430-153747.png}} このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。[[elechobby:picdic:picdic|詳細]] This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.[[elechobby:picdic:picdic|Details]]