roadrunner84 466 Posted February 23, 2013 Author Share Posted February 23, 2013 That's one of the reasons I don't like using hard delays to do anything on the msp430. I'll post my code using denouncing when done with it (having kids permits me less hobby time), but you won't see any delay constructs in my code :-) Quote Link to post Share on other sites
roadrunner84 466 Posted February 25, 2013 Author Share Posted February 25, 2013 I got rid of the creepy 6V -> 3V circuit. Feed with 3V now Quote Link to post Share on other sites
roadrunner84 466 Posted March 4, 2013 Author Share Posted March 4, 2013 For some heavily overdimensioned code: #include <msp430.h> #include <stdint.h> #ifndef __cplusplus__ #include <stdbool.h> #endif /* __cplusplus__ */ #define P2MAP (BIT6 | BIT7) /* set to 0xFF for 20-pin device */ #define BUTTON0 BIT2 #define BUTTON1 BIT5 #define PLATE0 BIT6 #define PLATE1 BIT7 #define CHECK_MSEC 10 #define PRESS_MSEC 40 #define RELEASE_MSEC 100 #define TIMEOUT 6000 /* in CHECK_MSEC periods */ volatile bool pwm0 = false, pwm1 = false; bool debounce(bool state, bool read, uint16_t* count); int main(void) { // Stop WDT WDTCTL = WDTPW | WDTHOLD; // Stop WDT BCSCTL1 = DIVA_2; // ACLK /= 4 BCSCTL2 = SELM_0; // MCLK = SMCLK = DCO BCSCTL3 = LFXT1S_2; // LFXT1 = VLO (ACLK = 3kHz) // Set up I/O (buttons as interrupt, LEDs off) P2SEL = 0; // Set crystal I/O to GPIO P1REN = ~(PLATE0 | PLATE1); // All pin pull up/down, except ouputs P2REN = P2MAP; // Also on port 2 P1DIR = ~(BUTTON0 | BUTTON1); // disable all input, except inputs P2DIR = P2MAP; // Also on port 2 P1OUT = BUTTON0 | BUTTON1; // pull up button inputs P1IES = BUTTON0 | BUTTON1; // high->low transition P1IFG = 0; // clear interrupt flags P1IE = BUTTON0 | BUTTON1; // enable interrupts // Set up timer for 10ms interval and CCR1 for 30% duty cycle TACCR0 = (10 * 3) - 1; // 10ms TACCR1 = ( 1 * 3) - 1; // 1ms TACCTL1 = CCIE; // Set TA0.1 to 30% duty cycle 10ms PWM TACCTL0 = CCIE; TACTL = TASSEL_1 | ID_0 | MC_1 | TACLR;// | TAIE; // Enable 3kHz timer interrupt __enable_interrupt(); LPM3; __no_operation(); } #pragma vector=PORT1_VECTOR __interrupt void PORT1_ISR(void) { P1IFG = 0; // Leave LPM4 __bic_SR_register_on_exit(OSCOFF); // Enable ACLK after ISR (LPM4 -> LPM3) } #pragma vector=TIMER0_A1_VECTOR __interrupt void TIMER0_A1_ISR(void) { TACCTL1 &= ~CCIFG; // clear interrupt flag if (!(pwm0 || pwm1)) return; switch(TACCR1) { case (1 * 3) - 1: if (pwm0) P1OUT |= PLATE0; TACCR1 = (4 * 3) - 1; break; case (4 * 3) - 1: P1OUT &= ~PLATE0; TACCR1 = (6 * 3) - 1; break; case (6 * 3) - 1: if (pwm1) P1OUT |= PLATE1; TACCR1 = (9 * 3) - 1; break; case (9 * 3) - 1: P1OUT &= ~PLATE1; TACCR1 = (1 * 3) - 1; break; default: TAR = 0; break; } } #pragma vector=TIMER0_A0_VECTOR __interrupt void TIMER0_A0_ISR(void) { static bool state0 = false, state1 = false; static uint16_t count0 = 0, count1 = 0; static uint16_t timeout; TACCTL0 &= ~CCIFG; // clear interrupt flag // Handle button 0 if (debounce(state0, P1IN & BUTTON0, &count0)) { state0 = !state0; if (!state0) pwm0 = !pwm0; timeout = TIMEOUT; } // Handle button 1 if (debounce(state1, P1IN & BUTTON1, &count1)) { state1 = !state1; if (!state1) pwm1 = !pwm1; timeout = TIMEOUT; } // Handle timeout if (--timeout == 0) { pwm0 = pwm1 = false; P1OUT &= ~(PLATE0 | PLATE1); } // Handle low power mode if (!pwm0 && !pwm1 && state0 && state1 && ((P1IN & (BUTTON0 | BUTTON1)) == (BUTTON0 | BUTTON1))) { // if plates off and buttons up // Enter LPM4 __bis_SR_register_on_exit(OSCOFF); // Disable ACLK after ISR (LPM3 -> LPM4) } } bool debounce(bool state, bool read, uint16_t* count) { if (read == state) { *count = !state?(RELEASE_MSEC / CHECK_MSEC):(PRESS_MSEC / CHECK_MSEC); } else { if ((--*count) + 1 == 0) { *count = !read?(RELEASE_MSEC / CHECK_MSEC):(PRESS_MSEC / CHECK_MSEC); return true; } } return false; } Debouncing two buttons and PWMing two LEDs with a 180 degrees phase shift. While spending as much time as possible in LPM4, or LPM3 otherwise. This code compiles to well over 600 bytes of code, so it won't fit on the 1/2 kB devices without tweaking. But the 8pin value line chips are both 2kB, so no harm there On an extended subject; (almost?) all MSP430 devices carry an addictional 4x64 byte "information flash". Let's assume we loose info_a to the TLV data and upper 32 bytes flash to vectors. This leaves us with a systematic 160 bytes extra (above the specified size) flash which remain unused in a lot of applications. Couldn't we repurpose that memory for the application? This would deliver us over 30% of "free" flash on the smallest devices. (or almost 8% on the 2kB devices) JK2308 1 Quote Link to post Share on other sites
rockets4kids 204 Posted March 4, 2013 Share Posted March 4, 2013 Wouldn't a main-driven 9V supply be easier? Quote Link to post Share on other sites
GG430 53 Posted March 4, 2013 Share Posted March 4, 2013 @roadrunner84 Wow, that's really some sophisticated code for this application. I also had some time to work on this today and I kind of went the other way and rather did chose the analog approach over the digital one. I just increased the resistors R1 and R8 to 560 Ohms and used my initial code without the PWM. Now I Quote Link to post Share on other sites
roadrunner84 466 Posted March 4, 2013 Author Share Posted March 4, 2013 Msp430 is misleadingly large on code, some instructions are "only" 2 bytes, others are 4. I noticed out takes a whopping 60 bytes if you have not all variables initialized to 0! This is because if you have variables initialized to any non-zero value, the linker hauls on an entire memcopy function to preload the variables. I'll benchmark the current usage as soon possible... which will probably be Friday next week. :-( Quote Link to post Share on other sites
GG430 53 Posted March 4, 2013 Share Posted March 4, 2013 I'd say there is no shorter instruction than 1 word on a 16b CPU and the 430 is quite good from a code density perspective. The compiler is a different story though. Guess that's why I was only programming assembly until 2 years ago. But I have to admit that the time to get something working is much faster on C. Which compiler do you use? That's a good compilation of instructions and code length: http://www.ti.com/sc/docs/products/micro/msp430/userguid/as_5.pdf Quote Link to post Share on other sites
roadrunner84 466 Posted March 4, 2013 Author Share Posted March 4, 2013 I'm using IAR, it is on low optimisation now, but high optimisation doesn't make it a lot smaller. C was actually invented as a "portable assembler", though the low level stuff we're doing on the msp430 makes out hardly portable. Quote Link to post Share on other sites
jcmaxwel 0 Posted March 17, 2013 Share Posted March 17, 2013 I successfully fixed our kitchen today using a MSP430G2211, roadrunner84's code and CCS. There's a pitfall in roadrunner84's code, though: if (debounce(state0, P1IN & BUTTON0, &count0)) The second argument does not evaluate to 'true' in (at least my) CCS but to the integer representation of P1IN & BUTTON0 Thus, if (read == state) does not work as intended. In my version of the code I fixed it like this: if (debounce(state0, (P1IN & BUTTON0) > 0, &count0)) I know that this is also far from safe in a C90 kind of way, but it works. Oh, and by the way: if ((--*count) + 1 == 0) is the ugliest piece of C I have seen in quite some time. Maybe I'm just too much accustomed to quality code... ;-) Anyways, thank you very much for sharing! It saved quite an amount of my free time. Quote Link to post Share on other sites
roadrunner84 466 Posted March 17, 2013 Author Share Posted March 17, 2013 P1IN & BUTTON0 may not evaluate to true or false, but as it is passed as a bool argument to the debounce function, it should be implicitly casted to a boolean. Maybe CCS doesn't evaluate it that way, but IAR does with low optimisation. (--*count) + 1 looks very ugly, I aimed at compact coding, and I couldn't find a way to execute postfix decrement on a dereferenced variable. I designed it this way te avoid initialising any variable to a non-zero value (as it would link memcopy in and size would be larger.) I finished my fixing too, I'll post pictures of it soon. Idle current is not measurable with my 200uA multimeter (which has 0.1uA resolution, so actually my ilde current is <150nA) bluehash 1 Quote Link to post Share on other sites
roadrunner84 466 Posted March 18, 2013 Author Share Posted March 18, 2013 (edited) So, it turned out I had the two buttons switched, thanks to define it is as easy as switching a 2 and a 5 to get it working properly. It actually looks messier than it does in real life. I had no SMD resistor/capacitor around, so I settled with PTH components instead. The SOIC8 chips is deadbug style on top of the DIP8 plate, which plugs into a DIP8 socket which I placed on the board. As my earlier design showed for only 6 used pins of the 8 in a DIP8 formfactor, I repurposed the other two as SBW breakout. These pins aren't routed on the IKEA PCB anyways. Ofcourse, those pins do not map on the normal launchpad pins at all, so I used female to female jumper wires to patch the lower half of the 20 pin socket to vcc, gnd, test and reset. Edited March 18, 2013 by bluehash No imgur links. They expire. All pics must be uploaded to 43oh. GG430 1 Quote Link to post Share on other sites
Slurm 0 Posted October 27, 2020 Share Posted October 27, 2020 wow, i found this old thread because i have the same kids toy on my bench right now. mine has failed because water got into it and corroded the two buttons. another design failure. having this thing right next to the sink, where kids play with water. they did take this into account somehow, because all the electronics is elevated and there are drain holes for water, but they still did not waterproof the buttions. the only place where there is electronics right underneath. long story short, i opend it up and my first thought was straight away, that this thing is unneccessary complicated, and due to the lack of a power switch it will drain the batteries even if the LED's are off. but you guys just took it even further. i have to admit, putting a microcontroller in there was one of my first thougts too, but my goal was to prevent more water damage in the future. the micro could have handled some capacitive touch sensor buttons. that way i could have sealed the whole thing off. but it would have constantly draind the power as well. so i think will go simpler, instead of even more complicated. first thought was just to repair the buttons as they are and to add a real power switch on the botttom to turn it off for good, if not in use. but now i lean to the most simplistic way there is. just remove all the electronics, add real (waterproof) on-off switches instead of the push buttons and wire the LED's directly to the batteries. it will only use power if it is really on, and there is nothing else in there to fail. (i will also add hotglue to the remaining solderpoints and wires to waterproof them too.) even has the added bennefit of teaching the kids to turn off the stove after use, and not to rely on it to turn of by itself. 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.