1

So I've got a FlySky TH9X and I'm trying to read some pulses using an Arduino Uno.

I'm just starting out so I want to get the hang of using the pulseIn function before moving onto interrupts. My problem is that, when I wire everything up, I don't get sensible values. Furthermore, they don't change even though I move around the sticks on the actual remote.

I tried to start off simple by wiring just the channel 1 of the receiver to pin 3 of the Uno. Then I used this code:

int ch1;

void setup() {
  pinMode(3, INPUT);
  Serial.begin(9600);
}

void loop() {
  ch1 = pulseIn(3, HIGH, 25000);
  Serial.print("Channel 1: ");
  Serial.println(ch1);
  delay(100);
}

The serial monitor then spits out numbers ranging from 0 up to 10000+ in a very erratic and apparently not periodic nature. I'll copy a few lines here:

Channel 1: 9989
Channel 1: 10063
Channel 1: 10068
Channel 1: 274
Channel 1: 0
Channel 1: 10085
Channel 1: 10039
Channel 1: 10336
Channel 1: 9629
Channel 1: 9959
Channel 1: 10064
Channel 1: 10088
Channel 1: 378
Channel 1: 0
Channel 1: 10044
Channel 1: 10059
Channel 1: 10424
Channel 1: 9632
Channel 1: 9867
Channel 1: 10069
Channel 1: 10067
Channel 1: 10473
Channel 1: 10037
Channel 1: 10063
Channel 1: 10063
Channel 1: 10253
Channel 1: 9677
Channel 1: 10013
Channel 1: 10064
Channel 1: 10062
Channel 1: 13

As you can see: not only are the higher-end values a whole order of magnitude too big (i thought pulses are normally between 1000 - 2000us?), but the actual range that these numbers span is far, far too wide for me to do anything with. Also, the sticks on my remote seem to have no influence on the numbers.

Can someone please help me? thank you :)

Hassan

4
  • The code looks good - at least it looks just like the code given in the docs for PulseIn(). What numbers do you get if you disconnect the receiver and tie the pin to ground or VCC? What happens if you increase the delay from 100ms up to something like 5000 (5 seconds)? Commented Sep 13, 2016 at 8:14
  • 1
    Have you checked the RX is paired to the TX, and the correct mode is selected? Might be worth using it in an RC model to check it works as expected. The other thing to try is to see if you can get a sensible/expected reading on an oscilloscope from that channel? Commented Sep 13, 2016 at 9:36
  • What are the shape of the pulses? Your displays themselves at 9600 baud are likely to take around 21 ms, which could be throwing out your interpretation of the data.
    – Nick Gammon
    Commented Apr 13, 2017 at 7:47
  • I'm voting to close this question because it has been abandoned for months with none of the requested detail to make it answerable ever being provided and the poster has not even returned to this site since the day the question was asked. Commented Oct 10, 2017 at 18:13

2 Answers 2

1

I would not recommend using pulseIn for reading values from the receiver. pulseIn blocks the program until a signal is received, which is almost always undesirable.

An alternative approach would be to use CHANGE interrupts. You get an interrupt when the signal goes high and low. You take note of the time that each change occurs with millis and compare the times to get the duration of the signal.

Here's an example - you can add more channels if you'd like. Note, this is using the EnableInterrupt library.

#include <EnableInterrupt.h>

#define SERIAL_PORT_SPEED 57600
#define RC_NUM_CHANNELS  2

#define RC_CH1  0
#define RC_CH2  1
#define RC_CH1_INPUT  A0
#define RC_CH2_INPUT  A1   

uint32_t last_update_time = 0;
uint16_t rc_values[RC_NUM_CHANNELS];
uint32_t rc_start[RC_NUM_CHANNELS];
volatile uint16_t rc_shared[RC_NUM_CHANNELS];

void rc_read_values() {
  // read the values out of the shared, volatile array (which can change at any time)
  // and into an array that we only will only change when we call this function

  noInterrupts();
  memcpy(rc_values, (const void *)rc_shared, sizeof(rc_shared));
  interrupts();
}

void calc_input(uint8_t channel, uint8_t input_pin) {
  // This is the interrupt.  If the pin is high, we record the start
  // time of the pulse.  If the pin is low, we compare the start time
  // to the current time in order to get the length of the pulse.

  if (digitalRead(input_pin) == HIGH) {
    rc_start[channel] = micros();
  } else {
    uint16_t rc_compare = (uint16_t)(micros() - rc_start[channel]);
    rc_shared[channel] = rc_compare;
  }
}

void calc_ch1() { calc_input(RC_CH1, RC_CH1_INPUT); }
void calc_ch2() { calc_input(RC_CH2, RC_CH2_INPUT); }  

void setup() {
  Serial.begin(SERIAL_PORT_SPEED);

  pinMode(RC_CH1_INPUT, INPUT);
  pinMode(RC_CH2_INPUT, INPUT);

  // set up CHANGE interrupts, so that we get notified when
  // each signal goes high or low.
  enableInterrupt(RC_CH1_INPUT, calc_ch1, CHANGE);
  enableInterrupt(RC_CH2_INPUT, calc_ch2, CHANGE);
}

void loop() {
  rc_read_values();

  Serial.print("CH1:"); Serial.println(rc_values[RC_CH1]);
  Serial.print("CH2:"); Serial.println(rc_values[RC_CH2]);

  delay(200);  // just so serial log doesn't flood
}

For a more detailed explanation, take a look here: http://rcarduino.blogspot.com/2012/01/how-to-read-rc-receiver-with.html

2
  • Hi, thank you for your answer Ryan. However, I do still need to know what went wrong with the pulseIn function as I would like to get that working first before moving onto interrupts. Can you offer me any advice on that? Thanks
    – Hassan M
    Commented Apr 23, 2016 at 16:09
  • 1
    I'd -1 this answer, but I don't have the points yet. The questioner clearly states that they don't want to use interrupts yet, and they would like to know why the code sample outputs seemingly random numbers. Commented Sep 13, 2016 at 7:59
0

Use a bigger timeout (30000):

int rcPin1 = 3; // PWM signal arduino pin
int rcPin2 = 4; // PWM signal arduino pin
int rcPin3 = 5; // PWM signal arduino pin
int rcPin4 = 6; // PWM signal arduino pin
int rcPin5 = 7; // PWM signal arduino pin
int rcPin6 = 8; // PWM signal arduino pin
int ch1 = 0;    // Receiver channel 1 pwm value
int ch2 = 0;    // Receiver channel 1 pwm value
int ch3 = 0;    // Receiver channel 1 pwm value
int ch4 = 0;    // Receiver channel 1 pwm value
int ch5 = 0;    // Receiver channel 1 pwm value
int ch6 = 0;    // Receiver channel 1 pwm value
void setup() {
  pinMode(rcPin1, INPUT);
  pinMode(rcPin2, INPUT);
  pinMode(rcPin3, INPUT);
  pinMode(rcPin4, INPUT);
  pinMode(rcPin5, INPUT);
  pinMode(rcPin6, INPUT);
  Serial.begin(9600);
}

void loop() {
  // Read in the length of the signal in microseconds
  ch1 = pulseIn(rcPin1, HIGH, 30000);
  Serial.print("Channel #1: ");
  Serial.println(ch1);
  ch2 = pulseIn(rcPin2, HIGH, 30000);
  Serial.print("Channel #2: ");
  Serial.println(ch2);
  ch3 = pulseIn(rcPin3, HIGH, 30000);
  Serial.print("Channel #3: ");
  Serial.println(ch3);
  ch4 = pulseIn(rcPin4, HIGH, 30000);
  Serial.print("Channel #4: ");
  Serial.println(ch4);
 ch5 = pulseIn(rcPin5, HIGH, 30000);
  Serial.print("Channel #5: ");
  Serial.println(ch5);
  ch6 = pulseIn(rcPin6, HIGH, 30000);
  Serial.print("Channel #6: ");
  Serial.println(ch6);
 delay(1000);
}
1
  • Hmm, that might possibly help, but most analog RC systems repeat every 20ms, and digital systems likely faster. It seems like with the originally 25,000 uS even if the a pulse was "just" missed another would arrive in time, but your longer allowance is probably okay, too. If this were the solution, then changing just this one thing would presumably make a difference, and changing it back would restore the problem. Commented Jan 13, 2017 at 3:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.