Jump to content
43oh

LaunchPad as Sony IR Remote


Recommended Posts

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
}

post-197-135135494277_thumb.png

Link to post
Share on other sites

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.

Link to post
Share on other sites
  • 1 month later...

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...