본문 바로가기

소프트웨어

리모콘 IR신호 수신기 및 송신기 코드

반응형

저희 집에는 꺼내놓고 사용하는 리모콘이 너무 많습니다.

주로 사용하는 리모콘을 나열해보자면,

티비, 미박스, 사운드바, 빔프로젝터 정도가 됩니다.

리모콘이 너무 많으니 관리도 어렵고 사용도 불편해서 통합 리모콘을 만들기로 결심했습니다.

일단 리모컨 수신기 코드부터 작성했습니다.

구글링을 하면 여러 기본예제들이 있습니다. 기본 예제를 토대로 조금 수정했습니다.

 

먼저, 수신기 코드는 아래와 같습니다.

#include <IRremote.h>

// Tell IRremote which Arduino pin is connected to the IR Receiver (TSOP4838)
#if defined(ESP32)
int IR_RECEIVE_PIN = 15;
#else
int IR_RECEIVE_PIN = 11;
#endif
IRrecv IrReceiver(IR_RECEIVE_PIN);

// Configure the Arduino
void setup() {
    pinMode(LED_BUILTIN, OUTPUT);

    Serial.begin(115200);   // Status message will be sent to PC at 9600 baud
#if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL)
    delay(2000); // To be able to connect Serial monitor after reset and before first printout
#endif
    // Just to know which program is running on my Arduino
    Serial.println(F("START " __FILE__ " from " __DATE__ "\r\nUsing library version " VERSION_IRREMOTE));

    IrReceiver.enableIRIn();  // Start the receiver
    IrReceiver.blink13(true); // Enable feedback LED

    Serial.print(F("Ready to receive IR signals at pin "));
    Serial.println(IR_RECEIVE_PIN);
}

// The repeating section of the code
void loop() {
    if (IrReceiver.decode()) {  // Grab an IR code
        // Check if the buffer overflowed
        if (IrReceiver.results.overflow) {
            Serial.println("IR code too long. Edit IRremoteInt.h and increase RAW_BUFFER_LENGTH");
        } else {
            Serial.println("-----------------------------------------------------------------------------------------");                               // 2 blank lines between entries
            IrReceiver.printIRResultShort(&Serial);
            //Serial.println(F("Raw result in internal ticks (50 us) - with leading gap"));
            //IrReceiver.printIRResultRawFormatted(&Serial, false); // Output the results in RAW format
            //Serial.println(F("Raw result in microseconds - with leading gap"));
            //IrReceiver.printIRResultRawFormatted(&Serial, true);  // Output the results in RAW format
            Serial.println();                               // blank line between entries
            //Serial.println(F("Result as internal ticks (50 us) array - compensated with MARK_EXCESS_MICROS"));
            IrReceiver.compensateAndPrintIRResultAsCArray(&Serial, false);   // Output the results as uint8_t source code array of ticks
            //Serial.println(F("Result as microseconds array - compensated with MARK_EXCESS_MICROS"));
            IrReceiver.compensateAndPrintIRResultAsCArray(&Serial, true);    // Output the results as uint16_t source code array of micros
            IrReceiver.printIRResultAsCVariables(&Serial);  // Output address and data as source code variables

            IrReceiver.compensateAndPrintIRResultAsPronto(&Serial);

            /*
             * Example for using the compensateAndStorePronto() function.
             * Creating this String requires 2210 bytes program memory and 10 bytes RAM for the String class.
             * The String object itself requires additional 440 Bytes RAM from the heap.
             * This values are for an Arduino UNO.
             */
//        Serial.println();                                     // blank line between entries
//        String ProntoHEX = F("Pronto HEX contains: ");        // Assign string to ProtoHex string object
//        if (int size = IrReceiver.compensateAndStorePronto(&ProntoHEX)) {   // Dump the content of the IReceiver Pronto HEX to the String object
//            // Append compensateAndStorePronto() size information to the String object (requires 50 bytes heap)
//            ProntoHEX += F("\r\nProntoHEX is ");              // Add codes size information to the String object
//            ProntoHEX += size;
//            ProntoHEX += F(" characters long and contains "); // Add codes count information to the String object
//            ProntoHEX += size / 5;
//            ProntoHEX += F(" codes");
//            Serial.println(ProntoHEX.c_str());                // Print to the serial console the whole String object
//            Serial.println();                                 // blank line between entries
//        }
        }
        IrReceiver.resume();                            // Prepare for the next value
    }
}

간단히 설명하자면, 적외선 리모콘 신호는 국제적으로 규격이 통일되어 있지 않지만 주요 프로토콜들이 있습니다.

센서를 통해서 리모콘 신호를 받아서 신호를 디코딩 하여 어떤 프로토콜의 어떤 값을 사용했는지을 분석하는 소스입니다.

만약 프로토콜에 없는 경우엔 적외선 파형을 디지털값으로 기록하게끔 했습니다.

분석된 신호는 터미널을 통해 시리얼 데이터로 표현됩니다.

 

위 코드를 가지고 실제 프로토타입도 수신기를 제작한 뒤 실제 저희집에서 사용하는 각 리모콘 신호를 분석을 완료하였습니다.(만들어본 프로토타입 수신기는 아쉽게도 사진을 남기지 못하였습니다.)

 

아래는 저희집 기기들 중 통합리모콘에 사용할 리모콘 신호분석 결과입니다.

(티비, 셋탑박스, 빔프로젝터, 안드로이드티비 등 자주사용하는 리모콘들)

 

     삼성 티비 리모컨 (decode_type : 17, tbits : 32)
              E0E040BF : 전원버튼          
          `   E0E0807F : 외부입력
              E0E020DF : 1번
              E0E0A05F : 2번
              E0E0609F : 3번
              E0E010EF : 4번
              E0E0906F : 5번
              E0E050AF : 6번
              E0E030CF : 7번
              E0E0B04F : 8번
              E0E0708F : 9번
              E0E08877 : 0번
              E0E0C837 : 이전채널
              E0E0E01F : 볼륨+
              E0E0D02F : 볼륨-
              E0E0F00F : 음소거
              E0E048B7 : 채널+
              E0E008F7 : 채널-
              E0E058A7 : 메뉴
              E0E0D22D : 간편메뉴
              E0E006F9 : 상
              E0E08679 : 하
              E0E0A659 : 좌
              E0E046B9 : 우
              E0E016E9 : 확인
              E0E01AE5 : 복귀
              E0E0B44B : 종료

     올레티비 ( decode_type : 8 , tbits : 32)
              20DF10EF 이후 E0E040BF : 전원 온 (2개 1세트로, 티비 전원)
              9CA800FF : 전원 온 (셋톱 전원)
              9CA8827D : 메뉴
              9CA8D827 : 편성표
              9CA8F807 : 뷸륨 +
              9CA802FD : 볼륨 -
              9CA818E7 : 음소거
              9CA8926D : 채널 +
              9CA852AD : 채널 -
              9CA88877 : 상
              9CA8A857 : 하
              9CA848B7 : 좌
              9CA828D7 : 우
              9CA8C837 : 확인
              9CA88679 : 이전
              9CA846B9 : 나가기
              9CA8C03F : 1번
              9CA820DF : 2번
              9CA8A05F : 3번
              9CA8609F : 4번
              9CA8E01F : 5번
              9CA810EF : 6번
              9CA8906F : 7번
              9CA850AF : 8번
              9CA8D02F : 9번
              9CA830CF : 0번
              9CA8728D : *, 획추가
              9CA8F20D : #, 쌍자음
              9CA82ED1 : 검색
              9CA86897 : 지우기
              9CA8B04F : 한영전환              
              
     선택기 (decode_type : 8, tbits : 32) //통합리모콘에서 따옴.
              40BF7B84 : 1번 스위치          
              40BF5BA4 : 2번 스위치          
              40BFDB24 : 3번 스위치          
              40BFAA55 : 4번 스위치          
              40BFFB04 : 5번 스위치          
              40BF9B64 : 스위치

     미박스 적외선 리모컨(USB) (decode_type : 0, tbits : 32)//다른 주파수가 많이 혼선됨. 아래가 안되면 다른 주파수로 테스트 필요. 디코드타입과 비트는 변동없음.
              5933C5C3 : 전원
              32AA3277 : 이메일버튼(메뉴로 사용)
              75D19FC3 : R버튼 (뒤로가기로 사용)
              FD822A51 : 상
              1304DA8D : 하
              4C06E3EB : 좌
              C9B62F1F : 우
              5EF4863 : 엔터
              
     사운드바 (decode_type : 17, tbits : 32) // 누르고 있으면 아래의 주파수가 1번 출력후 4AB0F7B6 주파수만 연이어 출력 됨.(decode_type : 0, tbits : 32)
              34347887 : 전원
              3434E817 : 볼륨+
              34346897 : 볼륨-
              343451AE : F
              3434F807 : 음소거
              
     빔프로젝트 (decode_type : 8, tbits : 32)
              CF20D : 전원 온
              C728D : 전원 오프
              
            

/* 디코드 타입 정리
 -1 : unknown
  0 : unused
  1 : RC5 (sendRC5)
  2 : RC6 (sendRC6)
  3 : NEC (sendNEC)
  4 : SONY (sendSony)
  5 : PANASONIC (sendPanasonic)
  6 : JVC
  7 : SAMSUNG (sendSAMSUNG)
  8 : WHYNTER (sendWhynter)
  9 : AIWA_RC_T501 (sendAiwaRCT501)
 10 : LG (sendLG)
 11 : SANYO
 12 : MITSUBISHI
 13 : DISH (sendDISH)
 14 : SHARP (sendSharp)
 15 : DENON (sendDenon)
 16 : PRONTO (sendPronto)
 17 : LEGO_PF (sendLegoPowerFunctions)
*/

 

 

리모콘 신호의 분석이 끝났으니까 이제 리모콘 신호를 실제 발생시킬 수 있는 송신기 코드를 작성합니다.

일단 테스트 목적으로 간단하게 티비 볼륨을 줄이는 부분의 코드만 작성해 보겠습니다.

(이 역시 구글링으로 기본예제를 찾은뒤 수정 작업하면 쉽습니다.)

 

#include <IRremote.h>

 
IRsend irsend;
 
void setup() {
    Serial.begin(115200);
}
 
void loop() {
      const uint8_t NEC_KHZ = 38; // 38kHz carrier frequency for the NEC protocol
      const uint16_t irSignal[] = { 280,1720, 280,1770, 280,1770, 230,770, 330,720, 330,720, 280,1720, 280,770, 330,720, 280,1720, 280,770, 280,1770, 280,720, 230,820, 280,770, 280,720, 280 }; // Using exact NEC timing    
    irsend.sendSAMSUNG(0x34346897, 32);  //티비 볼륨다운0xE0E0D02F
    delay(1000);
    

}

 

전원이 들어오면 1초마다 티비의 볼륨을 다운시키는 신호를 연속해서 발생하는 간단한 코드입니다.

실제 송신기를 만들어 테스트를 해봤는데 의도한 대로 1초마다 티비의 볼륨이 1칸씩 줄어드는것을 확인하였습니다.

(이 역시 아쉽게도 사진은 남기지 못하였습니다.)

다음 단계는 버튼을 여러개 만들어서 버튼별로 각 신호를 매핑하기만 하면 기능구현 설계는 끝납니다.

이후 기구부 및 하드웨어를 제작하고, 추가로 배터리 광탈을 방지하기 위한 슬립모드 등을 구현하면 됩니다.

 

다만 이 단계까지만 만들어보고 실제 통합리모콘 제작으로 이어지지 못하였습니다.

적외선 신호 방사각이 너무 좁아서 사용할 기기를 향해 송신 방향을 정확히 맞추지 않으면 신호가 인식이 안되더라고요.

신호 방사각이 넓은 IR LED를 써야하나....아니면 트랜지스터를 이용해서 신호를 증폭하면 해결이 되나..여러가지 고민을 하다가..해결해야지...해결해야지...하다가 어느덧 중도한 프로젝트가 되었습니다.

 

게다가 어쩌다보니 송신기와 수신기 프로토타입 만든것을 해체해버린 상태라 다시 하려니 현타가 오는것도 있습니다...

원래 이런건 추진력을 받아서 한번에 가야하는건데..한번 멈추면 다시 하기가 쉽지 않습니다.

근데 다시 한번 도전하고픈 욕심이 요새 생겨서 언젠가 여유가 생기면 다시 추진해보려고 합니다.

그때까지..일단 킵...

 

댓글