Support » Pololu AVR Library Command Reference »
8. Orangutan Pulse/PWM Inputs
<p>This section of the library makes it easy to measure pulse inputs such as hobby servo RC pulses, PWM frequency and duty cycle, discharge time of a capacitor (measured digitally), etc. For example, with these functions, it becomes simple to program your Orangutan to respond to multiple channels from an RC receiver or to read data from the multitude of sensors that use pulse outputs. The pulses can be connected to any digital input, and there is no limit to the number of pulse inputs you can have (beyond the obvious I/O line and RAM limitations; each pulse channel requires 17 bytes of RAM). These functions are not available within the Arduino environment, which has its own pulse-reading functions.</p>
<p>The pulse-measuring occurs in the background and is entirely interrupt driven, requiring no further action from you once you have initiated it by calling <strong>pulse_in_start()</strong>. Required memory is allocated using <strong>malloc()</strong> when pulse-measuring is initiated, which conserves RAM. The <strong>pulse_in_stop()</strong> function frees this dynamically allocated memory. Once measuring is started, you can use these functions to get information about the most recently received high and low pulse, as well as the current pulse in progress. The system tick counter from OrangutanTime is used to time the pulses, which means pulse width measurements have a resolution of 0.4 µs, and the upper limit on pulse width is approximately 28 minutes.</p>
<p>This section of the library uses the AVR’s pin-change interrupts: <strong>PCINT0</strong>, <strong>PCINT1</strong>, and <strong>PCINT2</strong> (and <strong>PCINT3</strong> on the Orangutan SVP and X2). It will conflict with any other code that uses pin-change interrupts (e.g. OrangutanWheelEncoders).</p>
<h3>Pulse Information Variables</h3>
<p>The OrangutanPulseIn code uses an array of 17-byte PulseInputStruct structs to keep track of the pulse data; each element of the array represents one pulse input channel. Struct data is automatically updated by the pin-change interrupt service routine (ISR) as pulses are received.</p>
<pre name="code" class="c">
#define LOW_PULSE 1
#define HIGH_PULSE 2
#define ANY_PULSE 3

struct PulseInputStruct
{
 volatile unsigned char* pinRegister;
 unsigned char bitmask;
 volatile unsigned long lastPCTime;
 volatile unsigned char inputState;
 volatile unsigned long lastHighPulse;
 volatile unsigned long lastLowPulse;
 volatile unsigned char newPulse;
};</pre>
<p>The bottom five struct variables are declared “volatile” because their values are changed by the pin-changed interrupt service routine (ISR), so we require the compiler to load them from RAM every time they are referenced. If a variable is not declared “volatile”, the compiler will eliminate what it decides are superfluous reads of a variable from RAM and instead work with that variable in local registers, which saves time and code space, but this can cause situations where you fail to detect when an ISR has changed that variable’s value.</p>
<ul><li><b><em>pinRegister</em> & <em>bitmask</em> :</b> Used by the pin-change ISR to determine the input state of the channel. <ins>You should not use these two struct variables in your programs</ins> because they might be removed in future versions of the library.</li>
<li><b><em>lastPCTime</em> :</b> The system tick counter value when the last state change happened on this channel. You can use <code>(get_ticks()-lastPCTime)</code> to figure out how long ago (in units of 0.4 µs) the last pulse ended.</li>
<li><b><em>inputState</em> :</b> This byte has a value of 1 (<span class="constant">HIGH</span>) if the channel is high, else it has a value of 0 (<span class="constant">LOW</span>).</li>
<li><b><em>lastHighPulse</em> :</b> The width of the last detected high pulse in system ticks (units of 0.4 µs). A high pulse is one that starts with a channel transition from low to high and ends with a channel transition from high to low.</li>
<li><b><em>lastLowPulse</em> :</b> The width of the last detected low pulse in system ticks (units of 0.4 µs). A low pulse is one that starts with a channel transition from high to low and ends with a channel transition from low to high.</li>
<li><b><em>newPulse</em> :</b> The bits of this byte are set whenever a new pulse occurs, which lets you tell when new data has arrived. The <span class="constant">LOW_PULSE</span> bit is set when a low pulse finishes, and the <span class="constant">HIGH_PULSE</span> bit is set when a high pulse finishes. The functions in this section clear the <em>newPulse</em> flags after returning them. Once set, the flags stay set until they are read. Masking <em>newPulse</em> with the keyword <span class="constant">ANY_PULSE</span> with the code <code>(newPulse&ANY_PULSE)</code> will be non-zero if either new-pulse bit flag is set.</li>
<div class="libpololu">
<h2>Reference</h2>
<div class="key">
<p class="cpp"><strong>C++ methods are shown in red.</strong></p>
<p class="c"><strong>C/C++ functions are shown in green.</strong></p>
</div>
<p class="cpp">static unsigned char OrangutanPulseIn::<strong>start</strong>(const unsigned char <em>pulse_pins</em>[], unsigned char <em>num_pins</em>)</p>
<p class="c">unsigned char <strong>pulse_in_start</strong>(const unsigned char <em>pulse_pins</em>[], unsigned char <em>num_pins</em>)</p>
<p class="def">Configures the AVR’s pin-change interrupts to measure pulses on the specified pins. The <em>num_pins</em> parameter should be the length of the <em>pulse_pins</em> array. A nonzero return value indicates that the needed memory could not be allocated.</p>
<p class="def">The <em>pulse_pins</em> parameter should be the RAM address of an array of AVR I/O pin numbers defined using the IO_* keywords provided by the library (e.g. <strong>IO_D1</strong> for a pulse input on pin PD1). This function does <ins>not</ins> configure the <em>pulse_pins</em> as digital inputs, which makes it possible to measure pulses on pins being used as outputs. AVR I/O pins default to digital inputs with the internal pull-up disabled after a reset or power-up.</p>
<h3>Example</h3>
<pre name="code" class="c">
// configure pins PD0 and PD1 as pulse input channels
pulse_in_start((unsigned char[]) {IO_D0, IO_D1}, 2);</pre>
<pre name="code" class="c">
// configure pins PD0 and PD1 as pulse input channels
OrangutanPulseIn::start((unsigned char[]) {IO_D0, IO_D1}, 2);</pre>
<p class="cpp">static void OrangutanPulseIn::<strong>stop</strong>()</p>
<p class="c">void <strong>pulse_in_stop</strong>()</p>
<p class="def">Disables all pin-change interrupts and frees up the memory that was dynamically allocated by the pulse_in_start() function. This can be useful if you no longer want state changes of your pulse-measuring channels to interrupt program execution.</p>
<p class="cpp">static void OrangutanPulseIn::<strong>getPulseInfo</strong>(unsigned char <em>channel</em>, struct PulseInputStruct* <em>pulse_info</em>)</p>
<p class="c">void <strong>get_pulse_info</strong>(unsigned char <em>channel</em>, struct PulseInputStruct* <em>pulse_info</em>)</p>
<p class="def">This function uses the <em>pulse_info</em> pointer to return a snapshot of the pulse state for the specified channel, <em>channel.</em> After get_pulse_info() returns, <em>pulse_info</em> will point to a <b>copy</b> of the PulseInputStruct that is automatically maintained by the the pin-change ISR for the specified channel. Additionally, after the copy is made, this function clears the <em>newPulse</em> flags (both high pulse and low pulse) in the original, ISR-maintained PulseInputStruct. Since <em>pulse_info</em> is a copy, the pin-change ISR will never change the <em>pulse_info</em> data. Working with <em>pulse_info</em> is especially useful if you need to be sure that all of your puse data for a single channel came from the same instant in time, since pin-change interrupts are disabled while the ISR-maintained PulseInputStruct is being copied to <em>pulse_info</em>.</p>
<p class="def">The argument <em>channel</em> should be a number from 0 to one less than the total number of channels used (<em>num_pins</em>-1); the channel acts as an index to the <em>pulse_pins</em> array supplied to the pulse_in_start() function.</p>
<p>See the “Pulse Information Variables” section at the top of this page for documentation of the members of the PulseInputStruct <em>pulse_info,</em> and see the <code>pulsein1</code> sample program for an example of how to use get_pulse_info() as the basis of your pulse-reading code.</p>
<h3>Example</h3>
<pre name="code" class="c">
// configure pins PD0 and PD1 as pulse input channels
pulse_in_start((unsigned char[]) {IO_D0, IO_C3}, 2);

struct PulseInputStruct pulseInfo;
get_pulse_info(1, &pulseInfo); // get pulse info for pin PC3
if (pulseInfo.newPulse & HIGH_PULSE)
 someFunction(pulseInfo.lastHighPulse);</pre>
<pre name="code" class="c">
// configure pins PD0 and PD1 as pulse input channels
OrangutanPulseIn::start((unsigned char[]) {IO_D0, IO_C3}, 2);

struct PulseInputStruct pulseInfo;
OrangutanPulseIn::getPulseInfo(1, &pulseInfo); // get pulse info for pin PC3
if (pulseInfo.newPulse & HIGH_PULSE)
 someFunction(pulseInfo.lastHighPulse);</pre>
<p class="cpp">static unsigned char OrangutanPulseIn::<strong>newPulse</strong>(unsigned char <em>channel</em>)</p>
<p class="c">unsigned char <strong>new_pulse</strong>(unsigned char <em>channel</em>)</p>
<p class="def">This function returns the <em>newPulse</em> flags for the specified pulse input channel and then clears them, so subsequent new_pulse() calls will return zero until the next new pulse is received. The return value of this fuction will be 0 only if no new pulses have been received. It will be non-zero if a new high or low pulse has been received. You can check the type of new pulse by looking at the <strong>HIGH_PULSE</strong> and <strong>LOW_PULSE</strong> bits of the return value.</p>
<h3>Example</h3>
<pre name="code" class="c">
// check for new pulses on pulse input channel 0:
unsigned char newPulse = new_pulse(0);
if (newPulse) // if there has been a new pulse of any kind
 doSomething();
if (newPulse & HIGH_PULSE) // if there has been a new high pulse
 doSomethingElse();</pre>
<pre name="code" class="c">
// check for new pulses on pulse input channel 0:
unsigned char newPulse = OrangutanPulseIn::newPulse(0);
if (newPulse) // if there has been a new pulse of any kind
 doSomething();
if (newPulse & HIGH_PULSE) // if there has been a new high pulse
 doSomethingElse();</pre>
<p class="cpp">static unsigned char OrangutanPulseIn::<strong>newHighPulse</strong>(unsigned char <em>channel</em>)</p>
<p class="c">unsigned char <strong>new_high_pulse</strong>(unsigned char <em>channel</em>)</p>
<p class="def">This function returns the <em>newPulse</em> flags if there is a new high pulse on the specified pulse input channel (i.e. the return value is non-zero), else it returns zero. It also clears the <strong>HIGH_PULSE</strong> bit of the <em>newPulse</em> flag byte, so subsequent new_high_pulse() calls will return zero until the next new high pulse is received. The <strong>LOW_PULSE</strong> bit is not changed by this function.</p>
<p class="cpp">static unsigned char OrangutanPulseIn::<strong>newLowPulse</strong>(unsigned char <em>channel</em>)</p>
<p class="c">unsigned char <strong>new_low_pulse</strong>(unsigned char <em>channel</em>)</p>
<p class="def">This function returns the <em>newPulse</em> flags if there is a new low pulse on the specified pulse input channel (i.e. the return value is non-zero), else it returns zero. It also clears the <strong>LOW_PULSE</strong> bit of the <em>newPulse</em> flag byte, so subsequent new_low_pulse() calls will return zero until the next new low pulse is received. The <strong>HIGH_PULSE</strong> bit is not changed by this function.</p>
<p class="cpp">static unsigned long OrangutanPulseIn::<strong>getLastHighPulse</strong>(unsigned char <em>channel</em>)</p>
<p class="c">unsigned long <strong>get_last_high_pulse</strong>(unsigned char <em>channel</em>)</p>
<p class="def">This function returns the length in system ticks (units of 0.4 µs) of the last complete high pulse received on the specified pulse input channel. It gives you (interrupt-safe) access to the <em>lastHighPulse</em> member of the ISR-maintained PulseInputStruct for the specified channel. A high pulse is one that starts with a channel transition from low to high and ends with a channel transition from high to low. Note that if the last high “pulse” was longer than 28.6 minutes, the value returned by this function will have overflowed and the result will be incorrect. You should disregard the first high pulse after the pulse input line has been in a steady-high state for more than 28. minutes.</p>
<p class="cpp">static unsigned long OrangutanPulseIn::<strong>getLastLowPulse</strong>(unsigned char <em>channel</em>)</p>
<p class="c">unsigned long <strong>get_last_low_pulse</strong>(unsigned char <em>channel</em>)</p>
<p class="def">This function returns the length in system ticks (units of 0.4 µs) of the last complete low pulse received on the specified pulse input channel. It gives you (interrupt-safe) access to the <em>lastLowPulse</em> member of the ISR-maintained PulseInputStruct for the specified channel. A low pulse is one that starts with a channel transition from high to low and ends with a channel transition from low to high. Note that if the last low “pulse” was longer than 28.6 minutes, the value returned by this function will have overflowed and the result will be incorrect. You should disregard the first low pulse after the pulse input line has been in a steady-low state for more than 28. minutes.</p>
<p class="cpp">static void OrangutanPulseIn::<strong>getCurrentState</strong>(unsigned char <em>channel,</em> unsigned long* pulse_width, unsigned char* <em>state</em>)</p>
<p class="c">void <strong>get_current_pulse_state</strong>(unsigned char <em>channel,</em> unsigned long* pulse_width, unsigned char* <em>state</em>)</p>
<p class="def">This function gives you information about what is currently happening on the specified pulse input channel by using the argument <em>pulse_width</em> to return the number of system ticks that have elapsed since the last complete pulse ended (in units of 0.4 µs) and by using the argument <em>state</em> to return whether the voltage on the input channel is currently <strong>HIGH</strong> (1) or <strong>LOW</strong> (0). The <em>pulse_width</em> and <em>state</em> arguments are pointers to integer types whose values are respectively set (in an ISR-safe way) based on the <em>lastPCTime</em> and <em>inputState</em> members of the ISR-maintained PulseInputStruct for the specified channel. Specifically, *<em>pulse_width</em> is set to: <code>get_ticks()-pulseInfo[channel].lastPCTime</code></p>
<h3>Example</h3>
<pre name="code" class="c">
unsigned long pulse_width;
unsigned char state;
// get info for pulse input channel channel 0:
get_current_pulse_state(0, &pulse_width, &state);
if (pulse_width > 250000 && state == HIGH)
{
 // if more than 100 ms have passed since last pulse ended
 // and the pulse input channel is currently high
 doSomething();
}</pre>
<pre name="code" class="c">
unsigned long pulse_width;
unsigned char state;
// get info for pulse input channel channel 0:
OrangutanPulseIn::getCurrentState(0, &pulse_width, &state);
if (pulse_width > 250000 && state == HIGH)
{
 // if more than 100 ms have passed since last pulse ended
 // and the pulse input channel is currently high
 doSomething();
}</pre>
<p class="cpp">unsigned long OrangutanPulseIn::<strong>toMicroseconds</strong>(unsigned long pulse_width)</p>
<p class="c">unsigned long <strong>pulse_to_microseconds</strong>(unsigned long pulse_width)</p>
<p class="def">Converts the provided <em>pulse_width</em> argument from system ticks to microseconds (this is the same as multiplying <em>pulse_width</em> by 0.4 µs, but without using floating-point math) and returns the result. The same result could be achieved by calling <code>ticks_to_microseconds(pulse_width)</code>.</p>
<h3>Example</h3>
<pre name="code" class="c">
// if last high pulse was longer than 1500 microseconds
if (pulse_to_microseconds(get_last_high_pulse(0)) > 1500)
 doSomething();</pre>
<pre name="code" class="c">
// if last high pulse was longer than 1500 microseconds
if (OrangutanPulseIn::toMicroseconds(OrangutanPulseIn::getLastHighPulse(0)) > 1500)
 doSomething();</pre>
</div>