FlySky TH9X с Arduino: невозможно заставить функциюpulsIn() возвращать разумные значения для любого канала

Итак, у меня есть FlySky TH9X, и я пытаюсь считать несколько импульсов с помощью Arduino Uno.

Я только начинаю, поэтому хочу научиться использовать функциюpulsIn, прежде чем переходить к прерываниям. Моя проблема в том, что когда я все подключаю, я не получаю разумных значений. Более того, они не меняются, даже если я перемещаю джойстики на самом пульте.

Я попытался начать с простого: подключил только канал 1 приемника к контакту 3 Uno. Затем я использовал этот код:

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);
}

Последовательный монитор затем выдает числа в диапазоне от 0 до 10000+ в очень хаотичной и, по-видимому, непериодической природе. Скопирую сюда несколько строк:

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

Как вы можете видеть: не только более высокие значения на целый порядок слишком велики (я думал, что импульсы обычно составляют от 1000 до 2000 мкс?), но и фактический диапазон, охватываемый этими числами, слишком, слишком широк. для меня, чтобы сделать что-нибудь с. Кроме того, джойстики на моем пульте, похоже, не влияют на цифры.

Может кто-нибудь мне помочь? спасибо :)

Хасан

, 👍1

Обсуждение

Код выглядит хорошо — по крайней мере, он выглядит так же, как код, приведенный в документации для PulseIn(). Какие числа вы получите, если отсоединить приемник и подключить контакт к земле или VCC? Что произойдет, если вы увеличите задержку со 100 мс до примерно 5000 (5 секунд)?, @Michael Vincent

Вы проверили, что RX сопряжен с TX и выбран правильный режим? Возможно, стоит использовать его в модели RC, чтобы проверить, работает ли он должным образом. Еще одна вещь, которую стоит попробовать, — это посмотреть, сможете ли вы получить разумные/ожидаемые показания на осциллографе с этого канала?, @KennetRunner

Какова форма импульсов? Ваши дисплеи со скоростью 9600 бод, вероятно, займут около 21 мс, что может исказить вашу интерпретацию данных., @Nick Gammon

Я голосую за закрытие этого вопроса, потому что он был заброшен в течение нескольких месяцев, и ни одна из запрошенных подробностей, позволяющих ответить на него, так и не была предоставлена, а автор даже не вернулся на этот сайт со дня, когда был задан вопрос., @Chris Stratton


2 ответа


1

Я бы не рекомендовал использовать pulseIn для считывания значений с приемника. pulseIn блокирует программу до тех пор, пока не будет получен сигнал, что почти всегда нежелательно.

Альтернативным подходом было бы использование прерываний CHANGE. Вы получаете прерывание, когда сигнал становится высоким и низким. Вы отмечаете время, когда происходит каждое изменение, с помощью millis и сравниваете время, чтобы получить длительность сигнала.

Вот пример — вы можете добавить больше каналов, если хотите. Обратите внимание, что здесь используется библиотека EnableInterrupt.

#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() {
  // считываем значения из общего, изменчивого массива (который может измениться в любое время)
  // и в массив, который мы изменим только при вызове этой функции

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

void calc_input(uint8_t channel, uint8_t input_pin) {
  // Это прерывание. Если вывод высокий, мы записываем начало
  // время импульса. Если пин низкий, мы сравниваем время начала
  // к текущему времени, чтобы получить длину импульса.

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

  // настраиваем прерывания CHANGE, чтобы получать уведомления, когда
  // каждый сигнал становится высоким или низким.
  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);  // просто чтобы последовательный журнал не переполнялся
}

Более подробное объяснение можно найти здесь: http://rcarduino.blogspot.com/2012/01/how-to-read-rc-receiver-with.html

,

Привет, Райан, спасибо за ответ. Однако мне все еще нужно знать, что пошло не так с функцией pulseIn, так как я хотел бы сначала заставить ее работать, прежде чем переходить к прерываниям. Можете ли вы дать мне какой-либо совет по этому поводу? Спасибо, @Hassan M

Я бы поставил -1 этому ответу, но у меня пока нет очков. Автор вопроса ясно заявляет, что пока не хочет использовать прерывания, и хотел бы узнать, почему пример кода выводит, казалось бы, случайные числа., @Michael Vincent


0

Используйте большее время ожидания (30000):

int rcPin1 = 3; // ШИМ-сигнал arduino pin
int rcPin2 = 4; // ШИМ-сигнал arduino pin
int rcPin3 = 5; // ШИМ-сигнал arduino pin
int rcPin4 = 6; // ШИМ-сигнал arduino pin
int rcPin5 = 7; // ШИМ-сигнал arduino pin
int rcPin6 = 8; // ШИМ-сигнал arduino pin
int ch1 = 0;    // Значение ШИМ канала 1 приемника
int ch2 = 0;    // Значение ШИМ приемника 1
int ch3 = 0;    // Значение ШИМ приемника 1
int ch4 = 0;    // Значение ШИМ канала 1 приемника
int ch5 = 0;    // Значение ШИМ канала 1 приемника
int ch6 = 0;    // Значение ШИМ приемника 1
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() {
  // Считываем длину сигнала в микросекундах
  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);
}
,

Хм, это, возможно, поможет, но большинство аналоговых систем RC повторяются каждые 20 мс, а цифровые системы, вероятно, быстрее. Похоже, что при изначальном значении 25 000 мкс, даже если импульс был "просто" пропущен, другой прибудет вовремя, но ваш более длинный допуск, вероятно, тоже подойдет. Если бы это было решением, то изменение только этого одного параметра, вероятно, имело бы значение, а изменение его обратно устранило бы проблему., @Chris Stratton