This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Read IR Pulse for MSP430G2553

Other Parts Discussed in Thread: MSP430G2553, MSP430G2452

I am currently using MSP430G2553 and Code Composer Studio v6 for my project Remote Controlled Fan. I already done the IR transmitter side but I'm having a problem in the receiver. My codes doesn't read the whole bit frame but it can detect bit "0" and bit "1". Can someone please give some advise how I can resolve my problem. Any help is much appreciated.

  • IR Remote Control is usually one direction only. Why do you need both transmitter and receiver? Are you trying to build two MSP430G2553 based devices that communicate with each other via IR? What IR receiver are you trying to use? (Neither MSP430G2553 nor Code Composer Studio can receive IR.)
  • Hi old_cow_yellow. Basically I am new in using MSP430G MCU the 2452 and 2553 which is in my launch pad. In my Remote Controlled Fan project I used MSP430G2452 for IR LED remote control transmitter and MSP430G2553 for my receiver using ROHM RPM7238-H5 Remote Control Receiver Module that responds to 37.9kHz. I'm using Sharp Protocol for IR communication. My codes for the receiver can only detect bit "0" and bit "1" but I can't figure out how to decode the whole bit frame received. May you please give some advise.
  • You could connect the output pin of RPM7238 to one of the Timer Capture input pins.

    A substantial burst of IR pulses at about 38 kHz will be detected as a single active low pulse that lasts about the duration of the IR burst. The timing is not precise and depends on (a) the strength of the received IR signal, (b) the ambient lights, (c) the immediate past history of received IR -- for about 1 second.

    In order to get reliable results, you should try to detect the the long burst at the beginning of Sharp-code before the 1s and 0s.

    Can you show your code for transmission? How long is the initial long burst? The length of the gap after that long burst? The burst and gap for a 1? The burst and gap for a 0?

    --OCY
  • Initially this is the code for my IR transmission. May you please advise how long is the perfect initial long burst, the gap after long burst, and burst gap for "0" and "1".

    #include <msp430.h>

    //========== Constants Definition ==========//

    #define IR_BIT BIT0
    #define IR_OUT P1DIR |= IR_BIT
    #define IR_ON P1OUT |= IR_BIT
    #define IR_OFF P1OUT &= ~IR_BIT

    #define BTN1 BIT0
    #define BTN1_DIR P2DIR &= ~BTN1
    #define BTN1_REN P2REN |= BTN1
    #define BTN1_OUT P2OUT |= BTN1

    #define BTN2 BIT1
    #define BTN2_DIR P2DIR &= ~BTN2
    #define BTN2_REN P2REN |= BTN2
    #define BTN2_OUT P2OUT |= BTN2

    #define BTN3 BIT2
    #define BTN3_DIR P2DIR &= ~BTN3
    #define BTN3_REN P2REN |= BTN3
    #define BTN3_OUT P2OUT |= BTN3

    #define BTN4 BIT3
    #define BTN4_DIR P2DIR &= ~BTN4
    #define BTN4_REN P2REN |= BTN4
    #define BTN4_OUT P2OUT |= BTN4

    #define BTN5 BIT4
    #define BTN5_DIR P2DIR &= ~BTN5
    #define BTN5_REN P2REN |= BTN5
    #define BTN5_OUT P2OUT |= BTN5

    #define DELAY_IR_ON 9
    #define DELAY_IR_OFF 10

    #define NUMBER_OF_PULSES 12 // to create spaces between bits (12 pulses x 26 microseconds each = ~320 microseconds)

    //========== Functions Declaration ==========//
    void init(void);
    void configClock(void);
    void transmitBit0(void);
    void transmitBit1(void);
    void transmit(unsigned long data_word, unsigned char number_of_bits);
    void delay_ms(unsigned int ms);

    /*
    * main.c
    */

    //====================
    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer

    init();

    while(1)
    {
    if((P2IN & BTN1) == 0)
    {
    unsigned int j;
    for(j=0; j<2; j++)
    {
    transmit(0b010000100100011, 15);
    delay_ms(40);
    }
    while((P2IN & BTN1) == 0);
    }

    if((P2IN & BTN2) == 0)
    {
    unsigned int j;
    for(j=0; j<2; j++)
    {
    transmit(0b010001001100011, 15);
    delay_ms(40);
    }
    while((P2IN & BTN2) == 0);
    }

    if((P2IN & BTN3) == 0)
    {
    unsigned int j;
    for(j=0; j<2; j++)
    {
    transmit(0b010010011100011, 15);
    delay_ms(40);
    }
    while((P2IN & BTN3) == 0);
    }

    if((P2IN & BTN4) == 0)
    {
    unsigned int j;
    for(j=0; j<2; j++)
    {
    transmit(0b010100111100011, 15);
    delay_ms(40);
    }
    while((P2IN & BTN4) == 0);
    }

    if((P2IN & BTN5) == 0)
    {
    unsigned int j;
    for(j=0; j<2; j++)
    {
    transmit(0b011001111100011, 15);
    delay_ms(40);
    }
    while((P2IN & BTN5) == 0);
    }
    }
    }

    //====================
    void init(void)
    {
    IR_OUT, IR_OFF;
    BTN1_DIR, BTN1_REN, BTN1_OUT;
    BTN2_DIR, BTN2_REN, BTN2_OUT;
    BTN3_DIR, BTN3_REN, BTN3_OUT;
    BTN4_DIR, BTN4_REN, BTN4_OUT;
    BTN5_DIR, BTN5_REN, BTN5_OUT;

    configClock();
    }

    //====================
    void configClock(void)
    {
    if(CALBC1_1MHZ == 0xFF) // If calibration constant erased
    {
    while(1); // Do not load up, trap CPU!
    }
    DCOCTL = 0; // Select lowest DCOx and MODx
    BCSCTL1 = CALBC1_1MHZ; // Set range
    DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation
    }

    //====================
    void transmit(unsigned long data_word, unsigned char number_of_bits) // sending out bits, one by one, LSB first, maximum 16 bits (1 word)
    {
    unsigned char i;
    unsigned int mask;
    for(i=0; i<number_of_bits; i++)
    {
    mask = (1 << i);
    if((data_word & mask) == 0) // bit '0'
    {
    transmitBit0();
    }
    else // bit '1'
    {
    transmitBit1();
    }
    }
    }

    //====================
    void transmitBit0(void)
    {
    // bit '0' = 12 pulses (~320 microseconds) + 680 microseconds silent
    unsigned char i;
    for(i=0; i<NUMBER_OF_PULSES; i++)
    {
    IR_ON;
    _delay_cycles(DELAY_IR_ON);
    IR_OFF;
    _delay_cycles(DELAY_IR_OFF);
    }
    _delay_cycles(680);
    }

    //====================
    void transmitBit1(void)
    {
    // bit '1' = 12 pulses (~320 microseconds) + 1,680 microseconds silent
    unsigned char i;
    for(i=0; i<NUMBER_OF_PULSES; i++)
    {
    IR_ON;
    _delay_cycles(DELAY_IR_ON);
    IR_OFF;
    _delay_cycles(DELAY_IR_OFF);
    }
    _delay_cycles(1680);
    }

    //====================
    void delay_ms(unsigned int ms)
    {
    unsigned int i;
    for(i=0; i<ms; i++)
    {
    __delay_cycles(1000);
    }
    }

  • I looked at your transmit code. It appears to me that:
    (a) The sub-carry you generated is 31.2kHz, not 37.8kHz. The consequence is, your 37.8kHz IR-receiver will not be at its peak sensitivity. Thus operating distance will be reduced.
    (b) You did not include a long burst of IR sub-carrier at the beginning of transmission. The consequence is, your receiver AGC will not be adjusted properly and it will be sensitive to noise in the ambient light.
    I do not know the details of Sharp-protocol. It calls for an initial long burst and a gap before you send the first bit of 0 or 1. Please find the specification.
  • I already modified my transmit codes, now I can measure in a oscilloscope 12pulses 38.61KHz subcarrier frequency, 25.9us period of time for each pulse.

    I included a long burst of 346pulses 38.61KHz for 9seconds and no pulses for 4.5seconds before the first bit "0" or bit "1" transmit.

    Do I need to include stop bit after the last bit transmitted?

  • You meant a 9 milliseconds burst and a 4.5 milliseconds gap, not 9 seconds and 4.5 seconds.

    The above is followed by N bursts and N-1 gaps between those bursts. All these N bursts have equal lengths and thus they do not deliver any information. Each of the N-1 gaps has one of two alternative lengths, and thus each gap delivers one bit of information. The last burst is the end of the entire IR-frame, the absence of IR after that can be called an undetermined very long gap, and the last (Nth) burst can be called a stop-bit.

    The receiving side could use Timer Capturing and do the following.

    (1). Capture both leading (high to low) and trailing (low to high) edges of the output of your IR detector. Calculate the time interval from leading to trailing edge. Repeat doing so until you find one that is within (expected initial long burst length) +/- 50%.

    (2). Capture the next leading edge to calculate the time interval from the last trailing edge in step 1. If this is within (expected gap length after initial long burst) +/- 50, continue to step 3. Else go back to step 1.

    (3). Set “# of bits detected so far” to 0 and repeat step 3a below for (N-1) times to collect (N-1) bits.

    (3a). Capture the next leading edge to calculate the time interval from the previous leading edge. Based on this, you may decide a) the current bit is a 1, b) the current bit is a 0, or c) something is wrong and we go back to step 1.

     

  • My apology, yes it is 9 millisecond burst and 4.5 millisecond gap.

    I have the sample codes here for the receiving side. May you please take a look and kindly advise.

    #include <msp430.h>

    //========== Macros & Constants Definition ==========//

    #define LOW 0
    #define HIGH 1
    #define FALSE 0
    #define TRUE 1

    // space/separator time (time_in_low) = ~320 microseconds in theory
    #define TIME_OF_SPACE_MIN 200
    #define TIME_OF_SPACE_MAX 400

    // bit 0 time (time_in_high) = ~680 microseconds in theory
    #define TIME_OF_BIT0_MIN 500
    #define TIME_OF_BIT0_MAX 800

    // bit 1 time (time_in_high) = ~1680 microseconds in theory
    #define TIME_OF_BIT1_MIN 1500
    #define TIME_OF_BIT1_MAX 1800

    #define CYCLE_FOR_20ms 20000
    #define IR_REC_BIT BIT1
    #define IR_REC_IN (P1DIR &= ~IR_REC_BIT)
    #define IR_REC_INPUT_IS_HIGH ((P1IN & IR_REC_BIT) != 0)
    #define TIMER_GETS_OVERFLOW ((TACTL & TAIFG) != 0)
    #define TIMER_NEVER_GETS_OVERFLOW ((TACTL & TAIFG) == 0)
    #define CCR1_COMPARE_MATCHED ((TACCTL1 & CCIFG) != 0)

    #define LED1 BIT0
    #define LED1_DIR P2DIR |= LED1
    #define LED1_ON P2OUT |= LED1
    #define LED1_OFF P2OUT &= ~LED1

    #define LED2 BIT1
    #define LED2_DIR P2DIR |= LED2
    #define LED2_ON P2OUT |= LED2
    #define LED2_OFF P2OUT &= ~LED2

    #define RECEIVE_BIT0 0
    #define RECEIVE_BIT1 1
    #define FUNCTION_1 0b110001001000010
    #define FUNCTION_2 0b110001100100010

    //========== Functions Declaration ==========//

    void init(void);
    void configClock(void);
    void configIO(void);
    void configTimer(void);
    void startTimer(void);
    void stopTimer(void);
    void clearTimer(void);
    unsigned int readTimer(void);
    unsigned char timeOut(void);
    void listen_IR(void);
    void read_IR_DATA(void);
    void Function1(void);
    void Function1_ON(void);
    void Function1_OFF(void);
    void Function2(void);
    void Function2_ON(void);
    void Function2_OFF(void);

    //========== Variables Declaration ==========//

    unsigned char old_ir_receive_input,
    time_out;
    unsigned int overflow_times,
    time_in_low,
    time_in_high;
    unsigned short count1 = 0;
    unsigned short count2 = 0;
    unsigned long data, bitFrame;

    /*
    * main.c
    */

    //==============================

    int main(void)
    {
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer

    init();

    while(1)
    {
    listen_IR();
    }
    }

    //==============================

    void init(void)
    {
    configIO();
    configTimer();
    configClock();

    // get the first status of the IR Receiver's Output
    if(IR_REC_INPUT_IS_HIGH)
    old_ir_receive_input = HIGH;
    else
    old_ir_receive_input = LOW;
    }

    //==============================

    void listen_IR(void)
    {
    if(IR_REC_INPUT_IS_HIGH)
    {
    // yes, being high
    if(old_ir_receive_input == LOW)
    {
    // it was low last time --> there is a rising edge (LOW to HIGH)
    stopTimer();
    time_in_low = readTimer(); // read before clearing
    clearTimer();
    startTimer();

    // check if timer measured a good space/separator (between bits).
    // a space/separator is defined as 320 microseconds in low state of the receiver's output
    if(TIMER_NEVER_GETS_OVERFLOW)
    {
    if((time_in_low > TIME_OF_SPACE_MIN) && (time_in_low < TIME_OF_SPACE_MAX))
    {
    // good space (separator)
    }
    else
    {
    // bad space (separator)
    }
    }
    }
    else
    {
    // it remains high --> there is no rising edge
    // check if CCR1 compare matched --> time out (that means no more bit coming/ or frame ended, the last bit was received is "1")
    if(time_out == FALSE)
    {
    if(timeOut() == TRUE)
    {
    time_out = TRUE;
    stopTimer();
    // bit "1" received...

    }
    }
    }

    // update the variable for next cycle processing
    old_ir_receive_input = HIGH;

    }
    else
    {
    // no, being low
    if(old_ir_receive_input == HIGH)
    {
    // it was high last time --> there is a falling edge (HIGH to LOW)
    stopTimer();
    time_in_high = readTimer(); // read before clearing
    clearTimer();
    startTimer();

    // decode/recognize the bit just received by checking the timer value
    if((time_in_high > TIME_OF_BIT0_MIN) && (time_in_high < TIME_OF_BIT0_MAX))
    {
    // bit "0" received...
    data = (data << 1) | RECEIVE_BIT0;

    }
    else if((time_in_high > TIME_OF_BIT1_MIN) && (time_in_high < TIME_OF_BIT1_MAX))
    {
    // bit "1" received...
    data = (data << 1) | RECEIVE_BIT1;

    }
    else
    {
    bitFrame = data;
    read_IR_DATA();

    }
    }
    else
    {
    // it remains low --> there is no falling edge
    // check if timer gets overflow --> time out (that means a wrong space/separator)
    if(timeOut() == TRUE)
    {
    stopTimer();
    }
    }

    // update the variable for next cycle processing
    old_ir_receive_input = LOW;

    }
    }

    //==============================

    void read_IR_DATA(void)
    {
    switch(bitFrame)
    {
    case FUNCTION_1:
    Function1();
    break;

    case FUNCTION_2:
    Function2();
    break;
    }
    }

    //==============================

    void Function1(void)
    {
    count1 += 1;
    if(count1 == 1)
    {
    Function1_ON();
    }
    else if(count1 == 2)
    {
    count1 = 0;
    Function1_OFF();
    }
    }

    //==============================

    void Function1_ON(void)
    {
    LED1_ON;
    }

    //==============================

    void Function1_OFF(void)
    {
    LED1_OFF;
    }

    //==============================

    void Function2(void)
    {
    count2 += 1;
    if(count2 == 1)
    {
    Function2_ON();
    }
    else if(count2 == 2)
    {
    count2 = 0;
    Function2_OFF();
    }
    }

    //==============================

    void Function2_ON(void)
    {
    LED2_ON;
    }

    //==============================

    void Function2_OFF(void)
    {
    LED2_OFF;
    }

    //==============================

    void startTimer(void)
    {
    TACCTL1 &= ~CCIFG; // clear the time out flag
    TACTL = TASSEL_2 + MC_2; // clock source: SMCLK, mode 2: count up to 0xFFFF
    }

    //==============================

    void stopTimer(void)
    {
    TACTL = 0;
    }

    //==============================

    void clearTimer(void)
    {
    TACTL |= TACLR;
    }

    //==============================

    unsigned int readTimer(void)
    {
    return TAR;
    }

    //==============================

    void configClock(void)
    {
    //1Mhz
    if (CALBC1_1MHZ==0xFF) // If calibration constant erased
    {
    while(1); // do not load, trap CPU!!
    }
    DCOCTL = 0; // Select lowest DCOx and MODx settings
    BCSCTL1 = CALBC1_1MHZ; // Set range
    DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation
    }

    //==============================

    void configIO(void)
    {
    IR_REC_IN;
    LED1_DIR, LED1_OFF;
    LED2_DIR, LED2_OFF;
    }

    //==============================

    void configTimer(void)
    {
    TACCR1 = CYCLE_FOR_20ms;
    }

    //==============================

    unsigned char timeOut(void)
    {
    if(CCR1_COMPARE_MATCHED)
    return TRUE;
    else
    return FALSE;
    }

  • There are many different methods to accomplish the same goal. One method may be better in one aspect, while another method may be better in a different aspect.
    Your code is using a different method than what I proposed. Both methods can work when implemented correctly.
    Your current code seems to call read_IR_DATA() at the wrong spot. You are calling it after the very first falling edge while there is no IR_DATA yet. And you are not calling it after IR_DATA are collected until there happen to be a falling edge not related to the current data.
  • Thank you for your advised. I have already completed my codes and I included what you proposed, it's now working perfectly.

  • You are welcome.

**Attention** This is a public forum