Attempting to read duty cycle...

I have (2) different kinds of pressure transducers in my engine fleet that control engine throttles. I've recently found out that one of them is programmable; I can change the duty cycle with respect to air pressure. I want to make the transducers the same, as I am running engines in tandem with a single pneumatic throttle control valve.

I believe this tutorial I found will head me down the right road...

However, this only counts the "ON" time. I think I can use this and also program to count the total (ON and OFF) time, divide the ON time by the total time and have the duty cycle.

Is this easy enough, or is there a better way? It would be so much easier to do these tests in shop with an Arduino rather than having to hook up and "trial and error" in the field. Thanks.

However, this only counts the "ON" time.

From the linked reference:

pin: the number of the pin on which you want to read the pulse. (int)

value: type of pulse to read: either HIGH or LOW. (int)

timeout (optional): the number of microseconds to wait for the pulse to start; default is one second (unsigned long)

the length of the pulse (in microseconds) or 0 if no pulse started before the timeout (unsigned long)

Thanks. I thought you had to choose either ON or OFF, but if I can do both and add them together, that will work.

I thought you had to choose either ON or OFF

For any given call to pulseIn, you do.

I've copied the code exactly from the pulseIN example, but when I try to verify, it gives me an error - 'pulseIN' was not declared in this scope.
I have little to no programming experience. Is the pulseIN example I posted earlier missing something? Thanks.

Function names are case sensitive. pulseIn, pulseIN, and PulseIn are three different functions. The one that the Arduino understands is pulseIn.

Aaarrgghh. Can't believe I did that. Programming eats my lunch. Thanks a million.

Ok. Stumped again. Got my code to verify, but returns only zeros. I checked with multimeter, and I'm getting around 2.3 volts at pin 7. Is that too low for Arduino to recognize as high? Or, is the arithmetic function in my program screwed up? Thanks.

unsigned long time;
unsigned long duration;
int pin = 7;
in DutyCycle;

void setup()
pinMode(pin, INPUT);
void loop(){
duration = pulseIn(pin, HIGH);
Serial.print("DutyCycle: ");
time = micros();
DutyCycle = (duration / time) * 100;

At beginning of code in above post, should read...

int DutyCycle

That typo is not in my actual code. I had to copy from my laptop that doesn't have internet access easily.

The time returned by micros keeps incrementing. The time returned by pulseIn is the time it takes the input pin to go HIGH.

If you are feeding a PWM signal into pin 7, you have no way of knowing where in the cycle you are measuring from.

| |___

Suppose your signal looks like this. When pulseIn is called, where along that wave form are you? All you know is how long it takes to get to next transition to HIGH.

Duration is an integer. Time is an integer, which is larger than duration. The result of the integer division will be 0. Multiplying that by 100 is not going to make it greater than 0.

What I am attempting to do is measure my ON time and divide it by the total time hence giving me the duty cycle of the transducer for that particular air pressure. I was expecting to get some fraction, which I multiplied by 100 just to put into percent, the normal duty cycle unit, not to try and make 0 bigger :). Evidently pulseIn is not what I need, so what function(s) do you suggest?

I'd be inclined to use two interrupts, one for the RISING edge, and one for the FALLING edge.

In each ISR, copy thisRisingTime to lastRisingTime (or the falling equivalents), and set thisRisingTime to micros().

Periodically, in loop, use the difference between rising times and the difference between the falling times to give you the duty cycle.

The duty cycle is not an integer, so the times, which are, (or, more accurately, the difference between the times) need to be cast to floats, divided, multiplied by 100.0 (not 100), and stored in a float.

Wouldn't something simple like this work? (not tested, just a concept):

durationHigh = pulseIn(pin, HIGH);
durationLow = pulseIn(pin, LOW);
period = durationHigh + durationLow;
float dutyCycle = (f)durationHigh / (f)period;

The assumption being that the duty cycle won't have changed significantly during two consecutive pulseIn() commands.


Wouldn't something simple like this work?

The presumption behind the code you posted is that the pulseIn command is called precisely when the pin transitioned to LOW, so the time returned in durationHigh is actually the time that the pin was LOW (the names for the times are reversed, by the way).

But, there is no way of knowing how long the pin was already LOW when the first call is made, so the time that the function spends waiting for a transition doesn't tell us anything.

Perhaps three calls to pulseIn, waiting for a transition to HIGH that you throw away, then timing for the transition to LOW, which you keep, then timing for the next transition to HIGH, which you keep, would be useful.

Interesting problem so I had a look at the pulsIn() code

      // 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)

Looks like it handles the situation properly by waiting for the first edge before timing.


/* 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, [glow]but must be called at least a few dozen microseconds
 * before the start of the pulse[/glow]. */

So there is the chance of some race condition or though that would be rare (depending on the frequency of the pulses).

Maybe catching an edge with an interrupt so you know you're well "inside" a pulse, then calling pulseIn(). (As long as the pulses are > the interrupt latency)


I thought the pulseIn() command had been 'upgraded' to automatically not start counting time until it sees the the start of the transistion it is looking for, high or low?


Reads a pulse (either HIGH or LOW) on a pin. For example, if value is HIGH, pulseIn() waits for the pin to go HIGH, starts timing, then waits for the pin to go LOW and stops timing. Returns the length of the pulse in microseconds. Gives up and returns 0 if no pulse starts within a specified time out.


I guess I ought to re-read the documentation myself, once in a while. Thanks for the reminder.

Thanks. I would have never thought this would be this difficult. I get what the problem is, but the codes retrolefty or graynomad suggested would probably give info accurate enough. Remember, when I first started this thread I stated I was attempting to "sync" if I can just get identical data, slightly "off" or not, between the transducers, it should still yield the same rpm's per psi. Thanks for all of your help, and you all have a merry xmas.

Ok, posted previous post before reading (2) posts before that. So pulseIn WILL work???

So pulseIn WILL work???

I think so, if used properly.