/* ************************************************************************** 説明 : 電子ボリューム コントロール マイコン: PIC16F676 ************************************************************************** PIC12F675 __ __ VDD =|・U |= VSS RA0 電圧検出入力 RA5 =| |= RA0 RA1 ADC入力 VR1入力 / デジタル入力 A相エンコーダー RA4 =| |= RA1 RA2 ADC入力 VR2入力 / デジタル入力 B相エンコーダー割込み RA3 =| |= RA2 GP3 MODE 入力(外部プルアップ) RC5 =| |= RC0 RC0 /CS 出力 RC4 =| |= RC1 RC1 SDI 出力 RC3 =| |= RC2 RC2 SCLK 出力 ~~~~~ RC3〜5 未使用出力 */ #include <16F676.h> #device adc=8 #fuses NOWDT,INTRC_IO, NOPROTECT, BROWNOUT, MCLR, NOCPD, PUT #use delay(clock=4000000) #byte PORTA = 5 #byte PORTC = 7 #byte TRISA = 0x85 #byte TRISC = 0x87 #byte WPUA = 0x95 #byte OPTION_REG = 0x81 #byte ADCON0 = 0x1f #byte ADCON1 = 0x9f #byte ANSEL = 0x91 #byte INTCON = 0x0b #bit T0IE = 0x0b.5 #use fast_io(A) #use fast_io(C) #define MODE PIN_A4 // ボリュームかエンコーダー識別ポート #define CS PIN_C0 #define SCLK PIN_C2 #define SDI PIN_C1 #define P_DOWN PIN_A0 #define ENCO_A PIN_A1 #define MUTE PIN_C3 #define EXT PIN_C4 #define DEBUG1 PIN_C5 #define JP3 PIN_A5 // ***** プロトタイプ ***** void debu(void); void sout(void); void ad_ave8(void); int vol_calc(int data); void init(void); // ***** グローバル変数 ***** int L_AD_OLD; int R_AD_OLD; // ボリューム値 int L_AD_data; int R_AD_data; int L_VOL_data; int R_VOL_data; short AD_NEW; short AD_1st; long ENCO_data; // EEPROMデータ int TMR1_Count; // ******************************************************* // 関数名 #int_RTCC // 概要 タイマー0割り込み // ******************************************************* #int_RTCC RTCC_isr() { AD_NEW = 0; // フラグ・リセット ad_ave8(); // ADC 8回の平均 if(L_AD_data != L_AD_OLD) { L_AD_OLD = L_AD_data; AD_NEW = 1; // AD変化フラグを立てる } if(R_AD_data != R_AD_OLD) { R_AD_OLD = R_AD_data; AD_NEW = 1; // AD変化フラグを立てる } if((AD_NEW)||(AD_1st)) // 初回ADしない可能性があるので { L_VOL_data = vol_calc(L_AD_data); R_VOL_data = vol_calc(R_AD_data); sout(); } AD_1st = 0; } // ******************************************************* // 関数名 #int_EXT // 概要 RA2立下り割込み(ロータリーエンコーダーB相) // ******************************************************* #int_EXT EXT_isr() { short FRUG; FRUG = 0; disable_interrupts(INT_EXT); // 外部割込み禁止 disable_interrupts(INT_TIMER1); // TMR1割込み禁止 TMR1_Count = 0; if(input(ENCO_A) == 1) // ボリュームアップ { if(input(JP3)== 1) // JP3が無ければ { if(ENCO_data < 255) // 255になっていたら加算しない { ENCO_data++; FRUG = 1; // output_low(DEBUG1); } // else // output_high(DEBUG1); }else // JP3があれば { if(ENCO_data < 255) // ステップ×2 { ENCO_data++; ENCO_data++; // output_low(DEBUG1); if(ENCO_data > 255) ENCO_data = 255; FRUG = 1; } // else // output_high(DEBUG1); } } else // ボリュームダウン { if(input(JP3)== 1) // JP3が無ければ { if(ENCO_data > 0) // 0やったら減算せーへん { ENCO_data--; FRUG = 1; // output_low(DEBUG1); } // else // output_high(DEBUG1); }else // JP3があれば { if(ENCO_data > 0) // ステップ×2 { ENCO_data--; ENCO_data--; // output_low(DEBUG1); if(ENCO_data > 255) ENCO_data = 0; FRUG = 1; } // else // output_high(DEBUG1); } } R_VOL_data = vol_calc(ENCO_data); L_VOL_data = R_VOL_data; if(FRUG == 1) sout(); // PGA2311にデーター書込み // set_timer1(0); // TMR1クリア enable_interrupts(INT_EXT); // 外部割込み許可 // enable_interrupts(INT_TIMER1); // TMR1割込み許可 } // ******************************************************* // 関数名 #int_TIMER1 // 概要 タイマー1割り込み // ******************************************************* #int_TIMER1 TIMER1_isr() // 0.5秒タイマー { clear_interrupt(int_timer1); // フラグクリア if(TMR1_Count > 2) // 2秒たったら { disable_interrupts(INT_TIMER1); // TMR1割込み禁止 TMR1_Count = 0; write_eeprom(0,ENCO_data); // EEPROMにボリュームデーター書き込み } else TMR1_Count++; } // ******************************************************* // 関数名 void debu(void) // 概要 デバッグ用 // ******************************************************* void debu(void) { output_high(DEBUG1); // デバッグ delay_ms(1); output_low(DEBUG1); /*if(input_state(DEBUG1)) output_low(DEBUG1); else output_high(DEBUG1); */ } // ******************************************************* // 関数名 void ad_ave8(void) // 概要 ADC 平均 // ******************************************************* void ad_ave8(void) { int ADtemp; int i; long ADsum; ADsum = 0; i = 8; do { set_adc_channel(1); // Lch delay_us(50); ADtemp = read_adc(); ADsum = ADsum + ADtemp; i--; }while(i>0); L_AD_data = ADsum / 8; ADsum = 0; i = 8; do { set_adc_channel(2); // Rch delay_us(50); ADtemp = read_adc(); ADsum = ADsum + ADtemp; i--; }while(i>0); R_AD_data = ADsum / 8; } // ******************************************************* // 関数名 void sout(void data) // 概要 spi出力 // ******************************************************* void sout(void) { int i; i = 8; output_low(CS); // CSイネーブル do { i--; if(bit_test(L_VOL_data,i)) // MSBファースト output_high(SDI); else output_low(SDI); output_high(SCLK); // クロックパルス delay_us(1); output_low(SCLK); }while(i>0); i = 8; output_low(SDI); do { i--; if(bit_test(R_VOL_data,i)) // MSBファースト output_high(SDI); else output_low(SDI); output_high(SCLK); // クロックパルス delay_us(1); output_low(SCLK); }while(i>0); delay_us(1); output_high(CS); // CSディセーブル output_low(SDI); } // ******************************************************* // 関数名 int vol_calc(int) // 概要 1バイトからボリューム値を変換する // ******************************************************* int vol_calc(int data) { int temp; if(data < 1) // ボリューム絞り切った時に-95.5dBにする temp = 1; else temp = data / 2 + 65; return(temp); } // ******************************************************* // 関数名 void init(void) // 概要 ハードウエアの初期化 // ******************************************************* void init(void) { TRISA = 0b00111111; PORTA = 0b00001100; port_a_pullups(0b00110001); PORTC = 1; TRISC = 0; OPTION_REG = 0b00000111; setup_comparator(NC_NC_NC_NC); setup_vref(FALSE); delay_ms(1000); // ポートが落ち着くまで待つ R_VOL_data = 1; // ボリューム最小 L_VOL_data = 1; sout(); output_high(MUTE); // ミュート解除 output_high(EXT); if(input(MODE) == 1) // モード入力が"0"であれば { ADCON0 = 0b0000101; // 外部ボリューム モード ADCON1 = 0b0011000; ANSEL = 0b0000110; enable_interrupts(INT_RTCC); }else // ロータリーエンコーダー モード { WPUA = 0b00110111; // GP0,1 プルアップ抵抗付ける enable_interrupts(INT_EXT); // 外部変化割り込み 有効 DISABLE_INTERRUPTS(INT_RTCC); // TMR0割り込みを無効にする setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); // TMR1割り込みを有効にする ENCO_data = read_eeprom(0); // 前回のボリュームデーターの読み出し R_VOL_data = vol_calc(ENCO_data); L_VOL_data = R_VOL_data; sout(); // ボリュームデーターをPGAに書込む } } void main() { init(); AD_1st = 1; // 1回目のAD変換 enable_interrupts(GLOBAL); while(1) { if(input(P_DOWN) == 1) // 電圧低下 { DISABLE_interrupts(GLOBAL); // 割り込み禁止 output_low(MUTE); // ミュート output_low(EXT); if(input(MODE) == 0) { // output_high(DEBUG1); write_eeprom(0,ENCO_data); // output_low(DEBUG1); } delay_ms(2000); // 2秒 ウエイト reset_cpu(); // リセット } } }