24 October 2015

赤外線リモコン作成 (TVの「d」ボタンが壊れたため)

テレビの「d」(データ放送)ボタンが故障したため、「d」だけを送信できる赤外線リモコンコード送信機を作ってみた。

マイコン PIC12F1822 (1個150円程度)と、Ir LED (10個で100円程度)を用いた。

回路

20151024-irsender-circuit.png

PIC12F1822 プログラム

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <xc.h>
 
/* PIC Configuration 1 */
__CONFIG(FOSC_INTOSC &  // INTOSC oscillator: I/O function on CLKIN pin
        WDTE_OFF &      // WDT(Watchdog Timer) disabled
        PWRTE_ON &      // PWRT(Power-up Timer) disabled
        MCLRE_OFF &     // MCLR pin function is digital input
        CP_OFF &        // Program memory code protection is disabled
        CPD_OFF &       // Data memory code protection is disabled
        BOREN_OFF &     // BOR(Brown-out Reset) disabled
        CLKOUTEN_OFF &  // CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin
        IESO_OFF &      // Internal/External Switchover mode is disabled
        FCMEN_OFF);     // Fail-Safe Clock Monitor is disabled
 
/* PIC Configuration 2 */
__CONFIG(WRT_OFF &      // Flash Memory Self-Write Protection : OFF
        VCAPEN_OFF &    // VDDCORE pin functionality is disabled
        PLLEN_OFF &     // 4x PLL disabled
        STVREN_ON &     // Stack Overflow or Underflow will not cause a Reset
        BORV_HI &       // Brown-out Reset Voltage Selection : High Voltage
        DEBUG_OFF &     // In-Circuit Debugger disabled, ICSPCLK and ICSPDAT are general purpose I/O pins
        LVP_OFF);       // Low-voltage programming : disable
 
#ifndef _XTAL_FREQ
    /* 例:4MHzの場合、4000000 をセットする */
    #define _XTAL_FREQ 4000000
#endif
 
// NECコードの場合
//#define TIMING_START_HI     9000
//#define TIMING_START_LO     4500
//#define TIMING_SIGNAL_HI    560
//#define TIMING_SIGNAL_1_LO  1690
//#define TIMING_SIGNAL_0_LO  560
 
// 家電協コードの場合
#define TIMING_START_HI     3500
#define TIMING_START_LO     1600
#define TIMING_SIGNAL_HI    540
#define TIMING_SIGNAL_1_LO  1200
#define TIMING_SIGNAL_0_LO  360
 
// シャープのTVの「d」ボタンの例
unsigned char code_1 = 0x55;
unsigned char code_2 = 0x5A;
unsigned char code_3 = 0xF1;
unsigned char code_4 = 0x48;
unsigned char code_5 = 0x7A;
unsigned char code_6 = 0x44;
 
//待ち時間が変数設定できるarg_delay_ms()関数を定義
//(__delay_ms()は引数に変数設定が出来ない為)
void arg_delay_ms(unsigned int x) {
    while(x) {
        __delay_ms(1);
        x--;
    }
}
 
void arg_delay_us(unsigned int x) {
    while(x) {
        __delay_us(1);
        x--;
    }
}
 
void decode_bit(unsigned char c){
    for(int i=0; i<8; i++){
        if(c & (0x80 >> i)){
            CCP1CON = 0b00001100;
            __delay_us(TIMING_SIGNAL_HI);
            CCP1CON = 0b00000000;
            __delay_us(TIMING_SIGNAL_1_LO);
        }
        else{
            CCP1CON = 0b00001100;
            __delay_us(TIMING_SIGNAL_HI);
            CCP1CON = 0b00000000;
            __delay_us(TIMING_SIGNAL_0_LO);
        }
    }
}
 
int main(int argc, char** argv) {
    // 基本機能の設定
    OSCCON = 0b01101010;        // 内部オシレーター 4MHz
    TRISA = 0b00101011;         // IOポートRA0(AN0),RA1(SCL),RA5(RX)を入力モード(RA3は入力専用)、RA2(SDA),RA4(TX)を出力モード
    APFCONbits.RXDTSEL = 1;     // シリアルポート RXをRA5ピンに割付
    APFCONbits.TXCKSEL = 1;     // シリアルポート TXをRA4ピンに割付
    ANSELA = 0b00000000;        // A/D変換をAN0,AN1,AN2,AN4を無効
    PORTA = 0;
 
    CCP1SEL = 0;            // RA2をCCP1(PWM)のP1Aで用いる
    CCP1CON = 0b00000000;   // PWM(シングル)
    T2CON   = 0b00000000;   // TMR2プリスケーラ値を1倍に設定, Timer2はこの時点ではOFF
    // PR2 = Fosc / (Fpwm * 4 * Prescale) + 1 = 4000000 / (38000 * 4 * 1) + 1 = 27
    PR2 = 0x19;     // 27→25
    CCPR1L = 0x0c;  // PR2=0x19の場合デューティ値は6bitで、デューティ比50%の設定
    CCPR1H  = 0;
    TMR2 = 0;       // Timer2カウンタを0
 
    // PWM開始
    TMR2ON = 1;
    // 0.05秒待つ
    __delay_ms(50);
 
    // スタートビット(リーダ)
    CCP1CON = 0b00001100;
    __delay_us(TIMING_START_HI);
    CCP1CON = 0b00000000;
    __delay_us(TIMING_START_LO);
 
    // 送信データ本体
    decode_bit(code_1);
    decode_bit(code_2);
    decode_bit(code_3);
    decode_bit(code_4);
    decode_bit(code_5);
    decode_bit(code_6);
 
    // ストップビット(トレーラ)
    CCP1CON = 0b00001100;
    __delay_us(TIMING_SIGNAL_HI);
    CCP1CON = 0b00000000;
    __delay_us(TIMING_SIGNAL_HI);
  
    /* 終了 (無限ループでこれ以降何もしない) */
    while(1){
        __delay_ms(1000);
    }
    return (EXIT_SUCCESS);
}

回路作成例と、使用例

20151024-irsender-board.jpg
回路作成例


20151024-irsender.jpg
使用例