RobG 1,892 Posted January 7, 2011 Share Posted January 7, 2011 I am in the process of creating my first entry to the project of the month contest, IR remote control for Sony devices. There are 3 switches, Volume Down, Volume Up, and Power, which are connected to ports P1.1 through P1.3. P1.4 will drive the transistor through resistor. MCU is in LPM4 mode waiting for a button to be pressed. Once the button is pressed, the mode is changed to LPM0 so the Timer can "work" on sending the command. After the command is sent, we check the button and start another cycle or change back to LPM4 mode. EDIT: I've made some changes as suggested, we do not need P1.0 anymore, we will simply change the function of P1.4 from I/O (no carrier) to SMCLK out (carrier on.) #include "msp430g2231.h" #define T600us 23 // 600us #define T1200us (T600us * 2) // 1200us #define T2400us (T1200us * 2) // 2400us #define T24ms (T2400us * 10) // 24ms #define BIT1_3 (BIT1 + BIT2 + BIT3) // all 3 bits, those will be used for switches unsigned int counter = 0; // main counter unsigned char command = 2; // current command unsigned char bitCounter = 0; // command's bit counter unsigned char carrierFlag = 0; // flag to indicate carrier on or off unsigned int tmpCommand = 0; // copy of the current command used for shifting // Sony commands: 7 bit Command + 5 bit Address, bit0 is MSB // Volume - 19 0000 (pad to 16) + 1100100 (command) + 10000 (device Address: TV) = 0x0C90 // Volume + 18 0000 + 0100100 + 10000 = 0x0490 // Power 21 0000 + 1010100 + 10000 = 0x0A90 unsigned int commands[3] = { 0x0C90, 0x0490, 0x0A90 }; // list of available commands 0 Volume Down, 1 Volume Up, 2 Power void main(void) { WDTCTL = WDTPW + WDTHOLD; // stop WDT DCOCTL |= DCO0 + DCO1; // DCO = ~300kHz BCSCTL1 |= RSEL0 + RSEL1; // as above BCSCTL1 &= ~(RSEL2 + RSEL3); // as above BCSCTL2 |= DIVS0 + DIVS1; // divide SMCLK by 8 which will give us ~38kHz P1DIR |= BIT4; // port 1.4 is configured as SMCLK out and connected to IR emitter, this will be our carrier frequency, 38kHz P1OUT &= ~BIT4; P1SEL &= ~BIT4; // for now turn it off P1REN |= BIT1_3; // P1.1-P1.3 pull-up P1OUT |= BIT1_3; // P1.1-P1.3 pull-up P1IE |= BIT1_3; // P1.1-P1.3 interrupt enabled P1IES |= BIT1_3; // P1.1-P1.3 hi/lo edge P1IFG &= ~BIT1_3; // P1.1-P1.3 IFG cleared TACCR0 = T600us; // interrupt every 600us for starters TACTL = TASSEL_2 + MC_1 + ID_0; // SMCLK, upmode tmpCommand = commands[command]; // default cmd __bis_SR_register(LPM0_bits + GIE); // switch to LPM0 with interrupts } // Timer A interrupt service routine #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) { if(counter == 0) { // start with start bit P1SEL |= BIT4; // carrier on TACCR0 = T2400us; // start bit is on for 2400us } else { if(bitCounter < 12) { // we have 12 bits to process if(!carrierFlag) { P1SEL &= ~BIT4; // carrier off, once before every bit TACCR0 = T600us; // no carrier for 600us } else { P1SEL |= BIT4; // carrier on if(tmpCommand & 0x0800) { // test bit 12, since we are only using 12 out of 16 bits TACCR0 = T1200us; // if bit is 1, carrier on for 1200us } else { TACCR0 = T600us; // if bit is 0, carrier on for 600us } bitCounter++; tmpCommand<<=1; // shift bits to the left in tmp variable } carrierFlag ^= 1; // toggle flag } } counter++; if(counter == 26){ // we are done sending current frame P1SEL &= ~BIT4; // carrier off counter = 0; // reset all counters bitCounter = 0; carrierFlag = 0; if(~P1IN & BIT1_3) { // check if the button is still pressed tmpCommand = commands[command]; // still pressed, repeat last command TACCR0 = T24ms; // delay, frames should be ~45ms apart } else { // we are done, go back to sleep P1IE |= BIT1_3; // enable P1.1-P1.3 interrupt TACCTL0 &= ~CCIE; // CCR0 interrupt disabled __bis_SR_register_on_exit(LPM4_bits); // switch from LPM0 to LPM4 } } } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { P1IE &= ~BIT1_3; // disable P1.1-P1.3 interrupt P1IFG &= ~BIT1_3; // P1.1-P1.3 IFG cleared if(~P1IN & BIT1) { // check which switch was pressed, set command command = 0; } else if(~P1IN & BIT2) { command = 1; } else if(~P1IN & BIT3) { command = 2; } else { // nothing pressed? P1IE |= BIT1_3; // enable P1.1-P1.3 interrupt return; // return to LPM4, keep timer off } tmpCommand = commands[command]; TACCTL0 = CCIE; // CCR0 interrupt enabled __bic_SR_register_on_exit(LPM4_bits-LPM0_bits); // switch from LPM4 to LPM0 } oPossum, VIPTech and TopHatHacker 3 Quote Link to post Share on other sites
OCY 19 Posted January 7, 2011 Share Posted January 7, 2011 Very good work. I have some small suggestions. You do not need to use P1.0 to modulate the 38 kHz sub-carrier with hardware (D2, D3, and R1). You could clear BIT4 of P1OUT and set/clear BIT4 of P1SEL to turn on/off the sub-carrier at P1.4. Connect P1.4 directly to the base of the transistor T1 and move R2 and D1 from the collector side to the emitter side of T1. Also, you do not need R3, R4, and R5. You could set BIT1, BIT2, and BIT3 of P1REN instead. With these small changes in firmware and some re-wiring , you freed one port pin and saved four resistors and two diodes. RobG 1 Quote Link to post Share on other sites
RobG 1,892 Posted January 7, 2011 Author Share Posted January 7, 2011 Nice, very good suggestions, I knew there was an easier way to do it, just couldn't see it. The simplest solutions are always in front of us. This is the reason I posted before before this thing was finished. Thanks for the feedback! Quote Link to post Share on other sites
RobG 1,892 Posted January 8, 2011 Author Share Posted January 8, 2011 The code is now final (I am still waiting for some parts and as soon as I get them I will add a video.) Quote Link to post Share on other sites
OCY 19 Posted January 8, 2011 Share Posted January 8, 2011 I am kind of obsessed in keeping hardware simple. Do you think you can move R2 and D1 between the emitter of T1 and ground? After that, I think you do not need R1. No change in firmware is needed. Quote Link to post Share on other sites
RobG 1,892 Posted January 8, 2011 Author Share Posted January 8, 2011 Sure, in this case we can do common collector. ScoMac 1 Quote Link to post Share on other sites
paradug 4 Posted January 9, 2011 Share Posted January 9, 2011 This is really neat! Easy to build and useful. I can't wait to give it a go. Thanks for sharing. Quote Link to post Share on other sites
RobG 1,892 Posted January 9, 2011 Author Share Posted January 9, 2011 My pleasure. The next logical step: IR receiver (I was actually thinking to do a complete IR RC solution using 2 LaunchPads, time permitting.) Quote Link to post Share on other sites
bluehash 1,581 Posted January 11, 2011 Share Posted January 11, 2011 Good work RobG. Sorry about this month's POTM being scrapped. You will have ample time to fine tune it for the next months(Feb 2011) POTM contest. Quote Link to post Share on other sites
infrared 3 Posted January 11, 2011 Share Posted January 11, 2011 @robg Cant wait for the receiver design! Quote Link to post Share on other sites
RobG 1,892 Posted February 13, 2011 Author Share Posted February 13, 2011 Quote Link to post Share on other sites
RobG 1,892 Posted February 13, 2011 Author Share Posted February 13, 2011 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.