#include #include #define Tbit 104 // (SMCLK = 1 MHz) / (baud rate = 9600 bps) #define __low_power_mode() __bis_SR_register(__SR_CPU_OFF | __SR_SCG0 | __SR_OSC_OFF) volatile unsigned char rxbit, txbit; // RX/TX bit counters, do NOT modify volatile unsigned short rxbuf, txbuf; // RX/TX buffers, do NOT modify volatile unsigned char rxfg; // received byte counter, reset manually volatile unsigned char rxdata; // last received byte void setup(void); void tx(unsigned char txbuf); void tx_16u(unsigned short datas); void setup(void) { WDTCTL = WDTPW + WDTHOLD + WDTTMSEL; // stop watchdog timer, interval timer mode, SMCLK source // Basic Clock Module+ DCOCTL = CALDCO_1MHZ; BCSCTL1 = CALBC1_1MHZ; BCSCTL2 = SELM_0 + DIVM_0 + DIVS_0; // MCLK = DCOCLK/1, SMCLK = DCOCLK/1, internal DCO resistor // Digital I/O P1SEL = P1SEL_1 + // RXD P1SEL_2; // TXD P1DIR = P1DIR_2; // TXD // Timer_A software UART TACTL = TASSEL_2 + ID_0 + MC_2 + TACLR; // SMCLK/1 source, continuous, clear timer TACCTL0 = CM_2 + CCIS_0 + SCS + CAP + CCIE; // RX falling start edge, CCI0A input, synchronous capture, interrupt on TACCTL1 = OUTMOD_0 + OUT; // TX idle polarity rxbit = 0x08; // initialize 8 data bits __bis_SR_register(GIE); } // Transmit 1 byte to software UART void tx(unsigned char txdata) { if (TACCTL1 & CCIE) { __low_power_mode(); // wait for previous TX to complete } TACCR1 = TAR + Tbit; // set next interrupt time TACCTL1 = OUTMOD_1 + CCIE; // compare, mark start bit, interrupt off txbit = 0x0A; // initialize 1 start, 8 data, 1 stop bits txbuf = txdata + 0x100; // add mark start bit txbuf = txbuf << 1; // add space stop bit } // Transmit 5-digit unsigned short < 65535 as ASCII to software UART void tx_16u(unsigned short datas) { tx((datas / 10000) % 10 + '0'); tx((datas / 1000) % 10 + '0'); tx((datas / 100) % 10 + '0'); tx((datas / 10) % 10 + '0'); tx((datas / 1) % 10 + '0'); } // Timer_A1 interrupt service routine to transmit 1 byte to software UART #pragma vector = TIMERA1_VECTOR __interrupt void TIMERA1(void) { switch (__even_in_range(TAIV, 10)) { case TAIV_CCIFG1: if (txbit == 0) { // TX complete TACCTL1 &= ~CCIE; // disable further interrupts __low_power_mode_off_on_exit(); } else { TACCR1 += Tbit; // set next interrupt time if (txbuf & 0x01) { TACCTL1 &= ~OUTMOD_4; // mark bit (set output mode 1) } else { TACCTL1 |= OUTMOD_4; // space bit (reset output mode 5) } txbuf = txbuf >> 1; --txbit; } break; } } // Timer_A0 interrupt service routine to receive 1 byte from software UART #pragma vector=TIMERA0_VECTOR __interrupt void TIMERA0(void) { TACCR0 += Tbit; // set next interrupt time if(TACCTL0 & CAP) { // falling start edge captured TACCTL0 &= ~CAP; // set to sample input bit TACCR0 += Tbit / 2; // latch at middle of bit period } else { rxbuf = rxbuf >> 1; if (TACCTL0 & SCCI) { rxbuf |= 0x80; // save latched bit } --rxbit; if (rxbit == 0) { // RX complete TACCTL0 |= CAP; // set to capture start bit rxbit = 0x08; // initialize 8 data bits ++rxfg; rxdata = rxbuf; __low_power_mode_off_on_exit(); } } } // http://www.mrkenneth.com