int value = 0; // value received from caliper unsigned char clock_active = 0; // any clock activity during last 32msec? unsigned char ready_for_data = 0;// idle between clock burts, ready for next one unsigned char bits_so_far = 0; // current bit count during value "assembly"
// how many CPU cycles between bits #define Bitime 104 //9600 Baud, SMCLK=1MHz (1MHz/9600)=104 unsigned char BitCnt; // Bit count, used when transmitting byte unsigned int TXByte; // Value sent over UART when Transmit() is called
#define LED BIT0 // LED on P1.0 #define TXPIN BIT1 // RS232 TX on P1.1 #define CLOCK BIT4 // Clock on P1.4 #define DATA BIT5 // Data on P1.5
void Transmit(void);
void main(void) { DCOCTL = 0x00; // Safe Flow BCSCTL1 = CALBC1_1MHZ; // run at 1Mhz DCOCTL = CALDCO_1MHZ;
//WDT as 32 ms interval counter. If no action on clock withing 32msec, // we are ready to receive next "number" WDTCTL = WDT_MDLY_32; // default timer 32 msec IE1 |= WDTIE; // Enable WDT interrupt
P1DIR |= LED; // Set P1.0 to output direction P1OUT |= LED; // LED ON, we'r ready P1SEL |= TXPIN; P1DIR |= TXPIN; // Set P1.1 to output direction
// Set up CLOCK input pin P1DIR &= ~CLOCK; // sets input direction P1OUT |= CLOCK; // pull-up is selected P1REN |= CLOCK; // pull-up/pull-down enabled P1IES &= ~CLOCK; // interupt triggered on low-to-high P1IFG &= ~CLOCK; // reset interup flag to 0. needs to be reset on start P1IE |= CLOCK; // interupt enabled for CLOCK
// Set up DATA input pin P1DIR &= ~DATA; // sets input direction P1OUT |= DATA; // pull-up is selected P1REN |= DATA; // pull-up/pull-down enabled P1IES &= ~DATA; // interupt triggered on low-to-high P1IFG &= ~DATA; // reset interup flag to 0. nneds to be reset on start P1IE &= ~DATA; // interupt disabled for DATA
// sending something over serial while (1) { __bis_SR_register(LPM0_bits + GIE);
// after we went into low power mode, program counter is at this instruction // (next one after where you entered LPM), but it's not moving until you enable active mode // within main loop. That can be done with __bic_SR_register_on_exit(LPM0_bits) in ISR _NOP();
// seding next value. value has been assambled by CLOCL interupt function // value is 16 bit, TXByte should be 8, sending in two parts TXByte = value >> 8; // first byte (most significant bits) Transmit(); TXByte = value & 0xFF; // second byte (least significant) Transmit(); P1OUT ^= LED; // blink LED } }
// Function Transmits Character from TXByte void Transmit() { CCTL0 = OUT; // TXD Idle as Mark TACTL = TASSEL_2 + MC_2; // SMCLK, continuous mode
CCR0 += Bitime; // Set time till first bit TXByte |= 0x100; // Add stop bit to TXByte (which is logical 1) TXByte = TXByte << 1; // Add start bit (which is logical 0)
CCTL0 = CCIS0 + OUTMOD0 + CCIE; // Set signal, intial value, enable interrupts while ( CCTL0 & CCIE ); // Wait for TX completion TACTL = TASSEL_2; // SMCLK, timer off (for power consumption) }
// Timer A0 interrupt service routine. Used to send bits over RS232 #pragma vector=TIMERA0_VECTOR __interrupt void Timer_A (void) { CCR0 += Bitime; // Add Offset to CCR0 if ( BitCnt == 0) // If all bits TXed, disable interrupt CCTL0 &= ~ CCIE; else { CCTL0 |= OUTMOD2; // TX Space if (TXByte & 0x01) CCTL0 &= ~ OUTMOD2; // TX Mark TXByte = TXByte >> 1; BitCnt --; } }
port = P1IN; // read DATA port value as soon as possible (otherwise it might be gone)
P1IFG &= ~CLOCK; // Clear interrupt flag clock_active = 1;
if (ready_for_data) { if (bits_so_far && bits_so_far <= 16){ // first bit is start bit, ignore it. Total we have 24 bits. But we need only 16 if (!(port & DATA)) // if 0 recived, invert = >1 value |=0x8000; // then set most significant bit value = value >> 1; // and move it one right }else if (bits_so_far == 21){ // 21st bit indicates sighn (+/-) if (!(port & DATA)) value = (~value)+1; // make it negative }else if (bits_so_far >= 23){ // we'r done, got all bits ready_for_data = 0; // warchdog timer will set it __bic_SR_register_on_exit(LPM0_bits); // wake up main from LPM sleep } bits_so_far++; } }
// watchdog used as 30msec timer for detecting start of new bit burst on clock #pragma vector=WDT_VECTOR __interrupt void WDT_ISR(void) { if (ready_for_data) return;
if (clock_active){ clock_active = 0; // clear flag, will wait another 32msec to see if there have been any activity of clock ready_for_data = 0; // not yet ready }else{ ready_for_data = 1; // nothing within last 32msec, ready for next clock burst value = 0; // init of value bits_so_far = 0; // init of bit counter }