/* att8.c * 2007.03.13 自動電源復帰 * 2007.03.10 ロータリーエンコーダ */ #include #include #define Nop() do { _asm nop _endasm; } while(0) #define ClrWdt() do { _asm clrwdt _endasm; } while(0) #define Sleep() do { _asm sleep _endasm; } while(0) /* #define Reset() do { _asm reset _endasm; } while(0) */ #define EEPROM_WRITE() do { \ EECON2=0x00; /* Get in right bank */ \ __asm MOVLW 0x55 __endasm; \ __asm MOVWF EECON2 __endasm; \ __asm MOVLW 0xaa __endasm; \ __asm MOVWF EECON2 __endasm; \ __asm BSF EECON1,1; __endasm; \ } while(0) /* PORT# In/Out Name RA0 IN/OUT PHB/DATA RA1 OUT STB RA2 IN/OUT PHA/CK RA3 OUT STANDBY RA4 IN IR/SW1 RB0 IN VS RB1 OUT LED1 RB2 OUT LED2 RB3 OUT LED3 RB4 OUT LED4 RB5 OUT LED5 RB6 OUT LED6 RB7 OUT LED7 */ #define DATA RA0 #define STB RA1 #define CK RA2 #define APOWER RA3 #define PHB RA0 /* DATAと共用 */ #define PHA RA2 /* CKと共用 */ #define IR (RA4 == 0) /* negative logic */ #define SW1 (RA4 == 0) /* IRと共用 */ #define LED1 RB1 #define LED2 RB2 #define LED3 RB3 #define LED4 RB4 #define LED5 RB5 #define LED6 RB6 #define LED7 RB7 #define LON 0 /* sink on */ #define LOFF 1 #define AON 1 #define AOFF 0 #define CPUFREQ 20.0 // MHz #define MSEC 20 //CPUFREQ*250.0/256 //CPUFREQ/4*1000/256 // kHz #define TENMSEC 10*MSEC #define SEC 100 // 1000/TENMSEC #define VOLMAX 20 // ボリュームの最大値 #define ATTMAX 20 /* VOLMAXに対応する電子ボリュームICの設定値 */ #define ATTMUTE 40 /* 消音に相当する電子ボリュームICの設定値 */ #define VOLLEDS 7 // ボリューム表示LEDの数 #define VOL1 3 // 1*VOLMAX/VOLLEDS #define VOL2 6 // 2*VOLMAX/VOLLEDS #define VOL3 9 // 3*VOLMAX/VOLLEDS #define VOL4 12 // 4*VOLMAX/VOLLEDS #define VOL5 15 // 5*VOLMAX/VOLLEDS #define VOL6 18 // 6*VOLMAX/VOLLEDS #define VSAVE 0x00 /* EEPROM ADDRESS */ #define LONLONG 250 /* IR信号リーダー部の最大ON長さ */ #define LONSHORT 2*MSEC /* 最小ON長さ */ #define LOFFLONG 10*MSEC /* 最大OFF長さ */ #define LOFFSHORT 1*MSEC /* 最小OFF長さ */ #define DONLONG 1*MSEC /* DATA部ON長さ最大値 */ #define DONSHORT MSEC/4 #define BUFSIZE 1 // codeバッファサイズ #define SMOOTH 4 /* ロータリーエンコーダの平滑度 */ /* code table * #define NCOLS 6 #define TOSHIBA 0 #define HITACHI NCOLS #define SANYO 2*NCOLS #define NEC 3*NCOLS static const unsigned char codes[4*NCOLS] = { 0x02, 0x58, 0x78, 0x08, 0xf0, 0x48, 0x0a, 0x48, 0xa8, 0xd0, 0x90, 0xe8, 0x0c, 0x90, 0x50, 0xd0, 0xa0, 0x00, 0x18, 0x40, 0xc0, 0x90, 0x50, 0x10 }; static const unsigned char default_company = NEC; */ /* 上記テーブルを使わずNECに固定 */ #define CORPID 0x18 #define UPCODE 0x40 #define DOWNCODE 0xc0 #define MUTECODE 0x90 #define INPUTCODE 0x50 #define POWERCODE 0x10 static signed char i, j; static unsigned char datum, flag, volume, mute, downwards, brink, zbrink, rotsave; static unsigned char counta, countb, phasea, phaseb; static unsigned int value; static unsigned char volatile count0, count10, free1, free2; static unsigned int volatile up0, up1, down0, down10; static unsigned char inbuff[BUFSIZE];//, upcode[BUFSIZE], downcode[BUFSIZE], mutecode[BUFSIZE]; static unsigned char irwidth, shortest, center, longest, company, command; int main(); void darken(); void volumesave(); /* configuration bits */ int at 0x2007 __config = _HS_OSC & _WDT_ON & _PWRTE_ON; /* interrupt process */ static void timer() interrupt 0 { /* Power fail? */ if ( INTF ) { INTF = 0; // 割り込みフラグクリア PORTA = 0x18; /* 下位3ビットのみLow */ PORTB = 0xff; /* All High (LED全消灯) */ TRISA = 0xff; /* RA全入力 */ TRISB = 0xff; /* RB全入力 */ volumesave(); T0IE = 0; INTE = 0; RBIE = 0; EEIE = 0; Sleep(); main(); } else { T0IF = 0; // 割り込みフラグクリア /* counters */ if ( count0 ) { ++up0; if ( down0 ) { --down0; } if ( down0 == 0 ) { count0 = 0; } } /* msec timer */ if ( count10 ) { if ( ++up1 > MSEC ) { up1 = 0; if (down10) { --down10; } } if ( down10 == 0 ) { count10 = 0; } } /* zero brink counter */ if ( zbrink ) { if ( ++free1 > TENMSEC ) { free1 = 0; if ( ++free2 > SEC ) { free2 = 0; if ( LED1 == LON ) { LED1 = LOFF; } else { LED1 = LON; } } } } } } void load_msec( unsigned int msec) { value = msec; count10 = 0; /* カウント停止 */ if ( value == 0 ) { return; } down10 = value; up1 = 0; /* msec以下をクリア */ ClrWdt(); /* WDTクリア */ count10 = 1; /* カウント開始 */ } unsigned int stop_msec() { count10 = 0; /* カウント停止 */ return down10; } void wait_msec( unsigned int msec) { value = msec; load_msec(msec); while ( count10 ) { ; } } void gap() { wait_msec(100); } void moment() { /* 0.5sec */ gap(); gap(); gap(); gap(); gap(); } // LED全消灯 void darken() { LED1 = LOFF; LED2 = LOFF; LED3 = LOFF; LED4 = LOFF; LED5 = LOFF; LED6 = LOFF; LED7 = LOFF; } // LED全点灯 void lighten() { LED1 = LON; LED2 = LON; LED3 = LON; LED4 = LON; LED5 = LON; LED6 = LON; LED7 = LON; } void volumedisp() { darken(); if ( volume == 0 || mute ) { free1 = 0; free2 = 0; zbrink = 1; } else { zbrink = 0; LED1 = LON; if ( volume < VOL1 ) { return; } LED2 = LON; if ( volume < VOL2 ) { return; } LED3 = LON; if ( volume < VOL3 ) { return; } LED4 = LON; if ( volume < VOL4 ) { return; } LED5 = LON; if ( volume < VOL5 ) { return; } LED6 = LON; if ( volume < VOL6 ) { return; } LED7 = LON; } } void volumebrink() { if ( downwards ) { /* 最上位のLEDを消灯 */ if ( LED7 == LON ) { LED7 = LOFF; } else if ( LED6 == LON ) { LED6 = LOFF; } else if ( LED5 == LON ) { LED5 = LOFF; } else if ( LED4 == LON ) { LED4 = LOFF; } else if ( LED3 == LON ) { LED3 = LOFF; } else if ( LED2 == LON ) { LED2 = LOFF; } else if ( LED1 == LON ) { LED1 = LOFF; } else { LED1 = LON; } } else { /* 最上位のLEDを点灯 */ if ( LED1 == LOFF ) { LED1 = LON; } else if ( LED2 == LOFF ) { LED2 = LON; } else if ( LED3 == LOFF ) { LED3 = LON; } else if ( LED4 == LOFF ) { LED4 = LON; } else if ( LED5 == LOFF ) { LED5 = LON; } else if ( LED6 == LOFF ) { LED6 = LON; } else if ( LED7 == LOFF ) { LED7 = LON; } else { darken(); } } } /* 電子ボリュームICにクロックを送る */ void clock_pulse() { CK = 0; ++j;++j; /* タイミングのためのダミー */ CK = 1; ++j;++j;++j;++j;++j; /* タイミングのためのダミー */ CK = 0; ++j;++j; /* タイミングのためのダミー */ } /* 電子ボリュームIC(TOSHIBA TC9210)にデータを送る */ void volumeset() { T0IE =0; /* Timer0 割り込み禁止 */ CK = 0; STB = 0; TRISA = 0xf8; /* RA下位3ビットのみ出力 */ datum = volume; if ( mute ) { datum = 0; } if ( datum == 0 ) { datum = ATTMUTE; } else { datum = ATTMAX - datum; } /* RL両チャンネル同時セット */ DATA = 1; j = 0; i = 0; while ( ++i <= 2 ) { clock_pulse(); } /* 減衰量 */ i = 0; while ( ++i <= 6 ) { DATA = datum & 0x01; datum = datum>>1; clock_pulse(); } /* LD, CS1, CS2 */ DATA = 0; i = 0; while ( ++i <= 3 ) { clock_pulse(); } /* CS3, CS4 */ DATA = 1; i = 0; while ( ++i <= 2 ) { clock_pulse(); } STB = 1; ++j;++j;++j;++j;++j; STB = 0; TRISA = 0xff; /* RA全入力 */ T0IE =1; /* Timer0 割り込み許可 */ } /* ボリューム設定値をEEPROMに保存 */ void volumesave() { while ( WR ) {;} GIE = 0; /* 割り込み禁止 */ EEADR = VSAVE; EEDATA = volume; WREN = 1; EEPROM_WRITE(); WREN = 0; GIE =1; /* 割り込み許可 */ } void volumeresume() { while ( WR ) {;} EEADR = VSAVE; RD = 1; volume = EEDATA; if ( volume > VOLMAX ) { volume = 0; } volumeset(); } void volumeup() { mute = 0; if ( downwards ) { if ( volume > 0 ) { --volume; volumeset(); } /* else { downwards = 0; } */ } else { if( volume < VOLMAX ) { ++volume; volumeset(); } /* else { downwards = 1; } */ } } unsigned char onwidth() { count0 = 0; /* カウント停止 */ up0 = 0; down0 = longest; count0 = 1; /* カウント開始 */ while ( IR && count0 ) { ; } count0 = 0; /* カウント停止 */ irwidth = up0; return irwidth; } unsigned char offwidth() { count0 = 0; /* カウント停止 */ up0 = 0; down0 = longest; count0 = 1; /* カウント開始 */ while ( ! IR && count0 ) { ; } count0 = 0; /* カウント停止 */ irwidth = up0; return irwidth; } /* IR信号リーダー? */ unsigned char leader() { flag = 0; datum = 0; longest = LONLONG; onwidth(); if ( IR ) { flag=1; return 0; } /* too long */ if ( irwidth < LONSHORT ) { flag=2; return 0; } /* too short */ longest = LOFFLONG; offwidth(); if ( ! IR ) { flag=3; return 0; } if ( irwidth < LOFFSHORT ) { flag=4; return 0; } datum = 0xff; return datum; /* IR信号リーダーである */ } /* IR信号を1バイト読み込み */ unsigned char irbyte() { datum = 0; i = 0; while ( ++i <= 8 ) { longest = DONLONG; onwidth(); if ( IR ) { flag=5; return 0; } /* too long */ if ( irwidth < DONSHORT ) { flag=6; break; } /* too short */ center = irwidth + irwidth>>1; /* x1.5 */ longest = irwidth<<2; /* x4 */ shortest = irwidth>>1; /* x0.5 */ offwidth(); if ( ! IR ) { flag=0; break; } /* 休止が長い(ストップビット) */ if ( irwidth < shortest ) { flag=7;return 0; } /* 休止が短い */ flag = 8; /* ストップビットではない */ datum = datum<<1; if ( irwidth > center ) { datum = datum | 1; } } return datum; } /* コマンド受信 */ unsigned char ircommand() { command = 0; if ( leader() == 0 ) { return 0; } command = irbyte(); if ( flag & 0x07 ) { return 0; } datum = irbyte(); if ( flag & 0x07 ) { return 0; } if ( (command ^ datum ) != 0xff ) { flag=9; return 0; } /* パリティエラー */ /* if ( command != codes[company] ) { flag=10; return command; } * 会社IDが違う */ if ( command != CORPID ) { flag=10; return command; } /* ID固定 */ command = irbyte(); if ( flag & 0x07 ) { return 0; } datum = irbyte(); if ( flag & 0x07 ) { return 0; } if ( (command ^ datum) != 0xff ) { flag=9; return 0; } /* パリティエラー */ flag = 0; return command; /* どのコマンドか? * i=1; while ( i < NCOLS ) { if ( command == codes[company + i] ) { break; } ++i; } if ( i >= NCOLS ) { flag=11; return command; } * コマンド表に無い */ } /* UP/DOWNキーのリピート */ void volrepeat() { brink = 0; flag = 1; while ( flag ) { brink = ~brink & 0x01; if ( brink ) { volumebrink(); } else { volumedisp(); } volumeup(); wait_msec ( 50 ); load_msec ( 200 ) ; while ( count10 ) { flag = 0; if ( IR ) { leader(); if ( flag ) { while ( IR ) {;} break; } } } stop_msec(); } volumedisp(); } void power_on() { PORTA = 0x10; /* 下位4ビットLow */ PORTB = 0x00; /* LED全点灯 */ APOWER = AON; /* アンプパワーON */ TRISA = 0xff; /* RAは全入力 */ TRISB = 0x01; /* RB0入力、他は出力 */ OPTION_REG = 0x07; /* WDT分周比128 (約2秒) */ /* カウンタの初期化 */ count0 = 0; count10 = 0; zbrink = 0; up0 = 0; up1 = 0; down0 = 0; down10 = 0; /* いったん消音 */ mute = 0; volume = 0; volumeset(); ClrWdt(); /* WDTクリア */ PSA = 1; // TM0はプリスケーラ使わない(WDTで使う) T0IE = 1; // TMR0オーバーフロー割り込み発生許可 INTE = 1; /* INTピン割り込み許可 */ GIE= 1; // 割り込み許可 moment(); moment(); darken(); /* LED消灯 */ moment(); /* company = default_company; */ downwards = 0; volumeresume(); volumedisp(); /* ロータリーエンコーダ */ counta = 0; countb = 0; phasea = 0; phasea = 0; rotsave = 0; } void power_off() { PORTA = 0x10; /* 下位4ビットLow */ PORTB = 0xff; /* All High (LED全消灯) */ APOWER = AOFF; TRISA = 0xf7; /* RA3のみ出力 */ TRISB = 0xff; /* RB全入力 */ volumesave(); moment(); /* 二重押しを無視するためのウェイト */ moment(); } /* IR入力があればコマンドを解釈し実行 */ void irdecode() { if ( IR == 0 ) { return; } command = ircommand(); if ( flag ) { return; } if ( command == POWERCODE ) { if ( APOWER == AON ) { power_off(); } else { power_on(); } } else if ( command == UPCODE ) { downwards=0; volrepeat(); } else if ( command == DOWNCODE ) { downwards=1; volrepeat(); } else if ( command == MUTECODE ) { mute = ~mute & 1; volumeset(); volumedisp(); } } /* ロータリーエンコーダ */ void rotdecode() { /* PHA/PHB信号を積分 */ if ( PHA ) { if ( ++counta >= SMOOTH ) { counta = SMOOTH; phasea = 1; } } else { if ( counta ) { --counta; } if ( counta == 0 ) { phasea = 0; } } if ( PHB ) { if ( ++countb >= SMOOTH ) { countb = SMOOTH; phaseb = 1; } } else { if ( countb ) { --countb; } if ( countb == 0 ) { phaseb = 0; } } /* PHAの立ち下がりを検出 */ if ( rotsave && phasea == 0 ) { downwards = phaseb; volumebrink(); gap(); volumeup(); volumedisp(); } rotsave = phasea; } int main() { power_on(); while (1) { ClrWdt(); /* WDTクリア */ irdecode(); /* IR信号チェック */ rotdecode(); /* ロータリーエンコーダ */ } }