just_another_noob 0 Posted June 15, 2011 Share Posted June 15, 2011 Hello All, I have been playing with my new launch pad trying to figure things out. I am currently attempting to use a single button for multiple purposes. For instance, if the button is held for 3 sec the red led is lit, but if the button is pressed and released before 3 sec, the green one is lit. I thought that this would be a simple exercise, but I haven't been able to quite get it to work. I know that I can toggle the interrupt edge using P1IES ^= BUTTON (Where BUTTON = BIT3), but what I don't know is how to determine if the edge is high or low. I have been looking through code and searching on line, but I must have missed it somewhere. If anyone has any ideas (hey, I'll even take leads if you think I ought to "work for it" more) . Thanks j.a.n. Quote Link to post Share on other sites
gordon 229 Posted June 15, 2011 Share Posted June 15, 2011 Not sure I understand, are you perhaps looking for (P1IES & BIT3) == 0? This will be true when interrupt on the rising edge is selected, conversely, (P1IES & BIT3) != 0 will be true when interrupt on the falling edge is selected. (PS. yes, I like to fully spell out conditionals ) just_another_noob 1 Quote Link to post Share on other sites
RobG 1,892 Posted June 16, 2011 Share Posted June 16, 2011 Alternatively, you can tie 2 pins together and get triggers on both edges. You can also do something more fancy and use timer's capture function. You will get triggers on both edges and you will get timing. EDIT: I just realized what you are trying to do and that is a neat idea. I have a problem with getting my encoder switch to work properly so I will try using your approach. Quote Link to post Share on other sites
just_another_noob 0 Posted June 16, 2011 Author Share Posted June 16, 2011 Thanks gordon! I think that is what I am looking for, I'll give that a try and see how it works. I am basically trying to have one LED light if the button has been held for a certain period (3 sec) and the other to be lit if the button has been released before that time. Kind of like the mode button common to digital watches; if you press the button it shows the date, but if you hold the button, it allows you to edit the time. j.a.n. Quote Link to post Share on other sites
rockets4kids 204 Posted June 16, 2011 Share Posted June 16, 2011 Also, be aware that you're going to need to de-bounce the switch. Quote Link to post Share on other sites
zeke 693 Posted June 16, 2011 Share Posted June 16, 2011 Sometimes you don't need traditional debouncing depending on how fast a response time you require. I've used interrupt timed polling of a switch input. That is, continuously check the state of the switch input every 20ms. If it is active four or eight times in a row then it's considered a valid input signal. It slows down the response time but it frees you to do other things in the mean time. Quote Link to post Share on other sites
jsolarski 94 Posted June 16, 2011 Share Posted June 16, 2011 I believe the code will go something like this Wait for button press, --> when pressed start interrupt ISR --> start timer, and change edge select, exit ISR --> wait for new interrupt when button is released --> ISR should stop - stop timer--> if timer is less then 3 seconds display option 1 if longer then 3 secs --> option 2 you will need to De bounce the switch otherwise this setup may not work for edge select P1ES = 1 == High to low P1ES = 0 == low to high be mindful of how you set your pull up and pull down on that port to determine your edge, you need to know the starting state, if its a button tied to ground - you would us a pull up resister and it would be considered High state -- when pressed it would go low and if its a button tied to a voltage(3.3V) then you would use a pulldown and the starting state would be low, and when the button is pressed the pin goes High you can also find the initial state by changing the pin to an input and reading the value (1|0) Quote Link to post Share on other sites
rockets4kids 204 Posted June 16, 2011 Share Posted June 16, 2011 Sometimes you don't need traditional debouncing depending on how fast a response time you require. The problem in this case is that that when the switch is depressed, it is likely to generate several interrupts before settling into the full-on state. This is going to need to be accounted for in the program logic if a hardware de-bounce circuit is not used. Quote Link to post Share on other sites
just_another_noob 0 Posted June 16, 2011 Author Share Posted June 16, 2011 Thanks everyone for the great responses. jsolarski - That is just about what my thought process was on the matter. It was good to have confirmation that I was thinking along a working path. I managed to get the code to work. I tried the different suggestions posted. Using (P1IES & BIT3) != 0 always returned as true and using P1ES just threw errors. I am guessing it is because I missed something and that these techniques would work with more nimble fingers at the keyboard. My solution was to create a variable to indicate when the button was pressed, and a variable to indicate when the timer was set. I'll include the code below. I invite you all to make suggestions on how to make the code leaner, more efficient, etc. My goal is to learn how to make this code efficient, so that I can store it a a bag of tricks for when I start doing things that are more complex. For now however, I am just trying to learn how all of this works. #include #define LED_RED BIT0 #define LED_GR BIT6 #define BUTTON BIT3 int pressed = 0;// declare variable to indicate button press int myTimer = 0;// declare variable to indicate timer running int main(void) { WDTCTL = WDTPW + WDTHOLD;// Stop watchdog timer P1DIR |= (LED_RED + LED_GR);// Set P1.0 to output direction P1OUT &= ~(LED_RED + LED_GR);// set P1.0 to 0 (LEDs OFF) P1IE |= BUTTON;// P1.3 interrupt enabled P1IFG &= ~BUTTON;// P1.3 IFG cleared __enable_interrupt();// enable all interrupts for (; {} } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { if (pressed == 0)// If the button hasn't been pressed yet { TACTL = TASSEL0 + ID_3 + TACLR;// TACLK, divider 8, clear TAR, TACCTL0 = CCIE;// enable interrupt TACCR0 = 4000;// set timer for 3 seconds TACTL |= MC_1;// setting mode bits starts timer up mode myTimer = 1;// set this to 1 to indicate the timer has started pressed = 1;// set this to 1 to indicate the button has been pressed } // end If pressed else if ((pressed == 1))//If the button has been pressed { pressed = 0;// reset button press variable if (myTimer == 1)// If the timer is going, this means that 3 sec hasn't elapsed or this is a button release { P1OUT ^= (LED_GR);// P1.0 = toggle TACCTL0 ^= CCIE;// turn off timer interupt TACTL = MC_0 + TACLR;// stop timer and clear timer myTimer = 0; } } P1IFG &= ~BUTTON;// P1.3 IFG cleared P1IES ^= BUTTON;// toggle the interrupt edge, // This means that an interrupt will be triggered // on p1.3 button up as well as button press } //end PORT1_VECTOR // Timer interrupt #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A0(void) { TACCTL0 ^= CCIE;// enable interrupt TACTL = MC_0 + TACLR;// stop timer and clear timer P1OUT ^= (LED_RED);// P1.0 = toggle P1IFG &= ~BUTTON;// P1.3 IFG cleared myTimer = 0; // set my timer to 0 since the time (3 sec) has elapsed } //end TIMERA0_VECTOR Quote Link to post Share on other sites
zeke 693 Posted June 16, 2011 Share Posted June 16, 2011 Sometimes you don't need traditional debouncing depending on how fast a response time you require. The problem in this case is that that when the switch is depressed, it is likely to generate several interrupts before settling into the full-on state. This is going to need to be accounted for in the program logic if a hardware de-bounce circuit is not used. But I don't trigger an ISR when the button is pressed. Rather, I periodically check the button using a timer ISR (ie: polled). I'm not saying it's the most efficient method - it's just another method. Quote Link to post Share on other sites
SouLSLayeR 5 Posted June 18, 2011 Share Posted June 18, 2011 #include unsigned int counter=0; int main(void) { WDTCTL = WDTPW + WDTHOLD;// Stop watchdog timer P1DIR |= BIT0+BIT6; // Set P1.0 to output direction P1OUT &= ~(BIT0+BIT6); // set P1.0 to 0 (LEDs OFF) while (1) // Infinite Loop { //pressing the button you add +1 to the counter every 10 msec. //If counter < 20 (200msecs = 0.2sec), normal press, green led lights on. //If counter > 200 (2000msecs = 2sec), extended press, red led lights on. if ((BIT3 & P1IN) == 0) // active low switch {counter++; __delay_cycles(10000);} //10000 delay cycles / ~1MHz = ~10 msec else if (0 < counter && counter < 20) //gotta love google {P1OUT ^= BIT6; counter = 0;} else if (counter >= 200) {P1OUT ^= BIT0; counter = 0;} else if (counter >200) //some help if things get stuck (and they probably will) {counter = 0;} } } Well, it works, though the long press is longer than what I had calculated it should be for some reason. jsolarski 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.