Measuring PWM width with pulsein()

Hi
I'm in a project where we have a PWM signal with 3 pulses containing information is coming in, I would want to store them and then print them out. The pulses are 22-88ms in length. I have recently discovered pulseIn() and that would be a smart way to record the "HIGH"-time of the pulses?
Any recommendations on how to program this?

Problem with pulsIn() is it's a blocking function. So while waiting fr the pulse to finish you can't do anything.

22-88ms is a reasonable length. Just connect them to an external interrupt (or use pin change interrupt even) and use millis() to determine the length of the pulse (if resolution is sufficient). millisWhenFalling - millisWhenRising = pulsLength.

At times of 22-88 ms I'd prefer to use micros() to do the timing, unless you know what times to expect and just have to distinguish between them.

pulseIn() produces microseconds. It's indeed blocking. It will do the job for you but you can't do anything else during the time the pulseIn() runs.

You also probably don't know when the pulse arrives. That's another issue. PulseIn() times out after 1 second (can be extended - see documentation) but if you do so you're having the processor sit there waiting. If you set up an interrupt you don't have to worry about sitting and waiting for the pulse to arrive.

wvmarle:
At times of 22-88 ms I'd prefer to use micros() to do the timing, unless you know what times to expect and just have to distinguish between them.

pulseIn() produces microseconds. It's indeed blocking. It will do the job for you but you can't do anything else during the time the pulseIn() runs.

You also probably don't know when the pulse arrives. That's another issue. PulseIn() times out after 1 second (can be extended - see documentation) but if you do so you're having the processor sit there waiting. If you set up an interrupt you don't have to worry about sitting and waiting for the pulse to arrive.

This one I could manage, how would I then set that up? Setting a trigger when it's RISING and FALLING?
I'm using an arduino uno and use pin 13 as a input, would I have to use pin 2 instead?
Sorry for being a noob, I'm very new to programming :slight_smile:

No interrupts example:

unsigned long pulseStart;

void loop() {
  if (digitalRead(pulsePin) && havePulse == false) { // Start of pulse.
    havePulse = true;
    pulseStart = micros(); // millis() may do as well.
  }
  if (digitalRead(pulsePin) == LOW && havePulse) { // End of pulse.
    havePulse = false;
    pulseReceived = true;
    pulseLength = micros() - pulseStart;
  }
  if (pulseReceived) {
    dealWithIt();
  }
  doOtherStuff();
  doMoreStuff();
}

Probably good enough for your pulse length, but you must make sure the other functions are non-blocking, so no delay() or so.

wvmarle:
No interrupts example:

unsigned long pulseStart;

void loop() {
  if (digitalRead(pulsePin) && havePulse == false) { // Start of pulse.
    havePulse = true;
    pulseStart = micros(); // millis() may do as well.
  }
  if (digitalRead(pulsePin) == LOW && havePulse) { // End of pulse.
    havePulse = false;
    pulseReceived = true;
    pulseLength = micros() - pulseStart;
  }
  if (pulseReceived) {
    dealWithIt();
  }
  doOtherStuff();
  doMoreStuff();
}




Probably good enough for your pulse length, but you must make sure the other functions are non-blocking, so no delay() or so.

I guess I should declare havePulse and pulseReceived as Booleans?

Yes; and pulseLength as unsigned long. It's just an example, there's more undeclared stuff in there :slight_smile:

Hi guys, tested out this code, the problem is the only thing it prints out is 0's.

const int pulsePin = 2;
volatile unsigned long elapsed;
volatile unsigned long StartTime;
volatile unsigned long StopTime;

void setup() {
pinMode(pulsePin, INPUT);
Serial.begin(115200);
attachInterrupt(digitalPinToInterrupt(pulsePin), rising, RISING);
attachInterrupt(digitalPinToInterrupt(pulsePin), falling, FALLING);
}

void loop() {
Serial.println(StartTime);
Serial.println(elapsed);

}

void rising() {
StartTime=micros();
}
void falling() {
StopTime=micros();
elapsed=StopTime-StartTime;
}

That probably means you didn't see a pulse yet, as you're printing StartTime and elapsed all the time, pulse or no pulse.

As falling comes second, you should set a flag there that shows loop() that a pulse has been detected. For testing, do the same with rising(). Then print based on those flags.

const int pulsePin = 2;
volatile unsigned long elapsed = 0;
volatile unsigned long StartTime;
volatile unsigned long StopTime;
volatile bool sawRisingEdge = false;

void setup() {
  pinMode(pulsePin, INPUT);
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(pulsePin), rising, RISING);
  attachInterrupt(digitalPinToInterrupt(pulsePin), falling, FALLING);
}

void loop() {
  if (sawRisingEdge) { // Only print when a rising edge has been detected.
    sawRisingEdge = false;
    Serial.print (F("Detected rising edge at micros() = "));
    Serial.println(StartTime);
  }
  if (elapsed > 0) { // Only print when a subsequent falling edge has been detected.
    Serial.print(F("Falling edge followed "));
    noInterrupts();
    unsigned long e = elapsed; // always read >2 byte values with interrupts switched off.
    interrupts();
    Serial.print(e);
    Serial.println(F("µs later."));
    elapsed = 0;
  } 
}

void rising() {
  StartTime=micros();
  sawRisingEdge = 0;
}

void falling() {
  StopTime=micros();
  elapsed=StopTime-StartTime;
}

You can only assign a single function / mode to an interrupt.

So this:

 attachInterrupt(digitalPinToInterrupt(pulsePin), rising, RISING);
  attachInterrupt(digitalPinToInterrupt(pulsePin), falling, FALLING);

only attaches the falling interrupt...

Or use a single call back for rising and falling (CHANGE) or change the mode in the interrupt again.

Oh, didn't know that. Makes sense, though.
Then OP can better use a state check: digitalRead() in the ISR, base action on that. Should be fast enough to do in an ISR.