Jump to content
43oh

Recommended Posts

so, i have a fairly basic question, and i'm sure the answer to this question already exists somewhere I just wasn't able to find it. Basically, I need to figure out how to add a button interrupt into my very basic code. mainly, I'm gonna be running a prototype off a launchpad that's basically hooked up to the usb port the entire time, and I just need to add one button press to make it start, as opposed to starting as soon as it's plugged in which is the case now. anyone got any quick easy resources or just a template I could look over? Thanks.

 

Chris

Link to post
Share on other sites

//******************************************************************************
//  MSP430G2xx1 Demo - P1 Interrupt from LPM4 with Internal Pull-up
//
//  Description: A hi/low transition on P1.4 will trigger P1_ISR which,
//  toggles P1.0. Normal mode is LPM4 ~ 0.1uA.
//  Internal pullup enabled on P1.4.
//  ACLK = n/a, MCLK = SMCLK = default DCO
//
//               MSP430G2xx1
//            -----------------
//        /|\|              XIN|-
//         | |                 |
//         --|RST          XOUT|-
//     /|\   |      R          |
//      --o--| P1.4-o      P1.0|-->LED
//     \|/
//
//  D. Dang
//  Texas Instruments Inc.
//  October 2010
//  Built with CCS Version 4.2.0 and IAR Embedded Workbench Version: 5.10
//******************************************************************************

#include  

void main(void)
{
 WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer
 P1DIR = 0x01;                             // P1.0 output, else input
 P1OUT =  0x10;                            // P1.4 set, else reset
 P1REN |= 0x10;                            // P1.4 pullup
 P1IE |= 0x10;                             // P1.4 interrupt enabled
 P1IES |= 0x10;                            // P1.4 Hi/lo edge
 P1IFG &= ~0x10;                           // P1.4 IFG cleared

 _BIS_SR(LPM4_bits + GIE);                 // Enter LPM4 w/interrupt
}

// Port 1 interrupt service routine
#pragma vector=PORT1_VECTOR
__interrupt void Port_1(void)
{
 P1OUT ^= 0x01;                            // P1.0 = toggle
 P1IFG &= ~0x10;                           // P1.4 IFG cleared
}

 

Change it to use P1.2...

 

When you look at the TI page for any of the chips there's usually example code listed near half/bottom of the page.

Link to post
Share on other sites

The polling method given above would work, and although as you are running connected to USB power management isn't much of an issue. Personally though I would go into low power mode and activate the CPU/Timers etc on the interrupt. You say you want it to start on the button press so there isn't any need for timers or anything so LPM4 is ideal.

 

Basically in your main() after initialising the interrupts etc run __bis_SR_register(LPM4_bits + GIE); This will turn off the CPU and all timers. As the CPU is turned off your program execution will stop there. Then in your interrupt routine run __bic_SR_register_on_exit(LPM4_bits);. This means that when the interrupt has finished the CPU and any configured timers will be enabled. Program execution will continue in your main() routine on the line after the __bis_SR_register.

 

As I say, for this application this is overkill.. but I think it is a good mindset to get into. Also realising you can pause execution in your code and activate it with interrupts is a handy skill to have under your belt.

 

**Edit**

Lol.. while typing this I see SugarAddict has posted some code using _BIS_SR()..

 

This raises a question from me.. I always use __bis_SR_register(flags).. What is the difference between this and _BIS_SR, and what are the advantages of each approach?

Link to post
Share on other sites

If you're going to BIS and BIC... I've found this works easiest (I've had issues leaving out the noop)

 

 

[somewhere in your code, after initialization but before running main loop]

__bis_SR_register(LPM4_bits + GIE);

__no_operation();

 

[in the P1 interrupt]

__bic_SR_register_on_exit(LPM4_bits);

 

 

 

That will cause your main code to go into LPM and when you push the button (GIE) it will fire the P1 interrupt which clears the LPM and your main code will continue from the __no_operation() spot.

 

There is also __bic_SR_IRQ(LPM4_bits);

 

http://www.rowley.co.uk/documentation/html/msp430_libc_bic_sr_irq.htm

http://www.rowley.co.uk/documentation/html/msp430_libc_bic_sr_register_on_exit.htm

Link to post
Share on other sites

I'm kinda confused on a few things and appreciate everyones patience. polling is definitely the way I'd like to go for now, don't know why i even said interrupt earlier. I guess really what's confusing me is how i actually implement it. I understand the logic as I can code in C++ all day, I'm just very new to MC programming.

 

basically.. i need

 

int flagvariable=0;

while (flagvaraible==1 && counter < cyclestocomplete)

{

//do my stuff

counter++;

}

 

problem is I don't know how exactly to get the button to change the flag variable.

Link to post
Share on other sites

You poll the port pin to which the button is connected.

 

unsigned char flagvariable = 0
volatile unsigned char buttonStatus;

void main(void)
{
  buttonStatus = P1IN & 0x8;  // assuming you connected it to Pin 1.3
  if (buttonStatus != 0)
  {    
     flagvariable = 1; //button clicked 
  }else
     flagvariable = 0; // unclicked
}


 

You don't even need a flag. Using your code:

while ( ((P1IN & 0x8) !=0) && counter {
//do my stuff
counter++;
}

 

EDIT: Using the second half, would run your code as long as the button is pressed.

Link to post
Share on other sites

Dude, give it a try :) Better than two while loops (one to keep the other from rechecking that the button was or was not pressed, as just the while loop examples in the last two posts will get passed by and the code will be over without something causing them to get hit repeatedly.)

 

#include "msp430g2452.h"

void main()
{
WDTCTL = WDTPW + WDTHOLD;						// Stop WDT
P1DIR &= ~(BIT3);						// 1.3 is button
P1SEL &= ~(BIT3);
P1OUT |= (BIT3);						// Set to high
P1REN |= (BIT3);						// Resistor enabled
P1IE |= (BIT3);						// Interrupt enabled
P1IES |= (BIT3);						// Edge select
P1IFG &= ~(BIT3);						// Clear interrupt flags

_bis_SR_register(LPM3_bits + GIE);				// Enter LPM3 w/ interrupt
__no_operation();							// Make sure we have something to sleep on
while(whatever here)
{
	//This is where your code goes.
}
}

#pragma vector=PORT1_VECTOR
__interrupt void P1ISR(void)
{
if(P1IFG & BIT3) // We interrupted on P1.3
{
	_bic_SR_register_on_exit(LPM3_bits);
	P1IFG &= ~BIT3; // clear the button press
}
}

Link to post
Share on other sites

alrighty, i'm definitely willing to give it a try as obviously the more i can learn from this project the better. my biggest issue is i was going to be trying to adapt and modify the code this guy used ( viewtopic.php?f=9&t=699 ) to use pwm to control my motor. will any of that stuff negatively interact with what i've got going on do you think? and if not, should i just combine your code and his and then put the main chunk of my functionality in that interrupt function? kinda confused on what's really going on there. thanks again!

Link to post
Share on other sites

#include 

// DEMO counter
unsigned int demoCounter = 0;

void main(void) {
   WDTCTL = WDTPW + WDTHOLD;           // Stop WDT

  P1DIR &= ~(BIT3);                  // 1.3 is button
  P1SEL &= ~(BIT3);
  P1OUT |= (BIT3);                  // Set to high
  P1REN |= (BIT3);                  // Resistor enabled
  P1IE |= (BIT3);                  // Interrupt enabled
  P1IES |= (BIT3);                  // Edge select
  P1IFG &= ~(BIT3);                  // Clear interrupt flags

   P1OUT |= BIT1;                  // Direction control - left
   P1OUT &= ~BIT0;                  // Direction control - right
                              // Both 0 or 1 - dynamic break
   P1DIR |= BIT0 + BIT1 + BIT2;      // Bit 2 is connected to enable and will be used for PWM

   P1SEL |= BIT2;                      // P1.2 TA1 option select
   CCTL0 = CCIE;                       // CCR0 interrupt enabled
   CCR0 = 1000;                  // ~8ms
   CCTL1 = OUTMOD_3;                   // CCR1 set/reset
   CCR1 = 950;                         // CCR1 duty cycle, slow in the beginning

  _bis_SR_register(LPM3_bits + GIE);            // Enter LPM3 w/ interrupt
  __no_operation();                     // Make sure we have something to sleep on

   TACTL = TASSEL_2 + MC_1 + ID_3;     // SMCLK/8, upmode

   _bis_SR_register(LPM0_bits + GIE);  // Enter LPM0 w/ interrupt
}

// Timer A0 interrupt service routine
#pragma vector = TIMERA0_VECTOR
__interrupt void Timer_A (void) {

   // DEMO movement
   demoCounter++;
   if(demoCounter == 800)
       CCR1 = 900;
   if(demoCounter == 1600)
       CCR1 = 500;
   if(demoCounter == 2000)
       CCR1 = 250;
   if(demoCounter == 2400)
       CCR1 = 0;
   if(demoCounter == 2800)
       CCR1 = 900;
   if(demoCounter == 3200) {
       P1OUT |= BIT0; // switch direction
       P1OUT &= ~BIT1;
   }
   if(demoCounter == 3600)
       CCR1 = 0;
   if(demoCounter == 4000)
       CCR1 = 900;
   if(demoCounter == 4400) {
       P1OUT |= BIT1; // switch direction
       P1OUT &= ~BIT0;
   }
   if(demoCounter == 4800) {
       P1OUT |= BIT0; // switch direction
       P1OUT &= ~BIT1;
   }
   if(demoCounter == 5200) {
       CCR1 = 500;
       P1OUT |= BIT1; // switch direction
       P1OUT &= ~BIT0;
       demoCounter = 0;
   }
   // END DEMO movement
}

#pragma vector=PORT1_VECTOR
__interrupt void P1ISR(void)
{
  if(P1IFG & BIT3) // We interrupted on P1.3
  {
     _bic_SR_register_on_exit(LPM3_bits);
     P1IFG &= ~BIT3; // clear the button press
  }
}

 

Like so, I beleive.

Link to post
Share on other sites

alrighty. so would i just replace my code with where he does his demo movements? or in the bottom function. so you fully understand what I'm needing to accomplish.. this thing is going to be plugged in almost all the time. all i want is the button press to make it execute my code(start a loop which will run a set amount of times), which is going to turn on an LED(stimulus light for drug discrimination research) turn it off, then turn the motor one way which is converted to a small linear actuator. then turn it other other way, then wait a set amount of time, and start the loop over. after it reaches the end of the counter for the loop repetition, it goes back into low power mode and wait's for the button to be pressed again to start it over. hopefully that helps it a bit. thanks for your help and patience once again. you're really helping me out a lot here

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...