Skip to content

7. Interrupt Service Routine

Kevin M. Smith edited this page Apr 8, 2014 · 4 revisions

(We have received an interrupt signal, what should we do?)

7.1 handleInterrupt()

Passes off responsibility for the interrupt to the active object.

inline void SDI12::handleInterrupt(){
  if (_activeObject) _activeObject->receiveChar();
}

7.2 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;
    }
  }
}

7.3 Interrupt Vectors

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

Clone this wiki locally