// Time domain reflectometer const int stepPin = 4; // digital output pin we generate the step on. Later in the code, we assume this is port D bit 4. const int refPin = 11; // PWM output pin that we use to generate the comparator reference voltage. Must be on timer 2. const int shutdownPin = 7; // digital output port used to put comparator in shutdown mode - drive HIGH before sleeping const int maxSteps = 4; // maximum number of steps in each direction that we capture // Define the fraction of the speed of light at which waves propagate in the cable // Some typical values; // cat 5 cable 68% // RG58 or RG213 coax (solid polyethylene dieletric) 66% // Airspaced coax up to 92% const float propagationFactor = 0.68; // fraction of speed of light that waves travel in the cable under test void setup() { pinMode(stepPin, OUTPUT); pinMode(refPin, OUTPUT); pinMode(shutdownPin, OUTPUT); TCCR1A = 0; TCCR1B = (1 << ICNC1); // input capture noise canceller enabled, capture on falling edge TIMSK1 = 0; // timer 1 interrupts disabled ACSR = 0; // input capture from ICP1 pin TCCR2B = (1 << CS20); // change timer 2 PWM frequency to 31.25kHz because we're using pin 11 as a DAC Serial.begin(19200); } struct Step { unsigned int time; unsigned int amplitude; }; // Take a single measurement, using either a positive or negative edge from the comparator. // The comparator reference voltage must have been set up and allowed to stablise before calling this. unsigned int takeMeasurement(bool posEdge) { byte reg1b = (posEdge) ? 0 : (1 << ICES1); // input capture noise canceller csdisabled, set up input capture polarity, stop timer reg1b |= (1 << CS10); TCCR1B = reg1b; TCNT1H = 0; TCNT1L = 0; // clear timer unsigned int capture = 0; unsigned long start = micros(); // get the time cli(); TCNT1H = 0; TCNT1L = 0; // clear timer TIFR1 = (1 << ICF1); // clear timer 1 input capture bit PORTD |= (1 << 4); // set output high sei(); do { if ((TIFR1 & (1 << ICF1)) && capture == 0) { byte temp = ICR1L; capture = (ICR1H << 8) | temp; } } while (micros() - start < 100); PORTD &= ~(1 << 4); // set output low return capture; } size_t findSteps(bool positive, struct Step *results, size_t maxResults) { byte amplitude = (positive) ? 5 : 250; analogWrite(refPin, amplitude); delay(100); // wait 100ms for the output to stabilise unsigned int lastReading = 0; size_t numResults = 0; unsigned int stepSize = 0; // 0 means not in a step #ifdef DEBUG Serial.print((positive) ? "pos " : "neg "); #endif for (int i = 0; i < 50; ++i) { analogWrite(refPin, amplitude); delay(10); unsigned int currentReading = takeMeasurement(positive); unsigned int currentDiff = currentReading - lastReading; // diff since start of possible step if (stepSize == 0) { // Not currently in a step if (i != 0 && currentReading != 0 && currentDiff == 0) { // Found the start of a possible step ++stepSize; } lastReading = currentReading; } else { if (currentDiff > 2 || i + 1 == 50) { // Step has endeed, so record it if it is big enough if (stepSize >= 2) { results->time = lastReading; results->amplitude = amplitude - 5; ++results; ++numResults; if (numResults == maxResults) break; } stepSize = 0; lastReading = currentReading; } else if (currentDiff == 0) { ++stepSize; } } #ifdef DEBUG if (i != 0) Serial.write(','); Serial.print(currentReading); #endif if (positive) { amplitude += 5; } else { amplitude -= 5; } } #ifdef DEBUG Serial.println(); #endif return numResults; } // Convert a number of clocks delay to a cable length in metres float clocksToMetres(unsigned int clocks) { float delayTime = (float)clocks/(float)F_CPU; // delay in seconds float distance in metres= (delayTime * 3.0e8 * propagationFactor)/2.0; Serial.print("distance in metres: "); return (distance in metres); } // Diagnose the cable condition. We have the following common possibilities: // 1. No cable connected, or a very short open-circuit cable connected. // In this case we should see the original positive step, very close to zero delay, with amplitude nearly 5V. // 2. Direct short, or very short cable with shorted end. // In this case, we will not even see the original positive-going step, or it will have a very low amplitude. // 3. Cable with open circuit. // We see the original positive step close to zero delay, and a further positive step going to nearly twice the amplitude later. // 4. Cable with short circuit. // We see the original positive step close to zero delay, and a negative step going back down to nearly zero later. // 5. Correctly terminated cable. // We see only the original positive step, with amplitudfe well below 5V. void loop() { Step posSteps[maxSteps], negSteps[maxSteps]; size_t numPosSteps = findSteps(true, posSteps, maxSteps); size_t numNegSteps = findSteps(false, negSteps, maxSteps); if (numPosSteps == 0) { Serial.print("Direct short"); } else if (numPosSteps == 1 && numNegSteps == 0) { if (posSteps[0].amplitude >= 200) { Serial.print("No cable connected"); } else { Serial.print("Cable correctly terminated"); } } else if (numPosSteps >= 2 && numNegSteps == 0) { Serial.print("Open at "); Serial.print(clocksToMetres(posSteps[1].time - posSteps[0].time), 1); } else if (numPosSteps == 1 && numNegSteps == 1) { Serial.print("Short at "); Serial.print(clocksToMetres(negSteps[0].time - posSteps[0].time), 1); } else { Serial.print("Failed to diagnose fault"); } #ifdef DEBUG Serial.print(" (pos="); for (size_t i = 0; i < numPosSteps; ++i) { if (i != 0) { Serial.write(','); } Serial.print(posSteps[i].time); Serial.write('|'); Serial.print(posSteps[i].amplitude); } Serial.print(" neg="); for (size_t i = 0; i < numNegSteps; ++i) { if (i != 0) { Serial.write(','); } Serial.print(negSteps[i].time); Serial.write('|'); Serial.print(negSteps[i].amplitude); } Serial.println(")"); #else Serial.println(); #endif }