Created
October 13, 2014 20:48
-
-
Save dreamlayers/d0b2bd2318b83ed903fd to your computer and use it in GitHub Desktop.
NEC remote control protocol receiver for MSP430
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* mspremote - NEC remote control protocol receiver for MSP430 */ | |
/* by Boris Gjenero <[email protected]> */ | |
#include <stdbool.h> | |
#include <msp430.h> | |
#include <msp430g2252.h> | |
#define P1_LED1 0x01 | |
#define P1_REMOTE 0x10 | |
#define REMOTE_SHORT_MIN 400 | |
#define REMOTE_SHORT_MAX 700 | |
#define REMOTE_LONG_MIN 1500 | |
#define REMOTE_LONG_MAX 1800 | |
static unsigned char timer_overflow = 0; | |
static unsigned short last_transition = 0; | |
static unsigned char remote_bits; | |
static unsigned short remote_accumulator, remote_address, remote_command; | |
void static inline remote_abort(void) | |
{ | |
remote_bits = 0; | |
} | |
bool static inline remote_burst(unsigned short len) | |
{ | |
if (len > REMOTE_SHORT_MIN && len < REMOTE_SHORT_MAX) { | |
if (remote_bits == 16) { | |
remote_address = remote_accumulator; | |
} else if (remote_bits == 32) { | |
remote_command = remote_accumulator; | |
remote_bits = 0; | |
return true; | |
} | |
} else { | |
remote_abort(); | |
} | |
return false; | |
} | |
void static inline remote_space(unsigned short len) | |
{ | |
if (len > REMOTE_SHORT_MIN && len < REMOTE_SHORT_MAX) { | |
remote_bits++; | |
remote_accumulator >>= 1; | |
} else if (len > REMOTE_LONG_MIN && len < REMOTE_LONG_MAX) { | |
remote_bits++; | |
remote_accumulator >>= 1; | |
remote_accumulator |= 0x8000; | |
} else { | |
remote_abort(); | |
} | |
} | |
// Timer 0 vectored interrupt handler | |
#pragma vector = TIMER0_A1_VECTOR | |
__interrupt void Timer_A1_ISR(void) | |
{ | |
switch (__even_in_range(TA0IV, TA0IV_TAIFG)) { // Use calculated branching | |
case TA0IV_TACCR2: { | |
unsigned short taccr = TA0CCR2, len; | |
unsigned char port = P1IN; | |
len = taccr - last_transition; | |
last_transition = taccr; | |
/* After a single overflow, unsigned subtraction works fine. After | |
* multiple overflows, length is unknown but certainly too long. | |
* COV and CCIFG check avoids situations where the pin changed | |
* again since the change which triggered the interrupt, and the | |
* port value may be misleading. | |
*/ | |
if (timer_overflow < 2 && (TA0CCTL2 & (COV | CCIFG)) == 0) { | |
/* A space is high and a burst is low, but both are measured | |
* after they end, and the pin is in the opposite state. */ | |
if (port & P1_REMOTE) { | |
if (remote_burst(len)) LPM0_EXIT; | |
} else { | |
remote_space(len); | |
} | |
} else { | |
TA0CCTL2 &= ~COV; | |
remote_abort(); | |
} | |
timer_overflow = 0; | |
break; | |
} | |
case TA0IV_TAIFG: | |
if (timer_overflow == 0) { | |
timer_overflow = 1; | |
} else { | |
timer_overflow = 2; | |
} | |
break; | |
} | |
} | |
int main(void) { | |
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer | |
DCOCTL = 0x00; // Set DCOCLK to 1MHz | |
BCSCTL1 = CALBC1_1MHZ; | |
DCOCTL = CALDCO_1MHZ; | |
P1DIR = P1_LED1; | |
P1SEL = P1_REMOTE; | |
P1SEL2 = P1_REMOTE; // Required to route input to TA0 | |
TA0CTL = TASSEL_2 | MC_2 | TACLR | TAIE; | |
TA0CCTL2 = CM_3 | SCS | CAP | CCIE; | |
__enable_interrupt(); | |
while (1) { | |
LPM0; | |
P1OUT ^= P1_LED1; | |
} | |
//return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment