Need Help Understanding pulseIn Behaviour

Hi,

I have an input of several digital pulses. I want to measure the duration of each of the high parts.

I tried to use the the pulseIn function in the following way:

for (int i=0; i<N; i++)
    data[i] = pulseIn(pin, HIGH);

The problem is that it seems that this code skips half of the pulses

When I tried to read the pulses manually (busy waiting and the use of micros() function) I got correct results.

So I tried to dig into pulseIn’s implementation but was not able to understand why this behaviour occurs.

/* Measures the length (in microseconds) of a pulse on the pin; state is HIGH
 * or LOW, the type of pulse to measure.  Works on pulses from 2-3 microseconds
 * to 3 minutes in length, but must be called at least a few dozen microseconds
 * before the start of the pulse. */
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
	// cache the port and bit of the pin in order to speed up the
	// pulse width measuring loop and achieve finer resolution.  calling
	// digitalRead() instead yields much coarser resolution.
	uint8_t bit = digitalPinToBitMask(pin);
	uint8_t port = digitalPinToPort(pin);
	uint8_t stateMask = (state ? bit : 0);
	unsigned long width = 0; // keep initialization out of time critical area
	
	// convert the timeout from microseconds to a number of times through
	// the initial loop; it takes 16 clock cycles per iteration.
	unsigned long numloops = 0;
	unsigned long maxloops = microsecondsToClockCycles(timeout) / 16;
	
	// wait for any previous pulse to end
	while ((*portInputRegister(port) & bit) == stateMask)
		if (numloops++ == maxloops)
			return 0;
	
	// wait for the pulse to start
	while ((*portInputRegister(port) & bit) != stateMask)
		if (numloops++ == maxloops)
			return 0;
	
	// wait for the pulse to stop
	while ((*portInputRegister(port) & bit) == stateMask) {
		if (numloops++ == maxloops)
			return 0;
		width++;
	}

	// convert the reading to microseconds. The loop has been determined
	// to be 20 clock cycles long and have about 16 clocks between the edge
	// and the start of the loop. There will be some error introduced by
	// the interrupt handlers.
	return clockCyclesToMicroseconds(width * 21 + 16); 
}

When the first pulseIn is called the pin is low so it will skip the first “while” loop and wait on the second. When the pin becomes high it will start to count and wait on the third while loop, until the pin becomes low again.

When the second pulseIn is called, the pin is low, so it should work exactly like the first one.

And so on with the other pulses.

I do not understand why it does not work. :~

What is sending the pulses that you are trying to measure? Perhaps your assumption that the pin is still LOW is not valid.

The pulses are produced by a DTH11 sensor.

Here is the code that compares pulseIn with busy waiting:

/* Testing pulseIn versus busyWait */

const int            PIN     = 7; 
const unsigned long  TIMEOUT = 4000;
const int            N       = 41;

unsigned long data[N] = {0};

void setup() {
  Serial.begin(9600);
}

void loop() {
 
  pulseIn_Test();
  printResults();

  delay(1000*5);
  
  busyWait_Test();
  printResults();
  
  delay(1000*15);
}


void pulseIn_Test() {
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN, LOW);
  delayMicroseconds(18000); // 18ms according to datasheet
  digitalWrite(PIN, HIGH);

  pinMode(PIN, INPUT);
  
  for (int i=0; i<N; i++)
    data[i] = pulseIn(PIN, HIGH, TIMEOUT);
}

void busyWait_Test() {
  pinMode(PIN, OUTPUT);
  digitalWrite(PIN, LOW);
  delayMicroseconds(18000); // 18ms according to datasheet
  digitalWrite(PIN, HIGH);

  pinMode(PIN, INPUT);
  
  busyWait(PIN, LOW);  // 20us-30us untill changes to low
  busyWait(PIN, HIGH); // 80us untill changes to high
  busyWait(PIN, LOW);  // 80us untill changes to low
  
  
  for (int i=0; i<N; i++) {
    busyWait(PIN, HIGH); // will be low for 50us
    data[i] = busyWait(PIN, LOW); // will be high for 24us or 70us
  }
}





void printResults() {
  Serial.println("Results:");
  for (int i=0; i<N; i++) {
    Serial.print(data[i]);
    Serial.print("\t");
    if (i%10 == 9)
      Serial.println("");
  }
  Serial.println("");
}




/* Porpuse: 
 *   Wait until the digital value of the pin is changed to a desired value. 
 *   Will wait until value changes or untill timeout.
 * Parameters:
 *   pin   - The pin number.
 *   value - The logical value to wait for.
 * Return:
 *   The time spent inside the busy wait. Will return 0 on timeout.
 */
unsigned long busyWait(int pin, int value) {
  unsigned long t = micros();
  while(digitalRead(pin) != value ){ 
    if ((micros() - t) >= TIMEOUT) 
      return 0; 
  }
  return micros() - t;
}

The results are:

Results:
85	24	24	73	73	24	24	24	24	24	
74	73	73	24	24	24	24	24	74	73	
24	0	0	0	0	0	0	0	0	0	
0	0	0	0	0	0	0	0	0	0	
0	
Results:
16	20	72	12	20	72	72	68	16	24	
24	16	20	24	24	12	24	24	16	80	
12	80	72	68	24	24	12	24	24	16	
16	24	12	24	72	72	72	68	72	16	
0

The pulses are produced by a DTH11 sensor.

A link to this mysterious sensor?

Sorry, I though that this sensor is well known.

Here is it's data-sheet: http://www.micro4you.com/files/sensor/DHT11.pdf

There are libraries around for reading that sensor. No interrupts, no pulseIn. Why are you trying to read pulses?

Thank you for the patience answering my questions.

I am aware that there are libraries for working with this sensor, but my problem is not with working with the sensor, but with understanding what the pulseIn actually does.

I am trying to learn by implementing the communication with the sensor myself, trying different ways, comparing ,experimenting...

Given that you have no control over when that sensor will send a pulse, I can't see that your assertion that the pin will remain LOW between calls to pulseIn() is valid.

There are two possible causes for pulseIn(PIN, HIGH) to return. One is timeout, the other is that the pin is LOW (it count how long the pin is at HIGH state). Therefore if I call pulseIn(PIN, HIGH) twice, one after another, thren at the beginning of the second pulseIn call the pin must be at LOW.

That is of course unless there is a delay larger than 50us at the beginning of pulseIn. From how I understand the code, I think it is not true.

Anybody? :blush:

What do you think the results of your experiment are showing there ? Should those two sets of numbers be the same ?

Yes, the first result which uses pulseIn is wrong, it reads only half of the pulses. I think that It reads pulses at the odd places (excluding the first 85 which is unrelated).

I am sure that the problem is my understanding of the logic of pulseIn or the way I use it.

If pulseIn's logic was what I am thinking is it's logic, both results should have been the same (up to the 85 pulse at the beginning).