/***********************************************(abc889_18426.c)***
 *      NEC/SONY赤外線リモコンの送受信
 ******************************************************************/
#include "mcc_generated_files/mcc.h"
#include "string.h"
#include "i2cLCD_ST7032i.h"
#define MAXDATA 90                              // 赤外線データ配列数
#define MAXADDR 10                              // SONYアドレス配列数
/*
#define BFSIZE  20                              // eusart.hで定義
*/
// ----- NEC pulse time parameter ----
#define MARK()      __delay_us(562)
#define SPACE_1()   __delay_us(1686)
#define SPACE_0()   __delay_us(562)
#define LEADER_1()  __delay_us(8992)
#define LEADER_0()  __delay_us(4496)
#define GYAP_0()    __delay_ms(43)
// ---- SONY puls time parameter -----
#define S_LEADER()  __delay_us(2400)
#define S_SPACE()   __delay_us(600)
#define S_MARK_0()  __delay_us(600)
#define S_MARK_1()  __delay_us(1200)
#define S_GYAP_20() __delay_ms(19)
#define S_GYAP_15() __delay_ms(25)
#define S_GYAP_12() __delay_ms(29)
// ----- DSM & STM controle ----
#define DSM_1()     (MD1CON0bits.MD1BIT = 1)
#define DSM_0()     (MD1CON0bits.MD1BIT = 0)
#define SMT_START() (SMT1CON1bits.SMT1GO = 1)
#define SMT_STOP()  (SMT1CON1bits.SMT1GO = 0)
// ---- IOdata Customer Code ----
#define IO_CUSTOM   0xE880
/* -----  Variables  ----- */
uint16_t PW[MAXDATA];                           // Mark配列
int16_t  PR[MAXDATA];                           // Space配列
uint8_t  p_PW;                                  // Mark配列ポインタ
uint8_t  p_PR;                                  // Space配列ポインタ
char     sBf[BFSIZE];                           // 文字列作業エリア
char     rBuf[BFSIZE];                          // シリアル受信バッファ
uint8_t  sFlg;                                  // シリアル受信フラグ
uint8_t  Sony;                                  // Sonyフォーマット?
uint16_t Sa[MAXADDR];                           // SONYアドレス配列
uint16_t IO2[] = {0x1084,0x2084,0x3084};        // IOdata赤外線コード例
/*----- Send NEC Code  -----*/
void Ir_Leader(){
    DSM_1();                                    // send Leader
    LEADER_1();
    DSM_0();
    LEADER_0();
}
void Ir_Stop(){
    DSM_1();
    MARK();                                     // send stop
    DSM_0();
}
void Ir_Send(uint8_t *dt, uint8_t x){           // send Byte
    uint8_t sft;
    for (int j = 0; j < x;j++){
        sft = 0x01;
        for(int i = 0; i < 8;i++){
            DSM_1();
            MARK();
            DSM_0();
            if(dt[j] & sft)  SPACE_1();
            else             SPACE_0();
            sft <<= 1;
        }
    }
}
void Ir_Send2(uint16_t wd){                     // send Word
    uint16_t wsft = 0x0001;
    for(int i = 0; i < 16;i++){
        DSM_1();
        MARK();
        DSM_0();
        if(wd & wsft)   SPACE_1();
        else            SPACE_0();
        wsft <<= 1;
    }
}
void send_NEC(uint16_t cst, uint16_t d){
    uint16_t dat;
    IO_RC2_SetLow();
    SMT_STOP();                                 // 赤外線測定中断
    dat = (d & 0x00FF) | ((~d << 8) & 0xFF00);  // Calc data code
    Ir_Leader();                                // Leader Start
    Ir_Send2(cst);                              // Send Custmer
    Ir_Send2(dat);                              // Send Data
    Ir_Stop();         	                        // stop
    LCD_clr();
    sprintf(sBf,">NEC %04X-%04X",cst,dat);
    LCD_str(sBf);
  printf("\n\r>NEC %04X-%04X",cst,dat);
    SMT_START();                                // 測定再開
}
/*----- Send IOdata code  ------*/
void send_IOdata(uint8_t c){                    // from IOarray(word)
    uint16_t w = IO2[c];
    uint16_t wLo;
    uint16_t wHi;
    IO_RC2_SetLow();
    SMT_STOP();                                 // 赤外線測定中断
    wLo = (w & 0x00FF) | ((~w << 8) & 0xFF00);  // Calc Low word
    wHi = ((w >> 8) & 0x00FF) | (~w & 0xFF00);  // Calc High word
    Ir_Leader();                                // Leader Start
    Ir_Send2(IO_CUSTOM);                        // Send Custom  
    Ir_Send2(wLo);                              // Send Data1
    Ir_Stop();         	                        // stop
    GYAP_0();                                   // Gyap time
    Ir_Leader();                                // Leader Start 
    Ir_Send2(IO_CUSTOM);                        // Send Custom  
    Ir_Send2(wHi);                              // Send Data2
    Ir_Stop();                                  // stop
    LCD_clr();
    sprintf(sBf,">IOdata %08X",w);
    LCD_str(sBf);
    printf("\n\r>IOdata %08X",w);
    SMT_START();                                // 測定再開
}
/*----- Send SONY Code ----*/
void send_SONY(uint16_t wd, uint16_t ad){
    uint8_t  btc;                               // bit counter
    uint32_t icd;                               // IRcode data
    uint8_t  adx;                               // address number
    uint32_t sft;                               // shift data
    LCD_clr();
    sprintf(sBf,">Sony:%04X-%04X",wd,ad);
    LCD_str(sBf);
    printf("\r\n%s\n\r",sBf);
    icd = (uint32_t)(wd & 0x007F);
    if(wd & 0x0080){                            // 15bit mode?
        btc = 15;
        icd += (uint32_t)((wd >> 1) & 0x7F80); 
    }else{
        if(wd & 0x8000){                        // 20bit mode?
            btc = 20;
            adx = (wd >> 8) & 0x003F;
            if(adx >= MAXADDR){
                btc = 0;
            }else{
                if(wd & 0x4000){                // write?
                    icd += (uint32_t)ad << 7;
                    Sa[adx] = ad;
                }else{                          // read
                    icd += (uint32_t)Sa[adx] << 7;
                }
            }
        }else{                                  // 12bit mode
            btc = 12;
            icd += (uint32_t)((wd >> 1) & 0x0F80);
        }
    }
    if(btc){                                    // 送信データが有効なら
        IO_RC2_SetHigh();
        SMT_STOP();                             // 赤外線測定中断
        sft = 0x00000001;
        DSM_1();                                // send Leader
        S_LEADER();
        for(int i = 0; i < btc; i++){
            DSM_0();                            // send Space
            S_SPACE();
            DSM_1();                            // send Mark
            if(icd & sft)   S_MARK_1();
            else            S_MARK_0();
            sft <<= 1;
        }
        DSM_0();                                // send Stop
        if(btc==20){
            S_GYAP_20();
        }else if(btc==15){
            S_GYAP_15();
        }else{
            S_GYAP_12();
        }
        sprintf(sBf,"- IR %05X",icd);
        LCD_cursor(0,1);
        LCD_str(sBf);
        printf("\r%s",sBf);
        SMT_START();                            // 測定再開
    }
}
void prt_Hex(uint8_t w, uint8_t n){             // 16進数表示
    if(n){
        sprintf(sBf,"%02X ",w);
        printf("  >> %02XH\n\r",w);
    }else{
        sprintf(sBf,"%02X",w);
        printf("  >> %02XH",w);  
    }
    LCD_str(sBf);                               // LCD表示
 }
/*-------------------------------------------
 *            Main application
 *-------------------------------------------*/
void main(void){
    uint8_t  ird;                               // 赤外線データ
    uint8_t  sbt;                               // ビットセット用バイト
    uint8_t  bct;                               // 有効ビットカウンタ
    uint8_t  sgf;                               // データ有効フラグ
    uint16_t sDat;                              // SONY送信データ
    uint16_t sAdr;                              // SONY送信アドレス
    char     *end;                              // 文字列切り出し処理用
    SYSTEM_Initialize();                        // デバイス初期化
    LCD_init();                                 // LCD初期化
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();
    LCD_str("== ready ==");
  // --- テスト用データセット
    Sa[0] = 0x04B9;                             // SONYデフォルトアドレス
    sDat  = 0xC000;
    sAdr  = 0x1C5A;
    while (1)                                   // 赤外線信号受信繰返し
    {
        p_PW = 0;                               // データポインタ初期化
        p_PR = 0;
        SMT1PWAIF = 0;                          // フラグクリア
        SMT1PRAIF = 0;
        SMT1IF = 0;
        SMT_START();                            // 赤外線測定開始
        printf("\r\n-ready\r\n");               // 準備完了メッセージ送信
        // ====== 赤外線信号の受信・送出ループ =====
        while((p_PR < MAXDATA)){                // バッファ満杯まで繰返
           if(sFlg){                            // 受信データがあれば?
                if(strchr(rBuf,'X') || strchr(rBuf,'x')){
                    sDat = (uint16_t)strtol(rBuf, &end, 16);
                    sAdr = (uint16_t)strtol(end,  NULL, 16);
                    send_SONY(sDat,sAdr);       // SONYコード送信
                    send_SONY(sDat,sAdr);       // SONYコード送信(2回目)
                }else{                          // IODATA(NEC)コード
                    uint8_t n = atoi(rBuf);
                    if((n > 0) & (n < 4)){      // 配列データ数内か?
                         send_IOdata(n-1);      // IOdataコード送信
                    }
                }
                sFlg = 0;                       // シリアルフラグをクリア
                printf("\n\r");
            }
            if(PORTCbits.RC4 == 0){             // テストボタンが押された?
          // ---- 赤外線コード送信(テスト用、以下のどれかを有効に)
                send_SONY(sDat,sAdr);           // 前回データを送信
          //      send_IOdata(0);               // 赤外線送信(IOdata)
          //      send_NEC(0x847C,0x10EF);      // 赤外線送信(NEC)
          //      send_SONY(0x0200,0);          // 赤外線送信(SONY12)
          //      send_SONY(0xB4D0,0);          // 赤外線送信(SONY15)
          //      send_SONY(0xC000,0x1C5A);     // 赤外線送信(SONY20)
          //      send_SONY(0x8000,0);          // 赤外線送信(SONY20)
            }
/*          // ---- LCD画面シフト操作 (現在無効)
            if(PORTAbits.RA0 == 0){             // ボタン0が押されていたら
                LCD_sift(RIGHT);                // LCD表示右シフト
                __delay_ms(100);                // チャタリング対策
            }
            if(PORTAbits.RA1 == 0){             // ボタン1が押されていたら
                LCD_sift(LEFT);                 // LCD表示左シフト
                __delay_ms(100);                // チャタリング対策
            }
 */
            // ----- 赤外線信号受信 ----
            if(SMT1PWAIF){                      // mark終了なら
                SMT1PWAIF = 0;                  // フラグクリア
                PW[p_PW++]=SMT1CPW;             // High時間を保存
            }
            if(SMT1PRAIF){                      // space終了なら
                SMT1PRAIF = 0;                  // フラグクリア
                if(SMT1CPR < 10000){            // 10ms未満なら
                    PR[p_PR++] = SMT1CPR;       //    Low時間を保存
                }else{                          // 10ms以上なら
                    PR[p_PR++] = -(SMT1CPR / 1000); // msに変換し負数で保存
                }
            }
            if(SMT1IF){                         // 無信号が100ms続いたら
                SMT1IF = 0;                     // フラグクリア
                PR[p_PR++]=0;                   // 無信号記号「0」を保存
                break;
            }
        }
        SMT_STOP();                             // 測定終了
        // ===== 受信結果を解析・送信する =====
        ird = 0;
        sbt = 1;
        bct = 0;
        sgf = 0;
        LCD_clr();
        if(PW[0]<3000){
            Sony = 7;                           // -> SONY Mode
            IO_RC2_SetHigh();
            sprintf(sBf,"$SONY, %d",p_PW);
            LCD_str(sBf);
            puts(sBf);
        }else{
            Sony = 0;                           // -> NEC Mode
            IO_RC2_SetLow();
            sprintf(sBf,"$NEC, %d",p_PW);
            LCD_str(sBf);
            puts(sBf);
        }
        printf(" -  mark  space (us)\r\n");     // タイトル送信
        LCD_cursor(0,1);
        for(char i = 0; i < p_PW; i++){         // 保存した時間を送信
            printf("%2d %5d",i,(uint16_t)PW[i]); // mark時間
            if(PR[i]==0) {                      // 無信号なら
                printf("    ---");              //  「---」を送信
                if(Sony){
                    if(PW[i] < 1600){           // markが1600us未満なら   
                        bct++;
                        if(PW[i] > 900){        // markが900us超なら
                            ird |= sbt;         // シフトバイトを加える
                            printf("  1");
                        }else{
                            printf("  0");
                        }
                        prt_Hex(ird, 0);        // 16進数で表示
                    }
                } 
            }else if(PR[i] > 0){                // 10ms未満なら
                printf("  %5d",PR[i]);          //  us単位で送信(無改行)
                if (Sony){                      // *** SONY Code (Mark) 
                    if(PW[i] < 1600){           // markが1500us未満なら
                        sgf = 1;                // 有効データ
                        if(PW[i] > 900){        // markが900us超なら
                            ird |= sbt;         // シフトバイトを加える
                            printf("  1");
                        }else{
                            printf("  0");
                        }
                    }
                }else{                          // *** NEC Code (Space)
                    if(PW[i] < 1500){           // markが1500未満なら
                        if(PR[i]<2000){         // spaceが2000未満なら
                            sgf = 1;            // 有効データ
                            if(PR[i]>900){      // 更にspaceが900以上なら
                                ird |= sbt;     // シフトバイトを加える
                                printf("  1");
                            }else{
                                printf("  0");
                            }
                        }
                    }
                }
                if(sgf){                        // 有効データなら 
                    sbt <<= 1;                  // シフトバイトを左シフト
                    bct++;                      // 有効データ数を1増やす
                    if(Sony){                   // コードがSONYなら
                        if(bct == Sony){
                            prt_Hex(ird, 0);    // 16進数で表示
                            ird = 0;            // 赤外データをクリア 
                            sbt = 1;            // シフトバイトも初期化  
                            Sony = bct + 8;
                        }
                    }else{                      // コードがSONY以外
                        if((bct % 8) == 0){     // データ数が8の倍数?
                            prt_Hex(ird, 0);    // 16進数で表示
                            ird = 0;            // 赤外データをクリア 
                            sbt = 1;            // シフトバイトも初期化  
                        }
                    }
                    sgf = 0;
                }
            }else{                              // 10ms超なら
                printf("%7d (ms)",-PR[i]);      //   ms単位で送信
                 if(Sony){
                    if(PW[i] < 1600){           // markが1500us未満なら
                        bct++;
                        if(PW[i] > 900){        // markが900us超なら
                            ird |= sbt;         // シフトバイトを加える
                            printf("  1");
                        }else{
                            printf("  0");
                        }
                        prt_Hex(ird, 1);        // 16進数で表示
                        ird = 0;                // 赤外データをクリア 
                        sbt = 1;                // シフトバイトも初期化  
                        Sony = bct + 7;
                    }
                }
            }
            printf("\r\n");
        }
        if(p_PW >= MAXDATA){                    // バッファ満杯なら
            printf("-- Buffer Full --\r\n");    //  Buffer Full 送信
        }
    }
}
/*****   End of File   *****/
 |