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.

Code for IR Receiver Tsop1138 38khz doesn´t work

Other Parts Discussed in Thread: MSP430G2553

Hello.

Iám trying to write a code for implement a IR 38KHZ receiver using Tsop1138. Te objetive of this project is to control a ceiling lamp which has a fan. That ceiling can be controlled by its remote control but i want to control it with a circuit made by me. At start i used a protoboard with the tsop1138 connect with a 100Ohm resistor and 4,7uf capacitor and the "out" line this tsop connect to P1.2(TimerA input) of MSP430 launch kit with msp430g2553. I use the TimerA in continue mode. The tsop1138 outputs signal at hight and low it when there is a change in signal.

The code doesn´t work correctly becouse it doesn´t detect correctly the 3 signal changes of a bit(low,high and low). It detects low,hight and again "hight" which is wrong.

Bit0:

---------            ------------------------

         |           |                       |

         |           |                       |

         ------------                        --------------

       <--550us-><---1600us---->


Bit1:

---------                     --------------

         |                    |             |

         |                    |             |

         ---------------------               --------------

       <----1600us-----><--550us->

Frame bits:

key 0:
01010101 01010101 00001111
key 1:
01010101 01010101 11110011
key 2:
01010101 01010101 11001111
key 3:
01010101 01010101 00111111
Light on/off key:
01010101 01010101 11000000
speed-up key:
01010101 01010101 11111100
speed-down key:
01010101 01010101 00001100

My code:

#include <msp430.h>

unsigned int tbajada0,tsubida0,tbajada1;
unsigned int tbajo,tciclo,talto;
unsigned int numbitscab,numbitscmd,numflancoscap;
unsigned int iniciosenal,iniciotrama;
unsigned char bitscab,bitscmd;

int main(void)
{

  WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer

// P1SEL |= BIT0;
  P1DIR |= BIT0+BIT6;                            // P1.0/LED Output
  P1OUT &= ~(BIT0+BIT6);                           // LED off
  if (CALBC1_8MHZ==0xFF)                    // If calibration constant erased
  {                                            
    while(1);                               // do not load, trap CPU!!    
  }
  DCOCTL = 0;                               // Select lowest DCOx and MODx settings
  BCSCTL1 = CALBC1_8MHZ;                    // Set DCO to 8MHz
  DCOCTL = CALDCO_8MHZ;

  // Configure Port Pins
  P1DIR &= ~BIT2;                           // P1.1/TA0.1 Input Capture
  P1SEL |= BIT2;                            // TA0.1 option select


  // Configure the TA0CCR1 to do input capture
  TA0CCTL1 = CAP + CM_3 + CCIE + SCS + CCIS_0;
                                            // TA0CCR1 Capture mode; CCI1A; Both
                                            // Rising and Falling Edge; interrupt enable
  TA0CTL |= TASSEL_2 +ID_3+ MC_2 + TACLR;        // SMCLK, Cont Mode; start timer

  // Variable Initialization
  numbitscab=0;
  numbitscmd=0;
  numflancoscap=0;
  bitscab=0;
  bitscmd=0;
  iniciosenal=0;//cambio actual
  iniciotrama=1;
  tciclo=0;
  tbajo=0;
  talto=0;
  tbajada0=0;
  tsubida0=0;
  tbajada1=0;

  while(1)
  {
      __bis_SR_register(LPM0_bits + GIE);   // Enter LPM0
     // __bis_SR_register(GIE);
      __no_operation();                     // For debugger
      // On exiting LPM0
      if (TA0CCTL1 & COV){                  // Check for Capture Overflow
          TA0CCTL1 |=COV;                    //para salir de overflow

      }
      //aqui calculamos los tiempos en alto,bajo y del periodo
      if(numflancoscap==3){//si capturado un bit
          tbajo=tsubida0-tbajada0;
          talto=tbajada1-tsubida0;
          tciclo=tbajo+talto;
          if(tciclo>=17000 && tciclo<=18000){//si duración correcta del bit
              if(tbajo>=4400 && tbajo<=4800){
                  if(talto>=12000 && talto<=14000){
                      //se trata de un 0
                      if(numbitscab<16){
                          bitscab=bitscab<<1;
                          numbitscab++;
                      }
                      else{
                          bitscmd=bitscmd<<1;
                          numbitscmd++;
                      }
                  }
              }
              if(tbajo>=12000 && tbajo<=18000){
                  if(talto>=4000 && talto<=4800){
                      //se trata de un 1
                      if(numbitscab<15){
                          bitscab=bitscab<<1;
                          bitscab|=0x0001;
                          numbitscab++;
                      }
                        else{
                            bitscmd=bitscmd<<1;
                            bitscmd|=0x0001;
                            numbitscmd++;
                        }
                  }
              }
          }
          if(numbitscab==16 && numbitscmd==8){//si trama leida
              //P1OUT|=BIT0+BIT6;
              iniciosenal=1;
              iniciotrama=1;//inicio nueva trama
          }
          numflancoscap=0;
      }

  }
}

// TA0_A1 Interrupt vector
#pragma vector = TIMER0_A1_VECTOR
__interrupt void TIMER0_A1_ISR (void)
{

  switch(__even_in_range(TA0IV,0x0A))
  {
      case  TA0IV_NONE: break;              // Vector  0:  No interrupt
      case  TA0IV_TACCR1:                   // Vector  2:  TACCR1 CCIFG
        if (TA0CCTL1 & CCI)                 // flanco subida
        {
            P1OUT |=BIT0;
            if(iniciosenal){//si puesta a nivel alto de la salida receptor IR.
                iniciosenal=0;//desmarcamos el inicio de señal
            }
            else{//si subida valida capturamos contador
                tsubida0=TA0CCR1;
                numflancoscap++;
                TA0CCR1=0;
            }
        }
        else //flanco bajada
        {
            P1OUT |=BIT6;
            if(iniciotrama){//si primera bajada de la trama capturamos contador
                tbajada0=0;
                numflancoscap++;
                iniciotrama=0;
                TA0CCR1=0;
            }
            else{//bajada intermedia,pertenece al final de un ciclo y al principio del otro
                tbajada1=TA0CCR1;
                tbajada0=0;
                numflancoscap++;
                TA0CCR1=0;
            }
        }
        __bic_SR_register_on_exit(LPM0_bits + GIE);
        break;
      case TA0IV_TACCR2: break;             // Vector  4:  TACCR2 CCIFG
      case TA0IV_6: break;                  // Vector  6:  Reserved CCIFG
      case TA0IV_8: break;                  // Vector  8:  Reserved CCIFG
      case TA0IV_TAIFG: break;              // Vector 10:  TAIFG
      default:     break;

  }

}

Please help me if you can.

Thank you.

  • Enrique Fernandez Garcia said:
    ...

    Bit0:

    ---------            ------------------------

             |           |                       |

             |           |                       |

             ------------                        --------------

           <--550us-><---1600us---->


    Bit1:

    ---------                     --------------

             |                    |             |

             |                    |             |

             ---------------------               --------------

           <----1600us-----><--550us->

    Frame bits:

    key 0:
    01010101 01010101 00001111
    key 1:
    01010101 01010101 11110011
    key 2:
    01010101 01010101 11001111
    key 3:
    01010101 01010101 00111111
    Light on/off key:
    01010101 01010101 11000000
    speed-up key:
    01010101 01010101 11111100
    speed-down key:
    01010101 01010101 00001100

    ...

    How do you know the above is correct information? Is there any IR signal before these 24 bits? Do you have an oscilloscope so that you can verify this by probing P1.2 while pressing one of keys on the remote control?

  • I know that information is correct, because i´ve measured the signal  connected it into  pc by "line-in" audio and using the Goldwave application. I´ve could measured the signal timming and view the frame bits.

    In the top image you can see the signal i captured. At the begining, the signal is  in hight level, when a key is pressed, the signal generated has 16 bits fixed of address and then 8 bits which depend of the command in question. At end of signal you also can see a long pulse which consist in a reestablishment of the signal to  high level.

    Note: When a key is pressed during a time, the frame bits is send repeatedly.

    I haven´t got a scilloscope so i cant use it for getting measures.

    The problem basically is that  the ISR of TimerA  detects 3 edges: first down,first up and then "again another up". That is wrong because the ISR should detect the 24 bits and for each one of them three correct edges " down, up and again down", that is to say a bit cycle.


    I wait your responde.

    Thank you very much.

  • I think the logical flaw here is that a bit is actually 2 edges, not 3. True, you have to wait for the 3rd edge to know how long the bit was, but by then the next bit has already started.

    In coding terms, this means that after computing "talto", you should set "tbajada0=tbajada1", to show that the end of the previous bit is the beginning of the next one. Of course, you should also Not set tbajada0=0 elsewhere. and numflancoscap should reset to 1, not 0, between bits.

    Unsolicited notes on things that haven't caused you trouble yet but will eventually:

    1) The variables you're sharing between the ISR and main (tbajada0, e.g.) should be declared "volatile".

    2) Don't set TA0CCR1=0. It doesn't help anything, and could conceivably overwrite a valid (new) value.

  • I am working on project for audio preamp control with MSP430x2xx. There is IR / KBD input on one (ADC) line with possibility of IR / KBD learning, and it will work (almost) wit any remote.

    Timer is in continuous up mode, and when IRK signal is changing (port interrupt), last up/down interval (calculated by difference in timer values) is stored. When all data are stored, command is decoded. If measured up / down interval is too long (timeout), than this is command begging / ending.

  • Hello.

    First thank you very much for your answer.

    Relative what you say  me about my code, already I have contemplate what you say. A bit consist in three edges (down,up and down). When the code reads the third edge (down) does this:

    tbajada1=TA0CCR1; //takes  timer value
    tbajada0=0; //start of next "bit"
    numflancoscap++;//number of captured edges. three for present "bit". The software will detect numflancoscap==3, will do measures of time and will set numflancoscap=0 because is the begining of the next bit.
    TA0CCR1=0;//value of timer at beginning  of bit.

    IR -----------------                     ---------------------
                               |                    |                           |
                               ----------------                            ------------
    Timer                0     ...      ta0ccr1                ta0ccr1
                                                taken1                 taken2/
                                                                            ta0ccr1=0

    Times    tbajada0=0      tsubida1=             tbajada1=
                                               ta0ccr1                  ta0ccr1/
                                                                            tbajada0=0 (is not neccesary) /
                                                                            ta0ccr1=0 (to next measure)

    Software    tsubida1-tabajada0                   tbajada1-tsubida0

    I decided write TA0CCR1=0 at end of "bit" because if the timer overflows it will be wrong the time captured.

    However I´m going to review the code and try to check what you say.

    Thank you.

    I´ll tell you soon.

  • Enrique Fernandez Garcia said:

    ... decided write TA0CCR1=0 at end of "bit" because if the timer overflows it will be wrong the time captured. ...

    Wrong register! You menat TA0R.

  • I've written this code any number of times, and my fingertips keep typing:

        new = CCR;

        diff = new - old;

        old = new;

    I think it's best to think of the decoding as a continuous process (2 edges/bit) rather than a series of discrete events (3 edges/bit) since it's easier for the code to keep its head straight.

    OCY appears to have figured out what you were after with TACCR=0, but I don't recommend setting TA0R=0 either, since at that point the software, not the hardware, is doing the timing. 16-bit (unsigned) subtract will do what you want over a TA0R overflow. You will want to guard against TA0R wrapping completely (N back around to N) using either TAIFG or a second CCR; in my experience I usually wanted a timeout that was much shorter than that anyway.

  • I implemented in a slightly referent way to decode your IR remote. I think it should work very reliably. But I do not have your IR remote or your IR receiver. I wonder if you could test it for me.

    #include <msp430g2553.h>
    
    volatile int id;
    volatile char code, bits, low, high;
    
    void show_result (void)
    {
      // *** put a breakpoint here to inspect ***
      //  id should be 0x5555
      //  key should be 0x0F, 0xF3, 0xCF, 0x3F, 0xC0, 0xFC, or 0x0C
      __no_operation();
      // let code continue after inspecting
    }
    
    int main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;
    
      if (CALBC1_8MHZ==0xFF)
      {                                            
        while(1);
      }
      BCSCTL1 = CALBC1_8MHZ;
      DCOCTL = CALDCO_8MHZ;
    
      P1DIR &= ~BIT2;
      P1SEL |= BIT2;
    
      TA0CCTL1 = CAP | CM_3 | CCIE | SCS | CCIS_0;
      
      while (1)
      {
         bits = 0;  
         low = 0;
         TA0CTL = TASSEL_2 | ID_3 | MC_2 | TACLR;
    
         __bis_SR_register(LPM0_bits | GIE);
    
         show_result();
      }
    }
    
    // TA0_A1 Interrupt vector
    #pragma vector = TIMER0_A1_VECTOR
    __interrupt void TIMER0_A1_ISR (void)
    {
      switch(__even_in_range(TA0IV,0x0A))
      {
          case  TA0IV_NONE: break;              // Vector  0:  No interrupt
          case  TA0IV_TACCR1:                   // Vector  2:  TACCR1 CCIFG
            TA0CTL |= TACLR;
            if (TA0CTL&TAIFG)
            {
              TA0CTL &= ~TAIFG;
              TA0CCR1 = 9999;
            }
            if (TA0CCTL1&CCI)
            { // begin examine duration of low
              if ((TA0CCR1<270)||(TA0CCR1>3200))
                { bits = 0; low = 0; }
              else if (TA0CCR1>818)
                { low = 'L'; }
              else
                { low = 'S'; }
            } // end examine duration of low
            else
            { // begin examine duration of high
              if ((TA0CCR1<270)||(TA0CCR1>3200))
                { bits = 0; low = 0; }
              else if (TA0CCR1>818)
                { high = 'L'; }
              else
                { high = 'S'; }
              // end examine duration of high
              if (((low=='L')&&(high=='S'))||((low=='S')&&(high=='L')))
              { // begin good low-high combination
                low = 0; // already checked, discard it
                id <<= 1;
                if (code & 0x80)
                  { id++; }
                code <<= 1;
                if (high=='S')
                  { code += 1; }
                bits++;
                if (bits==24)
                {
                  __bic_SR_register_on_exit(LPM0_bits + GIE);
                  TA0CTL = 0;
                }
              } // end good low-high combination
              else // bad low-high combination
              { bits = 0; low = 0; }
            }
            break;
          case TA0IV_TACCR2: break;             // Vector  4:  TACCR2 CCIFG
          case TA0IV_6: break;                  // Vector  6:  Reserved CCIFG
          case TA0IV_8: break;                  // Vector  8:  Reserved CCIFG
          case TA0IV_TAIFG: break;              // Vector 10:  TAIFG
      }
    }
    

    If you do so, please set up a single break-point inside the void show_result (void) {...} (do not single-step, do not set break-point elsewhere). Every time a complete 24-bit code is received, this break-point will get hit and you can examine the 16-bit id and the 8-bit key.

    Kindly inform me if it works.

**Attention** This is a public forum