DarthMessiah15 0 Posted May 16, 2011 Share Posted May 16, 2011 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 Quote Link to post Share on other sites
bluehash 1,581 Posted May 16, 2011 Share Posted May 16, 2011 Hook up a button to one of the interrupt lines. Create a global flag variable and initialize it to zero. If the button is pressed, interrupt is triggered, flag is set to one. In the main function, put your code in a while loop, waiting for the flag to change. Quote Link to post Share on other sites
bluehash 1,581 Posted May 16, 2011 Share Posted May 16, 2011 Hook up a button to one of the interrupt lines. Create a global flag variable and initialize it to zero. If the button is pressed, interrupt is triggered, flag is set to one. In the main function, put your code in a while loop, waiting for the flag to change. Quote Link to post Share on other sites
DarthMessiah15 0 Posted May 16, 2011 Author Share Posted May 16, 2011 cool. i didn't know it was that easy. never used buttons before. Quote Link to post Share on other sites
DarthMessiah15 0 Posted May 16, 2011 Author Share Posted May 16, 2011 ok one more question. by interrupt lines do you mean one of the pins like 1.3? and do I have to do any initialization stuff or just set it as an input within grace and then it'll take care of the rest? Quote Link to post Share on other sites
SugarAddict 227 Posted May 16, 2011 Share Posted May 16, 2011 //****************************************************************************** // 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. Quote Link to post Share on other sites
DanAndDusty 62 Posted May 16, 2011 Share Posted May 16, 2011 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? Quote Link to post Share on other sites
SugarAddict 227 Posted May 16, 2011 Share Posted May 16, 2011 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 Quote Link to post Share on other sites
DarthMessiah15 0 Posted May 16, 2011 Author Share Posted May 16, 2011 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. Quote Link to post Share on other sites
bluehash 1,581 Posted May 16, 2011 Share Posted May 16, 2011 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. jsolarski 1 Quote Link to post Share on other sites
SugarAddict 227 Posted May 17, 2011 Share Posted May 17, 2011 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 } } Quote Link to post Share on other sites
DarthMessiah15 0 Posted May 17, 2011 Author Share Posted May 17, 2011 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! Quote Link to post Share on other sites
SugarAddict 227 Posted May 17, 2011 Share Posted May 17, 2011 #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. DarthMessiah15 1 Quote Link to post Share on other sites
DarthMessiah15 0 Posted May 17, 2011 Author Share Posted May 17, 2011 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 Quote Link to post Share on other sites
SugarAddict 227 Posted May 17, 2011 Share Posted May 17, 2011 Yep, you would do all of your work in the TimerA interrupt. DarthMessiah15 1 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.