How to measure pulse duration of an analogue signal without pulseIn() function?

Hello,
I am very new in using Arduino and C++. I want to measure the pulse duration (positive only) of an analogue signal with high sampling rate (above the threshold amplitude value). I have the following program with sampling rate of 76.8 kHz. I compared the pulse duration of the signal from Oscilloscope and from the serial monitor. However, I did not get the right pulse duration from Arduino. Any suggestions/help regarding my sketch will be appreciated. Many thanks in advanced.

P.S. I am using Arduino UNO and a signal generator for the input signal.

int i;
unsigned long x;
unsigned long x1;
const int threshold = 20;
volatile unsigned long start_times;
volatile unsigned long stop_times;
unsigned long pulse;
void setup()
{
  Serial.begin(115200);

  ADCSRA = 0;             // clear ADCSRA register
  ADCSRB = 0;             // clear ADCSRB register
  ADMUX |= (0 & 0x07);    // set A0 analog input pin
  ADMUX |= (1 << REFS0);  // set reference voltage
  ADMUX |= (1 << ADLAR);  // left align ADC value to 8 bits from ADCH register

  // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                     // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

  ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADIE);  // enable interrupts when measurement complete
  ADCSRA |= (1 << ADEN);  // enable ADC
  ADCSRA |= (1 << ADSC);  // start ADC measurements
}

ISR(ADC_vect)
{
 //byte x= ADCH;  // read 8 bit value from ADC
 int x= ADCH;  // read 16 bit value from ADC. Max value 255.
 //Serial.println(x);
 if (x>threshold) {
    start_times = micros();
  }
 else 
  {
    stop_times = micros();
    pulse = (stop_times - start_times);
    Serial.println(pulse);
  }
 
}


void loop(){
   //
}

Serial I/O in interrupt context is not a Good Thing.

Many thanks for your comment AWOL. How can I avoid this?

Take the serial print out of the interrupt service routine.

 int x= ADCH;  // read 16 bit value from ADC. Max value 255.

Storing the 8 bits in an int does not make sense. Why are you doing that?

    start_times = micros();
    stop_times = micros();

Why are you using plural names for variables that are able to store a single value?

    pulse = (stop_times - start_times);

That value is a duration. Why does your variable name not reflect that?

Thanks Paul for your comments.
int x=ADCH // as I did not get correct result, I switch it to 'int' instead of 'byte'.
Is there any effect of plural names in the program? One is start time and one is stop time. Yes, each of these will store single value.
If I know what I am looking for then the name should not be a problem.

If I know what I am looking for then the name should not be a problem.

Sure, Joe, use whatever names you like.

Hello AWOL,
I made the following changes and using LCD to display the result. I got 64 ms whereas Oscilloscope is showing 68.14 ms. Any suggestion to make Arduino result accurate/ close to the Oscilloscope value.

int i;
unsigned long x;
const int threshold = 20;
volatile unsigned long t0;
volatile unsigned long t1;
unsigned long pulse_duration;

#include <LiquidCrystal.h>

LiquidCrystal lcd(7,8,9,10,11,12);
void setup()
{
  lcd.begin(16, 2);            // defines a LCD with 16 columns and 2 rows
  lcd.clear();
  //lcd.print("Pulse= ");
  //Serial.begin(115200);

  ADCSRA = 0;             // clear ADCSRA register
  ADCSRB = 0;             // clear ADCSRB register
  ADMUX |= (0 & 0x07);    // set A0 analog input pin
  ADMUX |= (1 << REFS0);  // set reference voltage
  ADMUX |= (1 << ADLAR);  // left align ADC value to 8 bits from ADCH register

  // sampling rate is [ADC clock] / [prescaler] / [conversion clock cycles]
  // for Arduino Uno ADC clock is 16 MHz and a conversion takes 13 clock cycles
  //ADCSRA |= (1 << ADPS2) | (1 << ADPS0);    // 32 prescaler for 38.5 KHz
  ADCSRA |= (1 << ADPS2);                     // 16 prescaler for 76.9 KHz
  //ADCSRA |= (1 << ADPS1) | (1 << ADPS0);    // 8 prescaler for 153.8 KHz

  ADCSRA |= (1 << ADATE); // enable auto trigger
  ADCSRA |= (1 << ADIE);  // enable interrupts when measurement complete
  ADCSRA |= (1 << ADEN);  // enable ADC
  ADCSRA |= (1 << ADSC);  // start ADC measurements
}

ISR(ADC_vect)
{
 byte x= ADCH;  // read 8 bit value from ADC
 if (x>threshold) {
    t0 = micros();
  }
 else 
  {
    t1 = micros();
    pulse_duration = (t1 - t0)/1000;  // in ms
    //Serial.println(pulse_duration);
  lcd.setCursor(0, 0);                 
  lcd.print(pulse_duration);
  //lcd.print("ms");
  } 
}

void loop(){
//  
}

jewelbd:
Many thanks for your comment AWOL. How can I avoid this?

Just set a flag (boolean variable) in your ISR to let the main loop know that you have a pulse duration value ready to print, then let the main loop take care of it.

if (x>threshold) {
    start_times = micros();
  }
 else
  {
    stop_times = micros();
    pulse = (stop_times - start_times);
    Serial.println(pulse);
  }

I think there is a logical error in the above code. After the waveform drops below the threshold the else clause will continually get executed every sample. You should only do that "else" code on the first time that the pulse falls below the threshold after it's been above.

You'll need to introduce some state variables to implement some "edge detection" logic.