Входной Режим захвата PPM сигнала

Приветствую всех участников Форума. Я хотел бы выразить свою глубочайшую благодарность в связи с названием этой должности. На прошлой неделе я пытаюсь захватить и декодировать сигнал PPM от RC-передатчика. Хотя я видел много различных подходов и кодов в Интернете, используя такие методы, как режим захвата ввода и изменение контакта, я хотел бы обратиться за помощью в моем подходе. Большинство кодов, которые я нашел в Интернете, представляют собой сбои и нестабильности при попытке прочитать время между восходящими импульсами. Я попытался прочитать и понять, как настроить входные регистры захвата на чипе Atmega 32u4, он же Arduino Pro Micro / Lepnardo, но я не могу найти правильный способ определения регистров, а также функции ISR (_vec). В следующих нескольких строках я попытаюсь объяснить код, который я написал до сих пор, но мне понадобится некоторая помощь в отношении инициализации регистров. Пожалуйста, оголитесь со мной, так как любая помощь будет очень ценна. Без лишних слов позвольте представить вам следующие строки.


#define STICK_CENTER 1500
#define STICK_HALFWAY 500
#define THRESHOLD 15 

#define MIN_PULSE_WIDTH (STICK_CENTER - STICK_HALFWAY - 15)
#define MAX_PULSE_WIDTH (STICK_CENTER + STICK_HALFWAY + 15)

#define RC_CHANNELS_COUNT 8

#define PPM_CAPTURE_PIN 4
#define NEWFRAME_PULSE_WIDTH 2000
#define TIMER_COUNT_DIVIDER 2

void rc_setup_ppm() {
  setupPins();
  initTimer();
}

void setupPins(void) {
  // Set up the Input Capture pin
  pinMode(PPM_CAPTURE_PIN, INPUT);
  digitalWrite(PPM_CAPTURE_PIN, 1); // enable the pullup
}

void initTimer(void) {
  cli();
  
  TIFR = (1 << ICF1); //Clear any Interrupt flags 
  PRR |= (0 << PRTIM1); //Enable Timer1
  TCCR1A = 0; //Clear TCCR1A
  TCCR1B = 0; //Clear TCCR1B
  TCCR1C = 0; //Clear TCCR1C
  TCCR1B = (1 << ICNC1) | (1 << ICES1) | (1 << WGM13) | (1 << WGM12) | (0 << CS12) | (1 << CS11) | (0 << CS10);
  TIMSK1 |= (1 << ICIE1); //Enable input capture
  TIFR1 = (1 << ICF1); //Clear interrupt flag

 sei();
}

uint16_t adjust(uint16_t diff, uint8_t chan) {
 
  return diff / TIMER_COUNT_DIVIDER;
}

ISR(TIMER1_CAPT_vect) {
  union twoBytes {
    uint16_t word;
    uint8_t  byte[2];
  } timeValue;

  uint16_t now, diff;
  static uint16_t last = 0;
  static uint8_t chan = 0;

  timeValue.byte[0] = ICR1L;    // grab captured timer value (low byte)
  timeValue.byte[1] = ICR1H;    // grab captured timer value (high byte)

  now = timeValue.word;
  diff = now - last;
  last = now;

  //all numbers are microseconds multiplied by TIMER_COUNT_DIVIDER (as prescaler is set to 1/8 of 16 MHz)
  if (diff > (NEWFRAME_PULSE_WIDTH * TIMER_COUNT_DIVIDER)) {
    chan = 0;  // new data frame detected, start again
  }
  else {
    if (diff > (MIN_PULSE_WIDTH * TIMER_COUNT_DIVIDER - THRESHOLD)
        && diff < (MAX_PULSE_WIDTH * TIMER_COUNT_DIVIDER + THRESHOLD)
        && chan < RC_CHANNELS_COUNT)
    {
      rc_values[chan] = adjust(diff, chan); //store detected value
    }
    chan++; //no value detected within expected range, move to next channel
  }
}

Учитывая вышеизложенное, я хотел бы помочь установить процедуру инициализации регистров. Немного информации о моем сигнале:

PPM включает в себя 8 различных каналов в качестве суммированного сигнала. Всего 9 импульсов, при этом каждый из них, имеет временную длительность от 998 до 2012 микросек.

Временные рамки каждого импульса легко изменить с помощью настроек передатчика. Также может быть изменен общий период кадра. Под первым я подразумеваю МАКСИМАЛЬНОЕ время каждого импульса, а под вторым-общий период кадра после сканирования 8 каналов. Учитывая это, временные периоды составляют 26,5 милл и 350 микросекунд.

Хватит с них. Возвращаясь к фактическому коду, вы увидите функции cli(); и sei ();. Действительно ли я должен устанавливать их во время этой части кода? Кроме того, нужно ли мне сбрасывать или удалять какие-либо активные флаги? Должен ли я включать какие-либо флаги (например, флаг переполнения после того, как счетчик достиг своего пикового значения)?

В этот момент я также хотел бы отметить, что я использую прескалер 1/8, что приводит к тиковому периоду примерно 0,5 микросекунд. Кроме того, я улавливаю только восходящую часть импульсов. И я использую входной канализатор, но, учитывая спецификации данных, я видел, что кадр отмены имеет 4 периода. Есть ли какой-либо способ использовать схему фильтрации с низкой задержкой?

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

Большое спасибо, Кутсук Феодосий

, 👍1

Обсуждение

У меня такое чувство, что ты собираешься вытащить кролика из шляпы или вызвать нас на дуэль или что-то в этом роде. Если говорить серьезно, то вам, вероятно, повезет больше, если вы это сократите., @timemage

Извините за содержание моего поста. Я хотел бы обратиться за советами только к инициализации режима захвата ввода. Только регистры и как ими пользоваться., @k. theodosis

Вероятно, я мог бы написать что-нибудь о том, как настроить захват входных данных. Но в своем вопросе вы упоминаете, что пытаетесь сделать это с помощью **8** разные сигналы. Только у 32u4 есть **2** входные контакты захвата. Если я правильно понимаю, для вас это будет проблемой., @timemage

Дорогой маг времени, спасибо за ответ. Это было что-то, что я написал неправильно, так что, пожалуйста, простите меня. Я имел в виду, что сигнал ppm содержит 8 различных сигналов (всего 9 импульсов)., @k. theodosis

Если "после того, как 8 *каналов* были отсканированы" означает, что после "после 8 *импульсов*..." вы можете [отредактировать свой вопрос](https://arduino.stackexchange.com/posts/81610/edit) сказать это. Разъяснения к вопросам, задаваемым здесь, обычно предполагаются отредактированными в самом вопросе., @timemage

Еще раз большое спасибо, я изменил его и включил в него то, что происходит на самом деле., @k. theodosis


1 ответ


2

Действительно ли я должен устанавливать их во время этой части кода?

- Нет, не знаешь. Однако я бы изменил порядок последних инициализаций:

  • Обновите TIFR1 прямо перед TIMSK1, чтобы избежать немедленного срабатывания прерывания.

  • Установите TCR1B последним, чтобы таймер запускался только тогда, когда он был полностью настроен.

Кроме того, нужно ли мне сбрасывать или удалять какие-либо активные флаги?

AFAIK ядро Arduino не использует прерывания таймера 1. Вы можете взять под контроль все биты в регистрах (например, TIMSK1 = (1 << ICIE1);) вместо только некоторых выбранных битов. Хотя это не должно иметь значения .

Должен ли я включать какие-либо флаги (например, флаг переполнения после того, как счетчик достиг своего пикового значения)?

Не беспокойтесь о переливах. Вычисление diff = now - last выполняется по модулю 216 и, в силу правил модульной арифметики, дает правильный результат даже при переполнении.

И я использую подавитель входного сигнала, но, учитывая технические характеристики таблицы данных, я видел, что кадр отмены имеет длину 4 периода.

Это создает задержку в “четыре системных такта”, или 0,25 мкс. Неужели вас действительно волнует такая маленькая задержка? Обратите внимание, что, поскольку все ребра страдают одинаковой задержкой, это не влияет на расчетные различия.

А теперь, если позволите, пара замечаний по поводу вашего кода:

  pinMode(PPM_CAPTURE_PIN, INPUT);
  digitalWrite(PPM_CAPTURE_PIN, 1); // включить подтягивание

Это можно упростить и сделать более явным:

  pinMode(PPM_CAPTURE_PIN, INPUT_PULLUP);

Затем,

  union twoBytes {
    uint16_t word;
    uint8_t  byte[2];
  } timeValue;
  timeValue.byte[0] = ICR1L;    // grab captured timer value (low byte)
  timeValue.byte[1] = ICR1H;    // grab captured timer value (high byte)
  now = timeValue.word;

Когда-то давно это был способ чтения 16-битных регистров. Так как уже много лет компилятор C знает, как это сделать, вам просто нужно выдать:

  now = ICR1;
,

Здесь содержится большая часть того, что я писал, так что я просто собираюсь проголосовать за это., @timemage

PRR |= (0 << PRTIM1); ->PRR0 &= ~(1 << PRTIM1);, @timemage

TCR1C = 0; не делает ничего полезного., @timemage

Дорогой Эдгар, маг времени, большое спасибо за ваши ответы. Особенно тому, от Точильщика, который включал в себя все, что я просил. Просто поражен простотой и тем, как вы передали всю информацию. Ваше здоровье!, @k. theodosis