Three ways of using Arduino to read PWM signal of RC receiver

Three ways of using Arduino to read PWM signal of RC receiver

Note: Recently, the static change of the playing model requires the use of a 2.4Ghz RC controller to control arduino.
I found an article on using Arduino to process PWM signal on the Internet. I think it's good. I hope it can help Tonghao.
(translation and summary) https://www.benripley.com/diy/arduino/three-ways-to-read-a-pwm-signal-with-arduino/ )

PWM signal realizes information transmission by controlling the pulse width, which is commonly used in steering gear control of RC model. (Note: PWM is a digital signal with only low level and high level, and the duration of high level is the pulse width)
There are roughly three ways to use Arduino to process PWM signals from RC Receivers:

  1. pulseIn() function
  2. External Interrupts
  3. Pin Change Interrupts

Using the pulseIn() function

Let's talk about the simplest pulseIn() function first. This function will wait for the input signal to change to HIGH level (when value is set to HIGH, on the contrary, LOW waits for LOW level), and start the timer. When the input signal changes to LOW level again, end the timer and return to the duration of HIGH level, in milliseconds (ms).
It should be added that the pulse duration that arduino can process ranges from 10 microseconds to 3 minutes.
pulseIn(pin, value, timeout) can set timeout manually. If it exceeds this value, 0 will be returned.

byte PWM_PIN = 3; //Input the PWM signal line to pin 3
 
int pwm_value;
 
void setup() {
  pinMode(PWM_PIN, INPUT);//Set this pin to input mode
  Serial.begin(115200);
}
 
void loop() {
  pwm_value = pulseIn(PWM_PIN, HIGH);//Detect high level
  Serial.println(pwm_value);//Serial port output value
}

Using the pulseIn() function is the simplest way, but the disadvantage is that the CPU cannot be used while the timer is waiting, resulting in low execution efficiency.

Use external interrupt

Using external interrupts can solve the efficiency problem that the CPU cannot be used. Most arduino have two external interrupts, which are on digital 2 and digital 3 pins respectively. An interrupt can be triggered by a change in level.

attachInterrupt(0, risingCallback, RISING);
//External interrupt No. 0, execute risingCallback() when the external level rises
volatile int pwm_value = 0; 
//Arduino docs emphasizes that volatile must be used for variable declaration when there are concurrent threads (such as interrupts)
volatile int prev_time = 0;
 
void setup() {
  Serial.begin(115200);
  // Perform risingCallback() when a level rise occurs externally
  attachInterrupt(0, risingCallback, RISING); //Enable rise interrupt
}
 
void loop() { }
 
void risingCallback() {
  attachInterrupt(0, fallingCallback FALLING);//Enable descent interrupt
  prev_time = micros(); //Start timing
}
 
void fallingCallback() {
  attachInterrupt(0, risingCallback, RISING);
  pwm_value = micros()-prev_time;//Low level duration
  Serial.println(pwm_value);
}

The use of external interrupts can improve the execution efficiency, but the external interrupts of arduino can only use digital 2 and digital 3 pins, which limits the development in some scenarios.

For the interrupt mechanism of arduino, see
Detailed introduction of interrupt, IIC, soft serial port and PinChangeInt Library

Pin Change Interrupts using pin level changes

PCI can be used on any arduino pin. The manual implementation of PCI is complex, and PinChangeInt library can be used

#include <PinChangeInt.h>
#define MY_PIN 5 / / any pin can be used
 
volatile int pwm_value = 0;
volatile int prev_time = 0;
uint8_t latest_interrupted_pin;
 
void rising()
{
  latest_interrupted_pin=PCintPort::arduinoPin;
  PCintPort::attachInterrupt(latest_interrupted_pin, &falling, FALLING);
  prev_time = micros();
}
 
void falling() {
  latest_interrupted_pin=PCintPort::arduinoPin;
  PCintPort::attachInterrupt(latest_interrupted_pin, &rising, RISING);
  pwm_value = micros()-prev_time;
  Serial.println(state);
}
 
void setup() {
  pinMode(MY_PIN, INPUT); digitalWrite(MY_PIN, HIGH);
  Serial.begin(115200);
  PCintPort::attachInterrupt(MY_PIN, &rising, RISING);
}
 
void loop() { }

Keywords: Single-Chip Microcomputer arduino

Added by debuitls on Mon, 14 Feb 2022 13:08:22 +0200