📄 wm430_transmitter.c
字号:
}
if (WM430_TX_pendingMsgs < WM430_TX_QUEUEMSGMAX)
WM430_TX_pendingMsgs++; // Increment pending messages counter
else
debug_dropped_messages++; // Increment dropped messages counter
}
// _______________________________________________________________
// Miller Encoding (Delay Modulation) Scheme: Implementation Logic
// _______________________________________________________________
//
// CURRENT BIT | NEXT BIT | ACTIONS FOR TIMER ISR (will occur at 100 usec resolution intervals if data needs to be sent)
// ----------------------------------------------------------------------------------------------------------------------------------
// 0 | 0 | Toggle rfState; set next Timer interrupt for 200 usec later
//
// 0 | 1 | Toggle rfState; set next Timer interrupt for 300 usec later
//
// 1 | 0 | Do Nothing; set next Timer interrupt for 100 usec later
//
// 1 | 1 | Toggle rfState; set next Timer interrupt for 200 usec later
// ----------------------------------------------------------------------------------------------------------------------------------
//
// Timer_A3 Interrupt Service Routine
#pragma vector=TIMERA0_VECTOR
__interrupt void TIMERA0_ISR(void)
{
unsigned char temp1, temp2, temp3;
// This routine sets the timing of the bits transmitted on the RF link. In order to have
// low jitter and accurate edge to edge spacing, we want to set the next data state early
// in this routine and restart the timer for the appropriate width early in this routine.
// That means we have to have previously calculated them.
// Determine if RF_DATA pin needs to be set to physical level high or low then set it!
// To avoid jitter problems, do not move this section of code (leave it at the beginning of the ISR)
if (WM430_TX_rfState)
P2OUT |= TX_CTRL2;
else
P2OUT &= ~TX_CTRL2;
// Original Thinking:
// Restart the timer so the next edge will happen at the right time.
// To avoid jitter problems, do not move this section of code (leave it at the beginning of the ISR)
// Latest Thinking:
// Actually it may not matter whether we restart the timer early. It depends on whether
// it counts down to negative numbers after the interupt occurs in which case we can add
// the delta anytime before exiting the ISR with the same results. On the other hand if it
// counts down to 0 and stays at 0 it's important to add the new timer value as soon as possible.
// I think it's the former case, so I moved the timer restart to the end of the routine. The same
// jitter resulted.
// FCLK Nom_bit JitterBit HowLongForThisISR AvgIdd1.5VMovingRefGray Iddw/oRFboard
// ---------------------------------------------------------------------------------------
// 1.0MHz 24.8mA 8.3mA
// 2.0MHz 205us >35us pp <95.2us 24.8mA 9.7mA
// 2.2MHz 204us >37us pp <82.4us 24.8mA- 9.7mA
// 2.5MHz 205us >28us pp <72.4us 25.0mA 10.0mA
// 3.0MHz 203us >24us pp <60.8us 24.1mA 10.7mA
// 4.0MHz 206us >25us pp <51.0us 25.6mA 10.6mA
// TACCR0 += WM430_TX_rfWidth; // see end of ISR
// Now we can take our time and calculate what the next bit state and duration will be.
// As long as we finish in less than the shortest pulse width (<200us @ 5000 bps) we will be fine
// Check if we're still in the STOP pattern sending phase
if (WM430_TX_stopPatternBitNum == 0) { // Stop pattern for current message has finished
if (WM430_TX_pendingMsgs > 0) // Make sure mesgs counter is not currently at 0
WM430_TX_pendingMsgs--; // Decrement pending mesgs counter only if non-zero (we've finished the message)
WM430_TX_dataIdle(); // Return data line to the default IDLE state
// Save last bit history
TA0V_currentTxBit = WM430_TX_CURRENTTXBITDEFAULT;
TA0V_currentTxPtr++; // Increment current Tx pointer
if (TA0V_currentTxPtr >= WM430_TX_QUEUEMSGMAX)
TA0V_currentTxPtr = 0; // Reset current Tx pointer
if (WM430_TX_pendingMsgs != 0) { // Any more messages to send?
// Yes, prepare & create a delay gap before start of next mesg
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_10;
// Reset bit counters
WM430_TX_startPatternBitNum = WM430_TX_STARTPATTERNPREAMBLENUMBITS;
WM430_TX_syncPatternBitNum = WM430_TX_SYNCPATTERNNUMBITS;
WM430_TX_stopPatternBitNum = WM430_TX_STOPPATTERNNUMBITS;
goto isr_exit; // Leave the transmitter ON
}
else { // No more pending messages
WM430_TX_disableInt(); // Disable Tx Interrupt for now
WM430_TX_disableRF(); // No messages left to send; turn off the Transmitter module
WM430_TX_dataIdle(); // Return data line to the default IDLE state
WM430_TX_dataHI(); // Leave this variable high for a consistent start pattern
goto isr_exit; // Exit the ISR
}
}
if (WM430_TX_stopPatternBitNum < WM430_TX_STOPPATTERNNUMBITS) {
if (WM430_TX_stopPatternBitNum > 1) // Need to start sending stop bits
WM430_TX_dataToggle();
else
WM430_TX_dataLO(); // The last stop bit will be prematurely squashed to low
// so go low in advance to avoid runt pulses
// Check status of last data bit
if (WM430_TX_stopPatternBitNum == (WM430_TX_STOPPATTERNNUMBITS-1)) {
if (WM430_TX_rfState) { // Next data bit is a logical '1' [1, 1]
WM430_TX_rfWidth = (TIMERA0_SMCLK_BITPERIOD_05 + TIMERA0_SMCLK_BITPERIOD_10);
}
else { // Next data bit is a logical '0' [0, 1]
WM430_TX_rfWidth = (TIMERA0_SMCLK_BITPERIOD_05 + TIMERA0_SMCLK_BITPERIOD_15);
}
}
else { // Remainder of the stop bits (2 thru N)
// will be all 1's so space them equally apart
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_10;
}
WM430_TX_stopPatternBitNum--;
goto isr_exit; // Exit the ISR
}
if (WM430_TX_keyOnPeriodBitNum) { // Check if new beginning of Tx On Period
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_10;
WM430_TX_dataToggle(); // To represent Miller encoded 1's
WM430_TX_keyOnPeriodBitNum--; // Decrement the # of front-end garbage bits
goto isr_exit; // Exit the ISR
}
if (WM430_TX_startPatternBitNum) { // Check if we're still in the preamble START pattern sending phase
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_10;
WM430_TX_dataToggle(); // To represent Miller encoded 1's
WM430_TX_startPatternBitNum--; // Decrement the # of start bits remaining
goto isr_exit; // Exit the ISR
}
else { // Finished sending start pattern bits
if (WM430_TX_syncPatternBitNum) { // Still have sync bits to shift out ?
switch (WM430_TX_syncPatternBitNum) {
case 6: case 5: case 4: case 2:
WM430_TX_dataLO(); // Physically set data lineLOW
break;
case 3: case 1:
WM430_TX_dataHI(); // Physically set data line HIGH
break;
default: break;
}
WM430_TX_syncPatternBitNum--; // Decrement sync pattern bit number
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_10;
goto isr_exit; // Exit the ISR
}
} // The variable data part of each packet is shifted out here
// When this part of the ISR is reached, all start/sync/preamble bits have been scheduled
// Look at current & next bits [x, y] to set data line & time interval for next interrupt
TA0V_nextTxBit = (((WM430_TX_mesgQueue[TA0V_currentTxPtr].byte8bits[TA0V_bytePtr]) << TA0V_shiftCounter) & BIT7);
if (TA0V_nextTxBit) { // Ucoming data bit is a logical '1'. We definitely toggle now, but if the
// bit after this is a 0 we won't be toggling for that bit, but rather waiting
// an extra 100us. To avoid use of 100us as a timer value (which allows
// lower CPU clock and lower power),let's check and see whether the next bit is a 0
// If so, we can bump the timer ahead 100us and increment the bit pointer an extra position
WM430_TX_dataToggle();
if (TA0V_currentTxBit) { // Crrent data bit is a logical '1' [1, 1]
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_10;
}
else { // Crrent data bit is a logical '0' [0, 1]
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_15;
}
}
else { // Ucoming data bit is a logical '0'
if (TA0V_currentTxBit) { // Crrent data bit is a logical '1' [1, 0]
// If we get here, no toggle due to [1,0] but peek ahead at the next next bit
// First find the "next next" bit and byte position
temp1 = TA0V_shiftCounter + 1 ; // Iitialize temp1 variable and increment the value
temp2 = TA0V_bytePtr; // Iitialize temp2 variable
if (temp1 == WM430_TX_BITSPERBYTE) {
temp1 = 0; // Rset temp1 variable
temp2++; // Icrement temp2 variable
}
if (temp2 == TXPACKET_MAXBYTES) { // Check to see if there is a next,next data bit or not
TA0V_bytePtr = 0;
// At this point all data in current Tx packet has been sent
// Signal to our own thread that we need to generate STOP condition
// Leave the bit pointers in a state that will trigger
// end of data package detection further down
temp1 = WM430_TX_BITSPERBYTE - 1;
temp2 -= 1;
temp3 = 1; // Nte the next next bit will be a 1 (stop bit)
}
else { // Peek ahead @ next bit - put it in temp3
temp3 = (((WM430_TX_mesgQueue[TA0V_currentTxPtr].byte8bits[temp2]) << temp1) & BIT7);
}
TA0V_shiftCounter = temp1; // Note for next time which bit we've moved to
TA0V_bytePtr = temp2; // Store byte pointer value
TA0V_nextTxBit = temp3; // Store value of next bit to be tx'd
WM430_TX_dataToggle(); // Physically toggle the data line
if (temp3 == 0)
// [1,0,0] <half+whole> bit periods
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_15;
else // [1,0,1] <half+one-and-a-half> bit periods
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_10 << 1;
}
else { // Crrent data bit is a logical '0' [0, 0]
WM430_TX_dataToggle(); // Physically toggle the data line
WM430_TX_rfWidth = TIMERA0_SMCLK_BITPERIOD_10;
}
}
TA0V_currentTxBit = TA0V_nextTxBit; // Save last bit history
// *****************************************************************************************
// Update pointer variables for next start of bit period
TA0V_shiftCounter++; // Increment the shfit counter
if (TA0V_shiftCounter == WM430_TX_BITSPERBYTE) {
TA0V_shiftCounter = 0; // Reset shift counter (wrap-around)
TA0V_bytePtr++; // Increment byte pointer
if (TA0V_bytePtr == TXPACKET_MAXBYTES) {
TA0V_bytePtr = 0; // Reset byte pointer (wrap-around)
// At this point all data in current Tx packet has been sent
WM430_TX_stopPatternBitNum--; // Signal to our own thread that we need to generate STOP condition
TA0V_currentTxBit = WM430_TX_CURRENTTXBITDEFAULT;
}
else
goto isr_exit; // Exit the ISR
}
else
goto isr_exit; // Exit the ISR
isr_exit:
TACCR0 += WM430_TX_rfWidth; // Add time to the timer so the next interrupt occurs at the right time
// Here's a good place for debug pulses to time the duration of this ISR
}
#else /* _FSKDATAPLUSENCODING */
void WM430_TX_sendDataPacket(unsigned char BUTTON, signed char XDISP, signed char YDISP, signed char ZDISP)
{
WM430_TX_DataPacket data;
data.field.button = BUTTON; // Transfer button data
data.field.horizontal = XDISP; // Transfer X displacement value
data.field.vertical = (~YDISP + 1); // Convert to 2's complement before sending over
data.field.zwheel = ZDISP; // Transfer Z displacement value
data.field.dummy5 = 0; // NOT USED
data.field.dummy4 = 0; // NOT USED
data.field.dummy3 = 0; // NOT USED
data.field.dummy2 = 0; // NOT USED
data.field.dummy1 = 0; // NOT USED
data.field.dummy0 = 0; // NOT USED
WM430_SYS_delaymsec(1); // Delay enough time to allow packet to be transmitted
}
#endif /* _FSKDATAPLUSENCODING */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -