Hi all, I just received my ez430 and the extra modules (with MSP430F2012) and I am just trying to get my head round some basic stuff, like reading in a port value to detect pushbuttons etc. I must say I am not very experienced so please be gentle :) I've connected two pushbuttons, one to P1.3 and one to P1.4 and they are pulled up to Vcc with 10K resistors. I've hooked them up to my multimeter and they drop to 0V when the button is pressed so they seem to be working. I've also coded this little bit of software, using mspgcc and I can't seem to get it to work. I know the LEDs are working as I've done a little blinking lights sequence with them but the following bit of code doesn't seem to 'register' when I press the push buttons. #include <io.h> #include <signal.h> #ifndef __MSP430_2012__ #define __MSP430_2012__ #endif int main(void){ WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer P1DIR = 0x1D; P1OUT = 0x00; for (;;){ if ( !(P1IN & 0x10) ){ // button a on port1.3 pressed? P1OUT |= 0x80; // turn on led 1 (port 1.0) } else if ( !(P1IN & 0x08) ){ // button b on port1.4 pressed? P1OUT |= 0x20; // turn on led 2 (port 1.2) } else { P1OUT = 0xFF; } } } I would appreciate any pointers as it just doesn't seem to work :( Thanks! Hamza.
MSP430-ez430 Basics - reading in pushbutton values
Started by ●April 21, 2008
Reply by ●April 21, 20082008-04-21
Hi, On Apr 21, 1:33=A0pm, Hamza <hamzasag...@googlemail.com> wrote: First, thank you for posting such a well-enunciated inquiry. It doesn't happen often enough here.> I've connected two pushbuttons, one to P1.3 and one to P1.4 and they > are pulled up to Vcc with 10K resistors. I've hooked them up to my > multimeter and they drop to 0V when the button is pressed so they seem > to be working.> =A0 =A0 =A0 =A0 P1DIR =3D 0x1D; > =A0 =A0 =A0 =A0 P1OUT =3D 0x00;As a rule you should also make it a point to initialize the PxSEL register when using the MSP430 family. So add P1SEL =3D 0x00 here. But that isn't your problem:> > =A0 =A0 =A0 =A0 for (;;){ > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ( !(P1IN & 0x10) ){ // button a on port=1.3 pressed? No it isn't, this code checks if P1.4 is pressed.> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 P1OUT |=3D 0x80; // turn o=n led 1 (port 1.0) No it isn't... this code turns on P1.7.> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else if ( !(P1IN & 0x08) ){ // button b =on port1.4> pressed?No it isn't... this code checks if P1.3 is pressed.> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 P1OUT |=3D 0x20; // turn o=n led 2 (port 1.2) No it isn't... this code turns on P1.5> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 } else { > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 P1OUT =3D 0xFF; > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }and this code ensures that both LEDs are always on even if the buttons aren't pressed :) The header files define macros for you to access the bits directly to avoid confusion. So try this: if ( !(P1IN & BIT3) ){ // button a on port1.3 pressed? P1OUT |=3D BIT0; // turn on led 1 (port 1.0) } else if ( !(P1IN & BIT4) ){ // button b on port1.4 pressed? P1OUT |=3D BIT2; // turn on led 2 (port 1.2) } else { P1OUT &=3D ~(BIT0 | BIT2); // turn off LEDs } This code is still not bug-free (consider what happens when only one button is pressed, then the second is pressed and released while the first is still held down), but it is closer to what you're trying to do.
Reply by ●April 21, 20082008-04-21
On Apr 21, 8:00 pm, larwe <zwsdot...@gmail.com> wrote:> Hi, > > On Apr 21, 1:33 pm, Hamza <hamzasag...@googlemail.com> wrote: > > First, thank you for posting such a well-enunciated inquiry. It > doesn't happen often enough here. > > > I've connected two pushbuttons, one to P1.3 and one to P1.4 and they > > are pulled up to Vcc with 10K resistors. I've hooked them up to my > > multimeter and they drop to 0V when the button is pressed so they seem > > to be working. > > P1DIR = 0x1D; > > P1OUT = 0x00; > > As a rule you should also make it a point to initialize the PxSEL > register when using the MSP430 family. So add P1SEL = 0x00 here. But > that isn't your problem: > > > > > for (;;){ > > if ( !(P1IN & 0x10) ){ // button a on port1.3 pressed? > > No it isn't, this code checks if P1.4 is pressed. > > > P1OUT |= 0x80; // turn on led 1 (port 1.0) > > No it isn't... this code turns on P1.7. > > > } else if ( !(P1IN & 0x08) ){ // button b on port1.4 > > pressed? > > No it isn't... this code checks if P1.3 is pressed. > > > P1OUT |= 0x20; // turn on led 2 (port 1.2) > > No it isn't... this code turns on P1.5 > > > } else { > > P1OUT = 0xFF; > > } > > and this code ensures that both LEDs are always on even if the buttons > aren't pressed :) > > The header files define macros for you to access the bits directly to > avoid confusion. > So try this: > > if ( !(P1IN & BIT3) ){ // button a on port1.3 > pressed? > P1OUT |= BIT0; // turn on led 1 (port 1.0) > } else if ( !(P1IN & BIT4) ){ // button b on port1.4 > pressed? > P1OUT |= BIT2; // turn on led 2 (port 1.2) > } else { > P1OUT &= ~(BIT0 | BIT2); // turn off LEDs > } > > This code is still not bug-free (consider what happens when only one > button is pressed, then the second is pressed and released while the > first is still held down), but it is closer to what you're trying to > do.Silly me! I really should have looked deeper before I let it out, sorry about the mess :) Thank you very much for your help, and also the hint on the shorthand BIT macros. I understand the flaws of this approach to handling pushbuttons, I was just trying to test if I was actually reading anything. Moving one step ahead on the same topic, I have written this little bit of code to implement interrupt handling, which I believe is a better alternative to polling. The idea is the LED on P1.0 will toggle away happily until a key is pressed and then the interrupt handler p1_interrupt() will kick in and toggle the LED on P1.2. I have scavenged bits and pieces from some samples and came up with the following mess: #include <io.h> #include <signal.h> #ifndef __MSP430_2012__ #define __MSP430_2012__ #endif interrupt (PORT1_VECTOR) p1_interrupt(){ dint(); if(P1IFG==0x01){ P1OUT ^= BIT2; // toggle LED on P1.2 } eint(); } int main(void){ WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer P1DIR = 0x07; P1OUT = 0x00; P1SEL = 0x00; P1IFG = 0X00; // No interrupt is pending P1IES = 0X01; // The PxIFGx flag is set with a high-to-low transition P1IE = 0X01; // The interrupt is enabled eint(); int i; for (;;){ // toggle the LED on p1.0 P1OUT ^= BIT0; i = 20000; while (i != 0){ i--; }; } } It compiles fine but the problem is the program never leaves the interrupt handler! P1.2 toggles continuously whether I press the button or not. Am I missing something really obvious again? Many thanks, Hamza.
Reply by ●April 21, 20082008-04-21
On Apr 21, 7:25=A0pm, Hamza <hamzasag...@googlemail.com> wrote:> Moving one step ahead on the same topic, I have written this little > bit of code to implement interrupt handling, which I believe is a > better alternative to polling. The idea is the LED on P1.0 will toggle > away happily until a key is pressed and then the interrupt handler > p1_interrupt() will kick in and toggle the LED on P1.2. > > I have scavenged bits and pieces from some samples and came up with > the following mess: > > #include <io.h> > #include <signal.h> > > #ifndef __MSP430_2012__ > #define __MSP430_2012__ > #endifWhy are you doing this, by the way? You shouldn't need to define any chip-specific macros. Set the chip type in the compiler settings. Otherwise the compiler is pulling in the wrong ioxxxxxx.h file.> interrupt (PORT1_VECTOR) p1_interrupt(){ > =A0 =A0 =A0 =A0 dint(); > =A0 =A0 =A0 =A0 if(P1IFG=3D=3D0x01){ > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 P1OUT ^=3D BIT2; // toggle LED on P1.2 > =A0 =A0 =A0 =A0 } > =A0 =A0 =A0 =A0 eint(); > > }You are not clearing the interrupt request flag here, so as soon as the ISR exits, the interrupt fires again. Some interrupts automatically clear their appropriate request flag when the handler is called - without looking at the datasheet I don't know if the pin- change interrupt is one of these - I guess not, from your description of the behavior.> It compiles fine but the problem is the program never leaves the > interrupt handler! P1.2 toggles continuously whether I press the > button or not.By the way, your code here is going to be toggling P1.0 constantly, and toggling P1.2 when you press the button. HOWEVER, it probably isn't going to work very well because you haven't put any debouncing in there. You'll probably see P1.2 toggle several times when you press or release the button.
Reply by ●April 22, 20082008-04-22
On Apr 22, 12:36 am, larwe <zwsdot...@gmail.com> wrote:> On Apr 21, 7:25 pm, Hamza <hamzasag...@googlemail.com> wrote: > > > #include <io.h> > > #include <signal.h> > > > #ifndef __MSP430_2012__ > > #define __MSP430_2012__ > > #endif > > Why are you doing this, by the way? You shouldn't need to define any > chip-specific macros. Set the chip type in the compiler settings. > Otherwise the compiler is pulling in the wrong ioxxxxxx.h file. >I altered the makefile and it looks much cleaner without all this now, I don't know why I didn't do this before :)> > interrupt (PORT1_VECTOR) p1_interrupt(){ > > dint(); > > if(P1IFG==0x01){ > > P1OUT ^= BIT2; // toggle LED on P1.2 > > } > > eint(); > > > } > > You are not clearing the interrupt request flag here, so as soon as > the ISR exits, the interrupt fires again. Some interrupts > automatically clear their appropriate request flag when the handler is > called - without looking at the datasheet I don't know if the pin- > change interrupt is one of these - I guess not, from your description > of the behavior. >Absolutely spot on. P1IFG = 0x00; solved everything, Thanks!> > It compiles fine but the problem is the program never leaves the > > interrupt handler! P1.2 toggles continuously whether I press the > > button or not. > > By the way, your code here is going to be toggling P1.0 constantly, > and toggling P1.2 when you press the button. HOWEVER, it probably > isn't going to work very well because you haven't put any debouncing > in there. You'll probably see P1.2 toggle several times when you press > or release the button.Strangely enough I didn't get any debouncing issues, but just to be on the safe side I've added it in. This seems to be working for me so I'm just throwing this in for further google searches :) if(P1IFG & BIT3){ d = 500; while(d){ d--; } if(P1IN & BIT3){ P1OUT ^= BIT2; } } Many thanks for your help larwe, it's much appreciated. Cheers, Hamza.