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.

Need urgent help with generating an interrupt using a push button switch

Other Parts Discussed in Thread: MSP430F2274, MSP430F2272

Hi,

I am trying to generate an interrupt using a Push button on Port 2.4 so that my LEDs toggle.

My problem is that my code never seems to be going to ISR . I dont know how to go along from here.

I am very new MSP430 TI so please any help will be greatly appreciated.

 

My code is as follows

#pragma vector = PORT2_VECTOR
__interrupt void Port_2(void){
  _DINT();
  //BUTTON 0
  if (P1IFG & BIT4)
  {
    P4OUT ^=BIT4;
  }
  //BUTTON 1
  else if (P1IFG & BIT5)
  {
    // do something
  }
 
 
  P1IFG = 0;
  _EINT();
}

void main(void){
        P4DIR |= 0x1F;
        P4OUT &= ~0x1F;  //output
    WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
    P2DIR &= ~0x10; //P2.0 as input
    //P2OUT = 0x01;  
    //P2SEL = 0x00;
    P2IE |= 0x10; // No interrupt is pending
    P2IES &= ~0x10; // The PxIFGx flag is set with a high-to-low transition
    P2IFG &= ~0X10; // The interrupt is enabled
        P2REN = 0x10;
    _EINT();
       //__bis_SR_register(GIE);
   
    }

 

I dont seem to know what exactly my code is doing as my code never really goes to ISR.

 

 

  • you should probably start with one of the code examples for your device and tweak the port settings instead of starting from scratch.  www.ti.com/msp430codeexamples

  • Try adding an infinite loop at the end of your code. For example:

      for (;;) ;

     

    Good luck.

     

  • I have used the following on a MSP430F2274 device.  The particular platform had a push button switch on P1.2, not P2.4, so it is not the same but should be similar enough to allow you to migrate to your setup.
    On the platform I tested this on, it had 2 LEDs.  I toggled one from a TimerA interrupt and the other based on a push button event.  The push button is connected to P1.2 to ground, therefore I configured P1.2 to enable the pullup resistor.

    #include  <msp430x22x4.h>

    void main(void)
    {
      WDTCTL = WDTPW + WDTHOLD;             // Stop WDT
      BCSCTL3 |= LFXT1S_2 ;
      P1REN |= 0x04 ;                       // P1.2 pullup enabled
      P1DIR |= 0x03;                        // P1.0 & P1.1 output
      P1DIR &= ~0x04 ;                      // P1.2 input
      P1OUT |= 0x03;                        // P1.0 & P1.1 set to logic high level
      P1IES |= 0x04 ;                       // P1.2 high-to-low transition
      P1IFG |= ~0x04 ;                      // P1.2 clear any pending interrupt
      P1IE |= 0x04 ;                        // P1.2 interrupt enabled
      CCTL0 = CCIE;                         // CCR0 interrupt enabled
      CCR0 = 1000-1;
      TACTL = TASSEL_1 + MC_1;              // ACLK, upmode

      _BIS_SR(LPM3_bits + GIE);             // Enter LPM3 w/ interrupt
    }

    // Timer A0 interrupt service routine
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
      P1OUT ^= 0x01;                        // Toggle P1.0
    }

    #pragma vector=PORT1_VECTOR
    __interrupt void Port1_ISR(void)
    {
      P1OUT ^= 0x02 ;                       // Toggle P1.1
      P1IFG &= ~0x04 ;                      // P1.2 clear any pending interrupt
    }

  • Thank you so much for your inputs ...i think i have got it working.....

    Made slight modifications in my code and it works fine......

    added a little bit of delay for any debounce issues......

  • Can you post your code? I am trying to do something similar... Thanks!

  • Hi Suzanne,

    you can install Grace on your PC (http://focus.ti.com/docs/toolsw/folders/print/grace.html?DCMP=Grace&HQS=Other+EM+grace) and use the Push-Button Debounce  example for reference.

    I've attached a CCS + Grace example to this post. Instructions how to import it can be found here: http://processors.wiki.ti.com/index.php/Project_Sharing

    3731.GRACE Push-Button Debounce sample.zip

    Rgds
    aBUGSworstnightmare

  • Thank you for the code. How would you implement this with my code? I am running other interrupts and functions, so I do not want to interfere with the watchdog timer. I need to put more priority to the P1 Interrupt, so that it can fire more than once. Another issue is I need debounce delay (I am using a keypad; not push button) within the P1 ISR and from googling, putting a delay in an ISR is not good practice....

     

    #include <msp430x22x2.h>
    #include <UF_LCD.h>

    //Pull the four column pins down to 0V. Set those pins as input.
    //Set your row pins as output with initial logic 0 values.
    //Loop through each row, sending a logic 1 to the row and read
    //the column pins. If there is a one in there, then you have a keypress.

    (variables defined here)

    void main(void)
    {
       WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
       BCSCTL1 = CALBC1_8MHZ;      // Set DCO
       DCOCTL = CALDCO_8MHZ;
      
       P1SEL = 0x00;
       P2SEL = 0x00;
       P3SEL = 0x30;   //P3.4,5 = USCI_A0 TXD/RXD
      
       P1DIR = 0x00;   //set columns P1.0-P1.3 as inputs
       P2DIR = 0x39;   //set rows P2.3 and P2.4, P2.0 for # pressed = LED on, and P2.5 Xbee0 DI0 as outputs
       P3DIR = 0xC0;   //set rows P3.6 and P3.7 as outputs
       P4DIR = 0x10;   //set P4.6 as fancontrol: fancontrol=0 (off); fancontrol=1 (on)

       P3OUT = 0x00;   //initialize output port to ground
       P2OUT = 0x00;
      
       __delay_cycles(800000);
       lcd_init();      //get the lcd booted up
      
      
      //RX Parameters
      UCA0CTL1 |= UCSSEL_2;                     //SMCLK
      UCA0BR0 = 0x34;                           //Prescaler = 8MHz/(16 x 9600) = 52 = 0x34
      UCA0BR1 = 0x00;                             //0x34,0x00,0x25 works
      UCA0MCTL = 0x25;                          //UCA0MCTL = UCBRFx | UCBRSx | UCOS16
                                                  //UCBRFx (1st modulation stage) = 0001b
                                                //UCBRSx (2nd modulation stage) = 000b
                                                //UCOS16 (Oversampling mode) = 1b -> Enabled
      UCA0CTL1 &= ~UCSWRST;                     //**Initialize USCI state machine**
      IE2 |= UCA0RXIE;                          //Enable USCI_A0 RX interrupt
     
      //RESET inputTemp()
      P1IE |= 0x02;                             //P1.1 interrupt enabled 
      P1IFG &= ~0x02;                            //P1.1 IFG cleared 
     
      while (1) {
         __bis_SR_register(CPUOFF + GIE);       //Enter LPM0 w/ interrupt
         if (dataReady == 1) {
             displayTemp();
         }
         if (numkeypressed == 0 || reset == 1) {
             inputTemp();
            reset = 0;
            dataReady = 0;
         }
         //numkeypressed = 0;
      }
    }

    int delay () {
        __delay_cycles(100000);
        return 0;
    }

    // Port 1 interrupt service routine 
    #pragma vector=PORT1_VECTOR 
    __interrupt void Port_1(void) 
    {     
        P3OUT |= 0x40;
        delay();
        if ((P1IN & 0x02) != 0) {
        reset = 1;
        numkeypressed = 0;
        }
        P3OUT &= ~0x40;
        P1IFG &= ~0x02;
    }  



    // Receive RXed character
    #pragma vector=USCIAB0RX_VECTOR
    __interrupt void USCI0RX_ISR(void)
    {
         apiframe[j] = UCA0RXBUF;
         if (apiframe[0] == 0x7E) {
             data[j] = apiframe[j];
             if (j == 11) { 
                dh = data[j];
             }
             if (j == 12) { 
                dl = data[j];
                dataReady = 1;
             }
         }
         if (j > sizeof apiframe - 1) {  
              //dataReady = 1;
              j = 0;
              __bic_SR_register_on_exit(CPUOFF);        // Return to active mode
         }
         j++;  
    }

    int displayTemp() {
         dh = data[11];
         dl = data[12];
         adio0 = (dh << 8) | (dl & 0x00FF); //shifts dh to left 8; places 8 zeros before dl; OR dh and dl to make 16-bit word
         v = ((float)adio0 /(float)0x03FF)*1200.0;   //convert reading to millivolts
         f = v / 10.0;   //convert to Fahrenheit.  10mv per Fahrenheit degree
         temp = (int)(f+0.5); // round to nearest int
         digit[0] = (temp / 10) % 10;
         digit[1] = temp % 10;
            if (digit[0] == 0)   {
               n = 3;
               t1 = 0x31;
               t2 = 0x30;
               one = digit[1];
               t3 = (one & 0x0F) | 0x30;
            }
            else if (digit[0] == 1)   {
               n = 3;
               t1 = 0x31;
               t2 = 0x31;
               one = digit[1];
               t3 = (one & 0x0F) | 0x30;
            }
            else {
               n = 2;
               one = digit[1];
               zero = digit[0];
               t1 = (zero & 0x0F) | 0x30;
               t2 = (one & 0x0F) | 0x30;
            }
         lcd_command(0x80);   //cursor back to home
         lcd_char(0x54); //T
         lcd_char(0x45); //E
         lcd_char(0x4D); //M
         lcd_char(0x50); //P
         lcd_char(0xFE); //space
         lcd_char(0x4E); //N
         lcd_char(0x4F); //O
         lcd_char(0x57); //W
         lcd_char(0x3A); //:
         lcd_char(0xFE); //space
            if (n == 2) {
               lcd_char(t1);
               lcd_char(t2);
            }
            else if (n == 3) {
               lcd_char(t1);
               lcd_char(t2);
               lcd_char(t3);
            } 
         lcd_char(0xDF);   //degree
         lcd_char(0x46);   //F for Fahrenheit
         lcd_command(0x80);   //cursor back to home
            return 0;


    int inputTemp() {        
       lcd_command(0xC0); //Move cursor to line 2
       lcd_char(0x45); //E
       lcd_char(0x4E); //N
       lcd_char(0x54); //T
       lcd_char(0x45); //E
       lcd_char(0x52); //R
       lcd_char(0xFE); //space
       lcd_char(0x54); //T
       lcd_char(0x45); //E
       lcd_char(0x4D); //M
       lcd_char(0x50); //P
       lcd_char(0x3A); //:
       lcd_char(0xFE); //space
      
        while (numkeypressed <= 2) {
          for (i=1; i<5; i++) {
             if (i == 1) {
                P2OUT |= 0x10; //ROW1 logic 1
                __delay_cycles(100000);
                if ((P1IN & 0x08) != 0) { //COL1 logic 1; P2IN&0x4 resolves to 0 if the port pin is low, and 4 if the port pin is high
                   lcd_char(0x31);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 1;
                   k++;
                }
                else if ((P1IN & 0x04) != 0) { //COL2 logic 1
                   lcd_char(0x32);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 2;
                   k++;  
                }
                else if ((P1IN & 0x02) != 0) { //COL3 logic 1
                   lcd_char(0x33);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 3;
                   k++;
                }
                else if ((P1IN & 0x00) != 0) { //COL4 logic 1
                   break;
                }
                P2OUT &= ~0x10; //ROW1 logic 0
                __delay_cycles(80000);  
             }
             else if (i == 2) {
                P2OUT |= 0x08; //ROW2 logic 1
                __delay_cycles(100000);
                if ((P1IN & 0x08) != 0) { //COL1 logic 1
                   lcd_char(0x34);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 4;
                   k++;
                }
                else if ((P1IN & 0x04) != 0) { //COL2 logic 1
                   lcd_char(0x35);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 5;
                   k++;
                }
                else if ((P1IN & 0x02) != 0) { //COL3 logic 1
                   lcd_char(0x36);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 6;
                   k++;
                }
                else if ((P1IN & 0x00) != 0) { //COL4 logic 1
                   break;
                }
                P2OUT &= ~0x08; //ROW2 logic 0
                __delay_cycles(80000);     
             }
             else if (i == 3) {
                P3OUT |= 0x80; //ROW3 logic 1
                __delay_cycles(100000);
                if ((P1IN & 0x08) != 0) { //COL1 logic 1
                   lcd_char(0x37);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 7;
                   k++;
                }
                else if ((P1IN & 0x04) != 0) { //COL2 logic 1
                   lcd_char(0x38);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 8;
                   k++;
                }
                else if ((P1IN & 0x02) != 0) { //COL3 logic 1
                   lcd_char(0x39);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 9;
                   k++;
                }
                else if ((P1IN & 0x00) != 0) { //COL4 logic 1
                   break;
                }
                P3OUT &= ~0x80; //ROW3 logic 0  
                __delay_cycles(80000);
             }
             else if (i == 4) {
                P3OUT |= 0x40; //ROW4 logic 1
                __delay_cycles(100000);
                if ((P1IN & 0x08) != 0) { //COL1 logic 1; * pressed?
                   P2OUT &= ~0x20;   //Turn P2.5 OFF (Turn BlackBox fan (linepassing) OFF)
                   P2OUT |= 0x01;   //Turn LED ON (P2.0)
                   __delay_cycles(8000000);
                   P2OUT &= ~0x01;   //LED (P2.0) OFF after 1 sec
                   autoControl = 0xF;
                   numkeypressed = numkeypressed + 1;
                }
                else if ((P1IN & 0x04) != 0) { //COL2 logic 1
                   lcd_char(0x30);
                   numkeypressed = numkeypressed + 1;
                   keypressed[k] = 0;
                   k++;
                }
                /*else if ((P1IN & 0x02) != 0) { //COL3 logic 1; # pressed?
                   P2OUT |= 0x01;   //Turn LED (P2.0)
                   __delay_cycles(1000000);
                   P2OUT &= ~0x01;   //LED (P2.0) OFF after 1 sec
                   reset = 1;
                   numkeypressed = numkeypressed + 2;
                }*/
                else if ((P1IN & 0x00) != 0) { //COL4 logic 1
                   break;
                }
                P3OUT &= ~0x40; //ROW4 logic 0
                __delay_cycles(80000);
             }
          }
          if (numkeypressed == 2) {
             lcd_char(0xDF); //degree
             lcd_char(0x46);   //F for Fahrenheit
             break;
             }     
       }
       //dataReady = 0;
       return 0;
    }
      /* //numkeypressed = 0;
       //lcd_command(0x80); //place cursor back at home of line 1
       //P3OUT = 0x00;   //set to logic 0
       //P2OUT &= ~0x18;   //set to logic 0
       //return 0;
    }
       //displayTemp();
       tI = 10 * keypressed[0];
       tempInput = tI + keypressed[1];
       if (autoControl == 0xF && (temp > (tempInput + 1))) {
               P2OUT |= 0x21;   //Turn LED (P2.0) & (P2.5)BlackBox fan (linepassing) ON
            __delay_cycles(1000000);
            P2OUT &= ~0x01;   //LED (P2.0) OFF after 1 sec
       }
       else if (autoControl == 0x8 && (temp < (tempInput - 1))) {
               P2OUT &= ~0x20;   //Turn P2.5 OFF (Turn BlackBox fan (linepassing) OFF)
            P2OUT |= 0x01;   //Turn LED ON (P2.0)
            __delay_cycles(1000000);
            P2OUT &= ~0x01;   //LED (P2.0) OFF after 1 sec
       }
       return 0;       
    }*/

  • Suzanne Delica said:
    I need to put more priority to the P1 Interrupt, so that it can fire more than once.

    interrupt priorities are fixed in the MSP. Look at the interrupt vector table. AFAIK, the higher in memory the vector is, the higher priority it has.
    However, once an ISR is entered, GIE is cleared by the system (it will be restored together with the saved status register from stack on ISR exit) and no other ISR can interrupt it while the ISR is running. THis is why you should seek to finish your ISR job as fast a spossible.

    One exception are the NMIs, here a system NMI can interrupt a user NMI, and any NMI can interrupt an normal ISR. And a reset interrupts them all - finally :)

    Suzanne Delica said:
    Another issue is I need debounce delay (I am using a keypad; not push button) within the P1 ISR and from googling, putting a delay in an ISR is not good practice...

    Google is your friend := Indeed, doing a busy-waiting in an ISR renders the whole existence of ISRs useless. ISRs are meant to be entered and exited as fast as possible.

    How to do a debounce delay (one possible solution): In the port ISR, start a timer that expires after the desired debounce time. then disable the port interrupt. In the timer expiration ISR, you check the current pin status and re-enable the port interrupt. There are other threads in thsi forum discussing this (including code snippets)

     

  • For anyone else who finds this thread and is interfacing a Xbee with MSP430F2272

    The problems I faced were

    1. Choosing correct Baud Rate parameters to sync MSP430 RX UART and Xbee DOUT 14-byte API Frame

    2. Choosing the proper interrupts to RX API Frame from Xbee and implement high priority Reset feature (using a keypad; not a push button) accounting for debouncing

     

    I am skeptical about:

    1. Continuous synchronization of MSP430 UART and Xbee DOUT; if error in "Temp Now" occurs must Reset using keypad or remove battery and start over

     

    Resources:

    1. Knowing interrupt priorities is very important. Choose Timer_B instead of Timer_A because it has priority over UART RX Interrupt. This will ensure Reset occurs when prompted. The way my code is set up, Timer_A interrupt never fired because UART RX has priority

    2. See these websites for extra info:

    http://cnx.org/content/m12321/latest/

    http://egarante.posterous.com/?tag=msp430

     

    This is the best code I could come up:

    #include <msp430x22x2.h>
    #include <UF_LCD.h>

    //define variables

    void main(void)
    {
       WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
       BCSCTL1 = CALBC1_8MHZ;      // Set DCO
       DCOCTL = CALDCO_8MHZ;
      
       P1SEL = 0x00;
       P2SEL = 0x00;
       P3SEL = 0x30;   //P3.4,5 = USCI_A0 TXD/RXD
      
       P1DIR = 0x00;   //set columns P1.0-P1.3 as inputs
       P2DIR = 0x39;   //set rows P2.3 and P2.4, P2.0 for # pressed = LED on, and P2.5 Xbee0 DI0 as outputs
       P3DIR = 0xC0;   //set rows P3.6 and P3.7 as outputs
       P4DIR = 0x10;   //set P4.6 as fancontrol: fancontrol=0 (off); fancontrol=1 (on)

       P3OUT = 0x00;   //initialize output port to ground
       P2OUT = 0x00;
      
       __delay_cycles(800000);  //100ms delay
       lcd_init();      //get the lcd booted up
      
      
      //RX Parameters
      UCA0CTL1 |= UCSSEL_2;                     //SMCLK
      UCA0BR0 = 0x34;                           //Prescaler = 8MHz/(16 x 9600) = 52 = 0x34
      UCA0BR1 = 0x00;                             //0x34,0x00,0x25 works
      UCA0MCTL = 0x25;                          //UCA0MCTL = UCBRFx | UCBRSx | UCOS16
                                                  //UCBRFx (1st modulation stage) = 0001b
                                                //UCBRSx (2nd modulation stage) = 000b
                                                //UCOS16 (Oversampling mode) = 1b -> Enabled
      UCA0CTL1 &= ~UCSWRST;                     //**Initialize USCI state machine**
      IE2 |= UCA0RXIE;                          //Enable USCI_A0 RX interrupt
     
      //RESET inputTemp()
      TBCCTL0 |= CCIE;                             //TACCR0 interrupt enabled
      TBCCR0 = 60000;
      TBCTL = TBSSEL_2 + MC_1 + ID_3;           //SMCLK/8, upmode   
     
      while (1) {
         __bis_SR_register(CPUOFF + GIE);       //Enter LPM0 w/ interrupt
        
        if (dataReady == 1) {
             displayTemp();
         }
        
         if (numkeypressed == 0 && dataReady == 1 && reset == 0) {
             inputTemp();
            dataReady = 0;
         }
        
         if (reset == 1) {
             lcd_command(0x01);
             numkeypressed = 0;
             reset = 0;
         }
      }
    }


    // Timer B0 interrupt service routine
    #pragma vector=TIMERB0_VECTOR
    __interrupt void Timer_B (void)
    {
        P3OUT &= ~0xFF;
        P3OUT |= 0x40;
        if ((P1IN & 0x02) != 0) {
            reset = 1;
        }
        P3OUT &= ~0x40;
        __bic_SR_register_on_exit(CPUOFF);    // Return to active mode
    }


    // Receive RXed character
    #pragma vector=USCIAB0RX_VECTOR
    __interrupt void USCI0RX_ISR(void)
    {
         apiframe[j] = UCA0RXBUF;
         if (apiframe[0] == 0x7E) {
             data[j] = apiframe[j];
             if (j == 11) { 
                dh = data[j];
             }
             if (j == 12) { 
                dl = data[j];
                dataReady = 1;
             }
         }
         if (j > sizeof apiframe - 1) {  
              //dataReady = 1;
              j = 0;
              __bic_SR_register_on_exit(CPUOFF);        //Return to active mode
         }
         j++;  
    }

    int displayTemp() {

    //code to do math to byte 11 and byte 12 of API Frame (RX from Xbee) and display "Temp Now" on LCD

    return 0;
    }

    int inputTemp() {

         //code to output "Enter Temp" to LCD and poll keypad for 2-digit temp entered by user

    return 0;

    }

     

  • Suzanne Delica said:
    The way my code is set up, Timer_A interrupt never fired because UART RX has priority

    Aehm, well, if there is never a delay between two RX interrupts where the TimerA interrupt would kick in, then there's something wrong with your RX ISR.

    Not that once an ISR is started, it won't be interrupted by a higher priority interrupt (except for NMI or RESET). So the very moment your RX ISR returns and there is only a single clock cycle without the next RX interrupt (which should be always the case, else you're running close to a regular RX overflow), the timer ISR will kick in instead. The maximum latency would be the execution time of your RX ISR. Which should be much shorter than one byte transmission length.

    Yet I don't see why you're seeing this problem, since you're not using any while/for loops in your ISRs.

    Transmission of a byte takes 1ms, so your RX isr is executed only every 1ms (which is 8.320 clock cycles, exactly). Subtract 8µs to wakeup from lpm and another 8µs for the same for the tiemr ISR, then a lockup should only occur if our RX ISR requires more than 7300 clock cycles. Which apparently isn't the case.

    So I really don't know why your timerA ISR wasn't executed. Maybe a glitch with initializing the timer? Or there's something wrong with the initialization of the USART, so certain interrupt conditions don't go away causing an endless ISR loop. But then, you simple read UCA0RXBUF, which should clear all interrupt flags.
    It's really a mystery that you're seeing problems.

     

     

  • Hello Jens-Michael,

     

     

    I ended up going back to Timer_A interrupt. I do not know why it wouldnt work the first time, but now when I press the button to "reset", i get it to work. However, getting my RXed frame from the Xbee is not always synchronized. Can I please have your help! For the Xbee I have 8-N-1, no flow control, transmitting temperature every 2 seconds. Thanks for any help :)

     

    void main(void)
    {
       WDTCTL = WDTPW + WDTHOLD;   // Stop WDT
       BCSCTL1 = CALBC1_8MHZ;      // Set DCO
       DCOCTL = CALDCO_8MHZ;
      
       P1SEL = 0x00;
       P2SEL = 0x00;
       P3SEL = 0x30;   //P3.4,5 = USCI_A0 TXD/RXD
      
       P1DIR = 0x00;   //set columns P1.0-P1.3 as inputs
       P2DIR = 0x39;   //set rows P2.3 and P2.4, P2.0 for # pressed = LED on, and P2.5 Xbee0 DI0 as outputs
       P3DIR = 0xC0;   //set rows P3.6 and P3.7 as outputs
       P4DIR = 0x10;   //set P4.6 as fancontrol: fancontrol=0 (off); fancontrol=1 (on)

       P3OUT = 0x00;   //initialize output port to ground
       P2OUT = 0x00;
      
       __delay_cycles(800000);  //100ms delay
       lcd_init();      //get the lcd booted up
      
      
      //RX Parameters
      UCA0CTL1 |= UCSSEL_2;                     //SMCLK
      UCA0BR0 = 0x34;                           //Prescaler = 8MHz/(16 x 9600) = 52 = 0x34
      UCA0BR1 = 0x00;                             //0x34,0x00,0x25 works
      UCA0MCTL = 0x25;                          //UCA0MCTL = UCBRFx | UCBRSx | UCOS16
                                                  //UCBRFx (1st modulation stage) = 0001b
                                                //UCBRSx (2nd modulation stage) = 000b
                                                //UCOS16 (Oversampling mode) = 1b -> Enabled
      UCA0CTL1 &= ~UCSWRST;                     //**Initialize USCI state machine**
      IE2 |= UCA0RXIE;                          //Enable USCI_A0 RX interrupt
     
      //RESET inputTemp()
      //P1IE |= 0x20;
      //P1IFG &= ~0x20;
      TACCTL0 |= CCIE;                             //TACCR0 interrupt enabled
      TACCR0 = 60000;
      TACTL = TASSEL_2 + MC_1 + ID_3;           //SMCLK/8, upmode   
     
      __bis_SR_register(CPUOFF + GIE);       //Enter LPM0 w/ interrupt
       
      while (1) {
        while (dataReady == 0);
        if (dataReady == 1) {
             displayTemp();
         }
        
         if (numkeypressed == 0 && dataReady == 1 && reset == 0) {
             inputTemp();
            //dataReady = 0;
         }
        
         if (reset == 1) {
             lcd_command(0x01);
             numkeypressed = 0;
             reset = 0;
         }
         //numkeypressed = 0;
      }
    }

    // Timer A0 interrupt service routine
    #pragma vector=TIMERA0_VECTOR
    __interrupt void Timer_A (void)
    {
        P3OUT &= ~0xFF;
        P3OUT |= 0x40;
        if ((P1IN & 0x02) != 0) {
            reset = 1;
        }
        P3OUT &= ~0x40;
        __bic_SR_register_on_exit(CPUOFF);    // Return to active mode
     
    }

     

    // Receive RXed character
    #pragma vector=USCIAB0RX_VECTOR
    __interrupt void USCI0RX_ISR(void)
    {
         apiframe[j] = UCA0RXBUF;
         if (apiframe[0] == 0x7E) {
             data[j] = apiframe[j];
             if (j == 11) { 
                dh = data[j];
             }
             if (j == 12) { 
                dl = data[j];
                dataReady = 1;
             }
         }
         if (j > sizeof apiframe - 1) {  
              dataReady = 0;
              j = 0;
              __bic_SR_register_on_exit(CPUOFF);        //Return to active mode
         }
         j++;  
    }

  • Suzanne Delica said:
    getting my RXed frame from the Xbee is not always synchronized.

    Your code just receives sizeof apiframe bytes and then wakes the main thread.

    So if you don't get a byte because of a parity error or a framing error or whatever, it will wait for the firs tbyte of the next frame, which in turn brings your whole mechanism out of sync.

    What you need is a timeout. Whenever you get a byte, you reset a timer, when the timer triggers before you got all 14 bytes, you know you missed a byte and need to reset your receive counter. That will bring you back in sync.

    You cannot assume a 100% reliable connection, so it's always possible that you miss a byte. Maybe once in a million, but possible, so you HAVE to add some sort of error detection and resyncing.

    The other question is, why does it happen for you so often. Maybe the timing of the UART is incorrect, maybe the hardware is faulty (or at least fragile).

    The UART configuration (baudrate etc.) looks okay on first glance. The clock config should be okay too (calibrated values). There is, however, an inherent problem in teh DCO that won't allow you a 100% exact destination frequency. Between two direct possible DCO outputs, there are only 32 interpolated frequencies possible. And the number of discrete frequencies output by the DCO is also limited. Also, the DCO drifts with temperature (and more than jsut a bit). So the clock frequency might be a bit off of 8MHz. Then your sensor might be off too and maybe to the other side. This can result in sometimes a too big difference when the DCo modulation and drift and the moment of the transmission make an unlucky marriage, resulting in a framing error and a lost byte (which you could detect when enabling the frame error interrupt and checking it).

    If you can live with sometimes not gettign a valid data frame, then a timeout function is by far the easiest and cheapest solution. Else I'd suggest adding a crystal for better timing. Either a watch crystal and a software FLL (or hardware, depending on the MSP used) or a high-speed crystal which of course consumes more power.

  • These are the changes I ended up making. By verifying the checksum, I was able to limit errors and ensure my project ran smoothly (doesn't mean unsynchronization didnt occur; i just disregarded the apiframe if it did)

     

    Thank for all your help :)

     

    ---CODE---


    // Receive RXed character
    #pragma vector=USCIAB0RX_VECTOR
    __interrupt void USCI0RX_ISR(void)
    {
         apiframe[j] = UCA0RXBUF;
         if (apiframe[0] == 0x7E) {
             data[j] = apiframe[j];
             if (j == 13) {
                 for (count = 3; count < 13; count ++) {
                     checksum += data[count];
                 }
                 verify = 0xFF - (checksum & 0xFF);
                 if (verify == data[13]) {      
                    dh = data[11];
                    dl = data[12];
                    dataReady = 1;
                 }
                else if (verify != data[13]) {
                    dataReady = 0;
                     j = 0;
                     count = 0;
                     checksum = 0;
                     verify = 0;
                }
             }
         }
         if (j > sizeof apiframe - 1) {   
              dataReady = 0;
              j = 0;
              count = 0;
              checksum = 0;
              verify = 0;
             // __bic_SR_register_on_exit(CPUOFF);        //Return to active mode
         }
         j++;
         __bic_SR_register_on_exit(CPUOFF);        //Return to active mode  
    }

  • Suzanne Delica said:
    I was able to limit errors and ensure my project ran smoothly (doesn't mean unsynchronization didnt occur; i just disregarded the apiframe if it did)

    I wonder how you re-sync when you detected a bad frame. If you miss a byte in a frame, you'll only see that it was a bad frame after receiving the first byte of the next one. But then you're out of sync still. Unless you missed a comple framesize of bytes (then you're in sync again, but this may take a longer time if you're experiencing byte loss less frequently)

    if you know htat your frame will take only 14 ms (14bvyte @9600bd) and th enext will follow 986ms later, a timeout is the best to get back in sync as fast a s possible.

    Suzanne Delica said:
    Thank for all your help :)

    You're welcome.

**Attention** This is a public forum