Go Down

Topic: Possible bug in pulseIn()? (Read 649 times) previous topic - next topic

JoakimCh

Hello! I'm new here (but not to programming btw).

It seems like pulseIn(pin,LOW) if it is ALREADY low will wait until it gets high and THEN low again before it measures the time it takes for it to get high after that. Okay, maybe it is hard to explain in a understandable way, but I had to rewrite the function to get the behavior I expected.

I was sitting for hours going insane at this weird behavior (at least weird to me).

If I must then I can show you my code...
It's a IR receiver I'm working on, my readings from the sensor is good and I would suspect the same behavior from these two code snippets I post below. But only the one where I wrote my own timing stuff instead of using pulseIn works as expected. And with "expected" I mean collecting timing data of the "on and off" pulses until the remote signals stopped.


This is where I tried using pulseIn to simplify things:
Code: [Select]
#define ir_pin 7

void setup() {
 pinMode(ir_pin,INPUT);
 Serial.begin(9600);
 Serial.println("Ready...");
}

unsigned long onDuration=0;
unsigned long offDuration=0;
unsigned int count=0;
unsigned int data[300];
unsigned long microseconds=0;
boolean timeout=false;

//LOW = IR light, HIGH = no IR light (that's how my IR receiver reads)
void loop() {
 onDuration = pulseIn(ir_pin,LOW);
 if (onDuration > 0) { //did it blink?
   data[count] = onDuration;
   count ++;
   
   microseconds = micros();
   while (digitalRead(ir_pin)==HIGH && timeout==false) { //messure delay between blinks
     if (micros()-microseconds > 10000) { //been off for a second or more
       timeout = true; //rather use break?
     }
   }
   if (timeout == false) {
     offDuration = micros()-microseconds;
     data[count] = offDuration;
     count ++;
   } else { //end of blinks, output data
     Serial.println("########################################");
     for (int i=0; i<count; i++) {
       Serial.println(data[i]);
     }
     count = 0;
     timeout = false;
   }
 }
 if (count > 298) {
   count = 0;
   Serial.println("too much data");
 }
}


This is the working code (when I decided to not use pulseIn for timing):
Code: [Select]
#define ir_pin 7

void setup() {
 pinMode(ir_pin,INPUT);
 Serial.begin(9600);
 Serial.println("Ready...");
}

unsigned long onDuration=0;
unsigned long offDuration=0;
unsigned int count=0;
unsigned int data[300];
unsigned long microseconds=0;
boolean timeout=false;
boolean wasLow=false;

//LOW = IR light, HIGH = no IR light (that's how my IR receiver reads)
void loop() {
 microseconds = micros();
 while (digitalRead(ir_pin)==LOW) { //messure delay between blinks
   wasLow=true;
 }
 if (wasLow==true) { //did it blink?
   onDuration = micros()-microseconds;
   wasLow=false;
 } else {
   onDuration = 0;
 }
 if (onDuration > 0) {
   data[count] = onDuration;
   count ++;
   
   microseconds = micros();
   while (digitalRead(ir_pin)==HIGH && timeout==false) { //messure delay between blinks
     if (micros()-microseconds > 100000) { //been off for a second or more
       timeout = true; //rather use break?
     }
   }
   if (timeout == false) {
     offDuration = micros()-microseconds;
     data[count] = offDuration;
     count ++;
   } else { //end of blinks, output data
     Serial.println("########################################");
     for (int i=0; i<count; i++) {
       Serial.println(data[i]);
     }
     count = 0;
     timeout = false;
   }
 }
 if (count > 298) {
   count = 0;
   Serial.println("too much data");
 }
}


As you see the only changes is a few lines over "if (onDuration > 0)". I may be crazy but shouldn't the snippets behave the same way? At least that would make sense to me.

fdufnews

To make accurate timing measure pulseIn should see the two edges of the pulse.

In the past pulseIn was working the way you are expected but as this was leading to unreliable measure it was reprogammed to wait for a first transition.

JoakimCh

Quote
it was reprogammed to wait for a first transition

Okay, thanks for the explanation, that I can respect.
But I think it should be noted in the reference page so other people will not waste hours on figuring out what happened like me.

Go Up