Hi @trentonp
Here's one way to measure an input channel from an RC receiver using the attachInterrupt() function. It's non-blocking, meaning that it continously reads the incoming pulse width around the loop(). Using the micro() function gives the input an accuracy of around 4us on AVR based Arduinos, (1us on ARM based ones):
// Sketch to calculate pulsewidth from an input signal in microseconds
#define INPUT_PIN 10 // Arduino input pin number
volatile unsigned long isrPulsewidth; // Define Interrupt Service Routine (ISR) pulsewidth
unsigned long pulseWidth; // Define Pulsewidth variable
void setup()
{
pinMode(INPUT_PIN, INPUT); // Set the input pin
attachInterrupt(digitalPinToInterrupt(INPUT_PIN), calcPulsewidth, CHANGE); // Run the calcPulsewidth function on signal CHANGE
}
void loop()
{
noInterrupts(); // Turn off interrupts
pulseWidth = isrPulsewidth; // Copy the isr pulsewidth to the pulsewidth variable
interrupts(); // Turn on interrupts
// Work with pulsewidth here ...
// ...
}
void calcPulsewidth() // Interrupt Service Routine (ISR)
{
static unsigned long pulseStartTime; // Start time variable
if (digitalRead(INPUT_PIN) == HIGH) // If the change was a RISING edge
{
pulseStartTime = micros(); // Store the start time (in microseconds)
}
else // If the change was a FALLING edge
{
isrPulsewidth = micros() - pulseStartTime; // Calculate the pulsewidth
}
}
If you require a resolution of more than 4us, timer 2 can be employed instead of micros() to increase this to 1us if required.
The conversion from 1ms-2ms receiver input pulse to PWM frequency output can be achieved using the Arduino map() and constrain() functions.
Regarding the PWM output, if you're after a 50% duty-cycle that changes frequency, this can be achieved at low frequencies using the Arduino Uno's 16-bit timer 1 in Fast PWM Mode with OCR1A as TOP.
Fast PWM Mode with OCR1A as TOP has the advantage over Clear Timer On Compare Match (CTC) mode, since the OCR1A register is double buffered, meaning that changes to the output only occur on a timer update, or in other words only when the timer overflows. This prevents glitches from appearing on the output waveform.
Here's the code to do that:
// Output 1Hz, 50% duty-cycle on D9 using timer 1 in "Fast PWM mode with OCR1A as TOP"
// Calculate OCR1A value = frequency(CPU) / (2 * precaler * frequency(PWM)) - 1
void setup()
{
pinMode(9, OUTPUT); // Set D9 as an output
TCCR1A = _BV(COM1A0) | _BV(WGM11) | _BV(WGM10); // Set timer 1 in Fast PWM mode with OCR1A as TOP
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12); // Enable timer clock with divide by 256 prescaler
OCR1A = 31249; // 1Hz PWM: OCR1A = 16MHz / (2 * 256 * 1Hz) - 1 = 31249
//OCR1A = 445; // 70Hz PWM: OCR1A = 16MHz / (2 * 256 * 70Hz) - 1 = 445
}
void loop() {}