/************************************************************************* * PIC24F_IR_REC_TEST * * Condition: * 10MHz External X'tal oscillator * Fcy=10MHz/2=5MHz, Tcy=200ns * * MPU: 、PIC24FJ64GA002 *    ・フラッシュ:64kバイト *    ・RAM:8kバイト * * N.Ishii 2019.4.30 **************************************************************************/ #include "p24FJ64GA002.h" #include "LCD_Lib3.h" // Set Configuration Word 1 _CONFIG1 ( JTAGEN_OFF & // JTAG Port: OFF GCP_OFF & // Code Protect: OFF GWRP_OFF & // Write Protect:OFF BKBUG_OFF & // Background Debug: OFF COE_OFF & // Clip On Emulation: OFF ICS_PGx1 & // Select ICD Pin: EMUC/EMUD-> PGC1/PGD1 For Common Use FWDTEN_OFF // WDT: OFF ) // Set Configuration Word 2 _CONFIG2 ( IESO_OFF & // 2 Speed Start Up: OFF FNOSC_PRI & // 10MHz 外部水晶振動子-> 10MHz x1=10MHz FCKSM_CSDCMD & // Change Clock Control: OFF Clock Monitor: OFF OSCIOFNC_OFF & // OSCO/RA3 function: Used Primary Oscillator IOL1WAY_OFF & // RP Register Protection: Unlimited Writes To RP Registers I2C1SEL_PRI & // I2C1 pins Select: Use Primary I2C1 pins POSCMOD_XT // Oscillator Selection: External X'tal(XT MODE) ) /// ポート定義 #define IRD_PORT PORTBbits.RB5 // 赤外線ポート #define LED LATAbits.LATA4 // 緑LEDポート #define RELAY LATAbits.LATA0 // RELAYポート /// 赤外線処理パラメータ #define LEADER_LOW_RESV_S 20 // Sonyコードの、リーダー(ガイドパルス)部の、ON/(Low)パルス幅規定値 // = 2.4mSx90%= 2.16≒ 2mS→ T1割込み周期=100uSなので、100x20= 2mS #define LEADER_HI_RESV_S 4 // Sonyコードの、リーダー部の、OFF(Hi)パルス幅規定値 // = 0.6mSx70%(たぶん)= 0.42≒0.4mS→ T1割込み周期=100uSなので、100x4= 0.4mS // 注:ガイドパルスとしては、最初のON/(Low)パルス幅としているらしいが、リーダーとしては、次のHiも //   含めるようだ。 #define ENDCHECK 150 // Sonyコードの、エンド部の、Hiパルス幅規定値 // =45mSx33%(たぶん)= 15mS→ T1割込み周期=100uSなので、100x150= 15mS #define BIT_HI_RESV 9 // Sonyコードの、データ部:Hiの判定基準(Low幅の違いによって判断) // Low幅= 1.2mSx75%= 0.9mS→ T1割込み周期=100uSなので、100x9= 0.9mS /// csse文のシーケンス番号定義 #define WAITON 0 #define CHECKON 1 #define CHECKOFF 2 #define DATAIN 3 #define DATAON 0 #define DATAOFF 1 /// データ読込みビット・バイト数定義 #define BIT 8 #define BYTE 2 /// リモコン・コード定義:SONYコード(audio-technica "ATV-515"使用) #define POWER_ON_CODE 0x49 // リモコンの、音量+キーを代用 #define POWER_OFF_CODE 0xC9 // リモコンの、音量−キーを代用 unsigned char ird_data[2]; char end_flag = 0; /// Message Data for LCD const char MsgStart[] = "Start!"; /* プロトタイプ宣言 */ void ird_resv(void); char resv_data(void); void lcd_hex(unsigned char c); /************************************************ * Function Main ************************************************/ int main(void){ CLKDIV= 0; // クロック分周 1:1 AD1PCFG= 0xFFFF; // 全てディジタルに指定 /// ポートの入出力モード設定 TRISB = 0x03FF; // RB15-10:LCD データ・制御出力、RB5:赤外線受信モジュール入力 // RB1-0:SW入力、その他未使用:入力 // TRISA = 0xFFEF; // RA4:緑LED、その他未使用:入力 TRISA = 0xFFEE; // RA0:RELAY_ON、RA4:緑LED、その他未使用:入力 /// Set O.D ODCA = 0x0001; // RA0:RELAY_ON is Open Drain /// Set Pull Up CNPU1 = 0x0030; // Pull Up Port is RB0(SW1), RB1(SW2) CNPU2 = 0x0060; // Pull Up Port is RB8(CD/), RB9(WE/) LED = 1; // LED OFF RELAY = 0; // RELAY OFF /// タイマ1設定 /// 外部水晶振動子使用:Fosc=10M・タイマ入力源:Fcy=5M(Fcy=Fosc/2)・PS=1 /// Ft1=Fcy/PS*(PR1+1)= 5M/1*500=10kHz=100usec周期 T1CON = 0b1000000000000000; PR1 = 499; // 100usec IPC0bits.T1IP = 5; // 割り込みレベル5に設定 IEC0bits.T1IE = 1; // 割り込み許可 /// 開始メッセージ表示 lcd_init(); // Initialize LCD lcd_clear(); lcd_str((char *)MsgStart); delay_ms(1000); // 約1秒待ち lcd_clear(); /// メインループ while(1){ //// T1割込み処理 /// 受信データ表示 if(end_flag){ // 上位バイトHEX表示 lcd_cmd(0x80); // 1行目の先頭へ lcd_str("Hight Byte= 0x"); lcd_hex(ird_data[0]); // 下位バイトHEX表示 lcd_cmd(0xC0); // 1行目の先頭へ lcd_str("Low Byte = 0x"); lcd_hex(ird_data[1]); /// リモコン電源制御 if(ird_data[0] == POWER_ON_CODE){ LED = 0; // 緑LED ON RELAY = 1; // RELAY ON } if(ird_data[0] == POWER_OFF_CODE){ LED = 1; // 緑LED OFF RELAY = 0; // RELAY OFF } end_flag = 0; } } } /********************* * タイマ1割り込み処理 * 100uS周期 **********************/ void __attribute__((interrupt, no_auto_psv)) _T1Interrupt(void){ IFS0bits.T1IF = 0; // 割り込みフラグクリア // LED = !LED; // 緑LEDの反転制御 ird_resv(); } /********************** * 赤外線受信処理 ***********************/ void ird_resv(void) { static unsigned char state = 0; static unsigned char count; switch(state) { case WAITON: if(IRD_PORT == 0){ // ONになるまで待つ state = CHECKON; count = 0; } break; case CHECKON: if(IRD_PORT == 0){ // ガイド・パルス部のON期間を計測 count++; break; } /// カウント終了の場合 if(count > LEADER_LOW_RESV_S){ state = CHECKOFF; count = 0; // breakしないで、CHECKOFFへ } else{ state = WAITON; // ON期間が規定値以下なら初めからやり直し break; } case CHECKOFF: if(IRD_PORT == 1){ // リーダ部のOFF期間を計測 count++; break; } if(count < LEADER_HI_RESV_S){ // OFF期間が規定値以下なら初めからやり直し state = WAITON; break; } state = DATAIN; count = 0; // breakしないで、DATAINへ case DATAIN: state = resv_data(); // データコードの受信 break; } return; } /************************************************************ * データコード(2byte)を受信し、ird_data[]に格納 *************************************************************/ char resv_data(void) { static unsigned char count = 0; static unsigned char bitcount = 0; static unsigned char bytecount = 0; static unsigned char bytedata = 0; static unsigned char datamask = 0x80; // MSBファースト static char state = DATAON; while(bytecount < BYTE) { while(bitcount < BIT) { switch(state) { case DATAON: if(IRD_PORT == 0){ // ON/期間計測 count++; return DATAIN; } /// ON/期間計測終了 if(count >= BIT_HI_RESV){ // ON部がBIT_HI_RESV以上ならbit1と判断 bytedata |= datamask; } datamask >>= 1; count = 0; state = DATAOFF; // breakしないで、DATAOFFへ case DATAOFF: if(IRD_PORT == 1){ count++; if(count > ENDCHECK){ // OFF部がENDCHECK以上なら終了 end_flag = 1; bitcount = 0; count = 0; bytedata = 0; datamask = 0x80; bytecount = 0; state = DATAON; return WAITON; } return DATAIN; } /// '1'でなければ、DATAONへ移行 bitcount++; count = 0; state = DATAON; } } ird_data[bytecount] = bytedata; // 1byte分のデータを格納 bitcount = 0; count = 0; bytedata = 0; datamask = 0x80; state = DATAON; bytecount++; // 次のバイトへ /// breakしないで、下位バイト読込みステートにし、DATAONへ } } /****************** * 16進文字変換表示 *******************/ void lcd_hex(unsigned char c){ const char hexch[] ="0123456789ABCDEF"; lcd_data(hexch[c >> 4]); lcd_data(hexch[c & 0x0F]); }