-
-
Notifications
You must be signed in to change notification settings - Fork 100
7. Interrupt Service Routine
(We have received an interrupt signal, what should we do?)
Passes off responsibility for the interrupt to the active object.
inline void SDI12::handleInterrupt(){
if (_activeObject) _activeObject->receiveChar();
}
This function quickly reads a new character from the data line in to the buffer. It takes place over a series of key steps.
7.2.1 - Check for the start bit. If it is not there, interrupt may be from interference or an interrupt we are not interested in, so return.
7.2.2 - Make space in memory for the new character "newChar".
7.2.3 - Wait half of a SPACING to help center on the next bit. It will not actually be centered, or even approximately so until delayMicroseconds(SPACING) is called again.
7.2.4 - For each of the 8 bits in the payload, read wether or not the line state is HIGH or LOW. We use a moving mask here, as was previously demonstrated in the writeByte() function.
The loop runs from i=0x1 (hexadecimal notation for 00000001) to i<0x80 (hexadecimal notation for 10000000). So the loop effectively uses the masks following masks:
- 00000001
- 00000010
- 00000100
- 00001000
- 00010000
- 00100000
- 01000000
- and their inverses.
Here we use an if / else structure that helps to balance the time it takes to either a HIGH vs a LOW, and helps maintain a constant timing.
7.2.5 - Skip the parity bit. There is no error checking.
7.2.6 - Skip the stop bit.
7.2.7 - Check for an overflow. We do this by checking if advancing the tail would make it have the same index as the head (in a circular fashion).
7.2.8 - Save the byte into the buffer if there has not been an overflow, and then advance the tail index.
void SDI12::receiveChar()
{
if (digitalRead(_dataPin)) // 7.2.1 - Start bit?
{
uint8_t newChar = 0; // 7.2.2 - Make room for char.
delayMicroseconds(SPACING/2); // 7.2.3 - Wait 1/2 SPACING
for (uint8_t i=0x1; i<0x80; i <<= 1) // 7.2.4 - read the 7 data bits
{
delayMicroseconds(SPACING);
uint8_t noti = ~i;
if (!digitalRead(_dataPin))
newChar |= i;
else
newChar &= noti;
}
delayMicroseconds(SPACING); // 7.2.5 - Skip the parity bit.
delayMicroseconds(SPACING); // 7.2.6 - Skip the stop bit.
// 7.2.7 - Overflow? If not, proceed.
if ((_rxBufferTail + 1) % _BUFFER_SIZE == _rxBufferHead)
{ _bufferOverflow = true;
} else { // 7.2.8 - Save char, advance tail.
_rxBuffer[_rxBufferTail] = newChar;
_rxBufferTail = (_rxBufferTail + 1) % _BUFFER_SIZE;
}
}
}
Check if the various interrupt vectors are defined. If they are the ISR is instructed to call _handleInterrupt() when they trigger.
#if defined(PCINT0_vect)
ISR(PCINT0_vect){ SDI12::handleInterrupt(); }
#endif
#if defined(PCINT1_vect)
ISR(PCINT1_vect){ SDI12::handleInterrupt(); }
#endif
#if defined(PCINT2_vect)
ISR(PCINT2_vect){ SDI12::handleInterrupt(); }
#endif
#if defined(PCINT3_vect)
ISR(PCINT3_vect){ SDI12::handleInterrupt(); }
#endif