Как принять сигнал с приемника в AVR (PWM|Digital)

Tester500

Формализуем ТЗ, пока до Канта не дошло 😃

  1. нужно оцифровать сигналы PWM, которые поступают с канальных выводов приемника (PPM)
  2. Оцифрованный канал должен иметь …-бит (указать битность)
  3. На выходе имеем переменные, содержащие пропорционально длительности сигнала число.
  4. Использовать не более одного таймера и одного прерывания (видимо проще от этого таймера)

Такое ТЗ пойдет?

msv
  1. Точность определения длины импульса не хуже … мкс.
    (Разрядность можно сделать хоть long, но это не обещает некоторую гарантированную точность…)
Tester500

Длина импульса 2.1 мс, минимум 0.8 мс
Кто что еще подскажет?

Bare

Нашел один пример, написан на Си, но не под ардуино, поэтому я до конца его понять не могу. Хочется сделать библиотеку под ардуино.
приведу куски кода ( ниже приложу весь архив)
#define RX_ROLL REGISTER_BIT(PIND,1)
#define RX_PITCH REGISTER_BIT(PIND,2) // INT0
#define RX_COLL REGISTER_BIT(PIND,3) // INT1
#define RX_YAW REGISTER_BIT(PINB,7)
#define RX_ROLL_DIR REGISTER_BIT(DDRD,1)
#define RX_PITCH_DIR REGISTER_BIT(DDRD,2)
#define RX_COLL_DIR REGISTER_BIT(DDRD,3)
#define RX_YAW_DIR REGISTER_BIT(DDRB,7)

// RX_ROLL
ISR(PCINT2_vect)
{
if ( RX_ROLL ) // rising
{
RxChannel1Start = TCNT1;

} else { // falling
RxChannelsUpdatingFlag = 1;
RxChannel1 = TCNT1 - RxChannel1Start;
RxChannelsUpdatingFlag = 0;
}
}

// RX_PITCH
ISR(INT0_vect)
{
if (RX_PITCH)
{
RxChannel2Start = TCNT1;

} else { // falling
RxChannelsUpdatingFlag = 1;
RxChannel2 = TCNT1 - RxChannel2Start;
RxChannelsUpdatingFlag = 0;
}
}

// RX_COLL
ISR(INT1_vect)
{
if (RX_COLL)
{
RxChannel3Start = TCNT1;

} else { // falling
RxChannelsUpdatingFlag = 1;
RxChannel3 = TCNT1 - RxChannel3Start;
RxChannelsUpdatingFlag = 0;
}
}

// RX_YAW
ISR(PCINT0_vect)
{
if ( RX_YAW ) // rising
{
RxChannel4Start = TCNT1;

} else { // falling
RxChannelsUpdatingFlag = 1;
RxChannel4 = TCNT1 - RxChannel4Start;
RxChannelsUpdatingFlag = 0;
}
}

----------------------------

// pin change interrupt enables
PCICR |= (1 << PCIE0); // PCINT0…7
PCICR |= (1 << PCIE2); // PCINT16…23

// pin change masks
PCMSK0 |= (1 << PCINT7); // PB7
PCMSK2 |= (1 << PCINT17); // PD1
// external interrupts
EICRA = (1 << ISC00) | (1 << ISC10); // Any change INT0, INT1
EIMSK = (1 << INT0) | (1 << INT1); // External Interrupt Mask Register
EIFR |= (1 << INTF0) | (1 << INTF1);

// timer0 (8bit) - run @ 8MHz
// used to control ESC/servo pulse length
TCCR0A = 0; // normal operation
TCCR0B = (1 << CS00); // clk/0
TIMSK0 = 0; // no interrupts

// timer1 (16bit) - run @ 1Mhz
// used to measure Rx Signals & control ESC/servo output rate
TCCR1A = 0;
TCCR1B = (1 << CS11);

// timer2 8bit - run @ 8MHz / 1024 = 7812.5KHz
// and Stick-Arming
TCCR2A = 0;
TCCR2B = (1 << CS22) | (1 << CS21) | (1 << CS20); // /1024
TIMSK2 = 0;
TIFR2 = 0;
TCNT2 = 0; // reset counter

В другом проекте, автор читает так:
Вешает функцию на прерывание attachInterrupt(0, interruptHandler, RISING);
А это основная часть из interruptHandler
#define TIMEOUT 2500
#define XMITFACTOR_ADR 12
#define THROTTLEPIN 4
#define ROLLPIN 2
#define PITCHPIN 3
#define YAWPIN 6
#define GEARPIN 7
#define AUXPIN 5

roll = pulseIn(ROLLPIN, HIGH, TIMEOUT);
aux = pulseIn(AUXPIN, HIGH, TIMEOUT);
gear = pulseIn(GEARPIN, HIGH, TIMEOUT);
pitch = pulseIn(PITCHPIN, HIGH, TIMEOUT);
throttle = pulseIn(THROTTLEPIN, HIGH, TIMEOUT);
yaw = pulseIn(YAWPIN, HIGH, TIMEOUT);

Мне этот код не нравится по нескольким причинам:

  1. Слишком много времени тратится на таймауты в pulsein, если нет сигнала на большинстве каналов.
  2. Если нет сигнала на первом канале, то и остальные читаться не будут.

XXcontroller_KR_v1_5.zip

Tester500

Моя мыслЯ такая:
Допустим нужно оцифровать сигнал с 8-битной точностью. Настраиваем таймер так, чтобы он выдавал прерывания каждую (2мс-1мс)/256. 2мс общая длина импульса, 1мс длительность сигнала до начала отсчета. Далее по прерыванию опрашиваем нужные порты-каналы. По изменению уровней (асинхронно для каждого канала) производим математические вычисления длины. Код изображу позже, счас уже думать нечем.
PS: оверхед будет не большим, думаю займется не более 4% общего процессорного времени.

AndyBig
Probelzaelo:

Это зачем же им разные узлы делать в одном приемнике? если и одно и второе достаточно не сложные задачи для практически любого микроконтроллера, просто два программных блока очевидно работающих совершенно независимо друг от друга…

Я об этом и говорил. Узлы - я имел в виду функциональные узлы (программные блоки, подпрограммы - называйте как больше нравится) в одном контроллере 😃

Probelzaelo:

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

Для чего? Какой смысл в этом? Передатчик должен гнать пакеты с достаточной для плавного управления частотой, а приемник должен выдавать ШИМ с частотой, требуемой сервами. Нафига синхронизация между ними? 😃

Bare
Tester500:

Моя мыслЯ такая: Допустим нужно оцифровать сигнал с 8-битной точностью. Настраиваем таймер так, чтобы он выдавал прерывания каждую (2мс-1мс)/256. 2мс общая длина импульса, 1мс длительность сигнала до начала отсчета. Далее по прерыванию опрашиваем нужные порты-каналы. По изменению уровней (асинхронно для каждого канала) производим математические вычисления длины. Код изображу позже, счас уже думать нечем.

Если еще одновременно использовать библиотеку servo, то timer1 и timer3 заняты. Остается только timer2.

Bare

В прошлом сообщение написал ерунду.
Сейчас нашел в интернете
Документация по таймеру на ардуино
sites.google.com/…/tajmery-sceetciki-arduino
Документация по прерываниям на ардуино
…google.com/…/ispolzovanie-preryvanij-arduino

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

V_Alex
Tester500:

Моя мыслЯ такая:
Допустим нужно оцифровать сигнал с 8-битной точностью…

Для работы с сервой 8 бит мало, тем более, что оцифровываться будет цифровой сигнал, но как аналоговый, джиттер гарантирован. Кроме того, нужно знать алгоритм прохождения сигналов на выходе приемника, пачкой одновременно с порта контроллера или последовательно со сдвигового регистра.
Наличие синхронизации приемника и передатчика также желательны - это резко упрощает задачу.

Boroda

Давайте рассуждать логически, с колокольни разработчика приёмника. Кристалл с 8-12-ю аппаратными ШИМ генераторами на борту будет слишком дорогой и громоздкий для данного применения. Для четырёхканального приёмника городить раздельный шим тоже не имеет смысла, мало кто будет втыкать в него дорогущие цифровые сервы. С точки зрения программера наиболее логичный вариант - крутить однобитовый шаблон в выходном порту по прерыванию таймера. По сути - тот же сдвиговый регистр, только программный. Во всех встречавшихся мне цифровых FM примниках так и было, так я делал сам, и так работают DSM2 оранжики. Могу проверить ещё турнигу ради интереса.

Можно считать, что большинство примников не выдают одновременно сервосигналы на нескольких ногах, и лишь некоторые дорогие многоканальные модели способны на это. С принятием такого ограничения на полную совместимость задачка многоканального захвата значительно упрощается. Выходы примника подаются на порты ввода меги и на базы транзисторов. Их коллекторы совершенно в штатном режиме соединяются с ногой ICP1 по схеме “монтажного ИЛИ-НЕ”, и включается аппаратный захват TCNT1 по ICR. В процедуре прерывания анализируется уровень на портах, и вычисляется длительность именно того сервоимпульса, завершение которого вызвало прерывание.

V_Alex

В варианте “программного сдвигового регистра” возникает ограничение на количество каналов приемника. В старых РРМ приемниках наличие синхропаузы ограничивало канальность 7-8 каналами для такта до 25 мс (40 Гц). Если сэкономленную синхропаузу задействовать под дополнительные каналы, можно добавить еще пару-тройку каналов. В такт 20 мс (50 Гц) можно воткнуть по-хорошему 10 “сдвиговых” каналов по 2 мс. В то-же время генерация пачкой, несколькими пачками или с наложением канальных импульсов такое ограничение снимает. Для сервы главное, чтобы генерируемый импульс был “съедобным”.

msv
Boroda:

Давайте рассуждать логически

Если бы не было других реал-тайм задач (как минимум прием и анализ PPM посылки), c логикой и выводами может и можно согласиться… А в реале в этом случае слишком велика вероятность оказаться в одном прерывании при срочной необходимости обрабатывать другое. Я бы, со своей колокольни, никогда бы так не делал (и не делаю…).
Да и вообще о чем речь? Если делать для себя любимого, можно из приемника вытащить исходный PPM (если он там есть…). Если в глобальном масштабе- по любому надо быть готовым, что декодер приемника не обязан выдавать канальные PWM с определенным, нам удобным, фазовым сдвигом…

V_Alex:

В такт 20 мс (50 Гц) можно воткнуть по-хорошему 10 “сдвиговых” каналов по 2 мс.

А как тогда делать синхронизацию?..

V_Alex
msv:

Если в глобальном масштабе- по любому надо быть готовым, что декодер приемника не обязан выдавать канальные PWM с определенным, нам удобным, фазовым сдвигом…

Именно так. Единого стандарта нет и, скорее всего, уже не будет никогда.
Да и РРМа в приемнике скорее всего не обнаружится. Входит цифра, проверяется и сразу перегоняется в цифру.

Tester500
V_Alex:

Для работы с сервой 8 бит мало, тем более, что оцифровываться будет цифровой сигнал, но как аналоговый, джиттер гарантирован.

8бит для примера, оно хоть 16 можно. Вот далее каша, что значит “оцифровываться будет цифровой сигнал”? Когда PPM успел стать цифровым? Каналы приемника демультиплексированный PPM, оно так задумывалось задолго до первого микроконтроллера, и работало в полном аналоге. Джиттера не будет, откуда он там.
И зачем знать алгоритм прохождение и прочее, если достаточно в ТЗ предусмотреть самый сложный асинхронный режим. Решение задачи от этого не пострадает.

Bare:

Сейчас нашел в интернете
Документация по таймеру на ардуино

Блин, для winavr у меня все есть, пришлось качать для ардуины, счас сижу и разбираюсь в ихних стандартах. Оно там сишное, только свои обозначения переменных (ноги,таймеры, и т.д.).
PS: вообще подобные вещи лучше затачивать сразу под некое подобие RTOS, легче будет добавлять функционал, при ограниченных аппаратных ресурсах.

Bare:

Пытаюсь понять исходники библиотеки servo, немного не хватает знаний.

Помогу, в этой библиотеке:
Servo - Class for manipulating servo motors connected to Arduino pins.
Это для управления сервоприводами, которые висят на ногах контроллера.

AndyBig
Tester500:

Когда PPM успел стать цифровым? Каналы приемника демультиплексированный PPM, оно так задумывалось задолго до первого микроконтроллера, и работало в полном аналоге.

Так то когда было. Вы посмотрите какие сейчас чипы стоят в передатчиках - они в принципе не умеют формировать PPM. У них на выходе пакеты цифры с различного типа модуляцией.

V_Alex:

Да и РРМа в приемнике скорее всего не обнаружится. Входит цифра, проверяется и сразу перегоняется в цифру.

Вот именно.

V_Alex
Tester500:

8бит для примера, оно хоть 16 можно. Вот далее каша, что значит “оцифровываться будет цифровой сигнал”? Когда PPM успел стать цифровым? Каналы приемника демультиплексированный PPM, оно так задумывалось задолго до первого микроконтроллера, и работало в полном аналоге. Джиттера не будет, откуда он там.

Так и было, пока в шифраторе передатчика стояла NE5044, а на выходе приемника 4015. А в контроллерных шифраторах передатчиков аналоговый сигнал оцифровывается в АЦП и в режиме РРМ уходит в эфир с соответствующей дискретностью. Войцеховский когда-то писал, что 16 бит - выше крыши, а нынче гурманам 4096 подавай. Если и в приемнике стоит контроллер, пришедший канальный импульс до подачи на серву оцифровывается еще раз. Если и серва используется дешевенькая цифровая (третья оцифровка), можно столкнуться с весьма занимательными спецэффектами. А вроде один и тот-же РРМ.

Tester500
AndyBig:

Так то когда было. Вы посмотрите какие сейчас чипы стоят в передатчиках - они в принципе не умеют формировать PPM. У них на выходе пакеты цифры с различного типа модуляцией.

Турнига, та самая - дешевая. Да, у нее внутри Atmega168, но между контроллером и передатчиком PPM (если не выбран PCM). Без разницы чем и как формируется PPM - ЛА3 в режиме генератора или 555 или на транзисторах или контроллер. Суть PPM не меняется - он аналоговый. Цифровой это PCM. Вот в нем не времянки гуляют, а вполне конкретное число.

V_Alex:

А в контроллерных шифраторах передатчиков аналоговый сигнал оцифровывается в АЦП и в режиме РРМ уходит в эфир с соответствующей дискретностью.

А если на входе оно будет не оцифровываться а сразу кодироваться энкодером, то PPM чем станет? В эфир оно уходит не дискретно, а промодулировано несущей частотой, или вообще кодировано. Большинство 2.4 Ггц приемников-передатчиков цифровые, они оцифровывают входящий сигнал и используя алгоритмы сжатия-кодирования-декодирования коррекции ошибок и т.д. Но в данном случае это к топику не относиться.

V_Alex:

а нынче гурманам 4096 подавай

не совсем понятно, если серва делает 360гр, то 360/4096=на один шаг ~0.088гр
нашиша? палец на стике этого не поймет. 😃
Другое дело если народ из одного канала делает кучу дискретных, но счас проще перейти на PCM.

AndyBig
Tester500:

Да, у нее внутри Atmega168, но между контроллером и передатчиком PPM (если не выбран PCM). Без разницы чем и как формируется PPM - ЛА3 в режиме генератора или 555 или на транзисторах или контроллер. Суть PPM не меняется - он аналоговый.

Я говорил о передатчике. О ВЧ-модуле. Посмотрите какая микросхема там стоит в качестве передатчика, выдающего готовый к эфиру ВЧ-сигнал.
Промежуточный PPM между аппой и передатчиком - дань универсальности, чтобы можно было поставить другой ВЧ-модуль и он работал. И это не только в дешевой турниге. Сам радиомодуль оцифровывает PPM и в эфир уходят пакеты байтов. Так что если в приемнике производитель специально не озадачился сформировать PPM из приходящих данных (так, на всякий случай, вдруг кому понадобится), то его там и не будет 😃

V_Alex

В Турниговском РРМ длительность импульса меняется дискретно, у классики - плавно. Разница, как между винилом и МР3.
То, что оставлен РРМ при передаче, дань старому стандарту совместимости аппаратур. На этапе между приемником и сервой это и сейчас основной стандарт. Не хотят фирмы терять покупателей, вот и диназаврят помаленьку, многократно перегоняя цифру в аналог и обратно, теряя в качестве сигнала на каждом преобразовании.
А энкодер можно, но дорого. Даже хороший потенциометрический датчик стоит дороже турниги целиком.

Boroda
msv:

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

Эту проблему не так уж и трудно разрулить продуманой организацией тайминга и блокирующими прерываниями. Про программный сдвиг - я не говорил, что это есть хорошо. Я лишь сказал, что пока почти все делают так. Если это не коммерческая тайна, расскажите о взгляде с вашей колокольни, как, а если точнее, то на чём бы вы сделали независимую раздачу сигнала на сервы? Коммерческий проект, восьмиканальный приёмник среднего ценового уровня, дискретность… скажем всего 10 бит?

msv:

Если в глобальном масштабе- по любому надо быть готовым, что декодер приемника не обязан выдавать канальные PWM с определенным, нам удобным, фазовым сдвигом…

Да, я высказал мысль, что в ближайшие 2-3 года в большинстве случаев как раз можно быть готовым к удобному для нас фазовому сдвигу. Готов свои слова подтвердить осциллограммами, правда с не очень широким охватом рынка. Буду искренне рад, если моё предположение с треском опровергнут таким же способом.

msv

В моем проекте прием PPM и генерация канальных PWM далеко не основные задачи, решаются максимально простым способом- захват PPM через ICP, вывод- аппаратным ШИМ.
Реализация декодера на проце дает большие возможности обработки входного сигнала чем простой сдвиговый регистр (как мин. простейшая проверка достоверности пакета, реализация failsave), поэтому кажется вполне логичным подобное решение (кстати когда-то повторял и был вполне доволен его работой).

Boroda:

Да, я высказал мысль, что в ближайшие 2-3 года в большинстве случаев как раз можно быть готовым к удобному для нас фазовому сдвигу.

Уже много лет периодически попадаются сообщения, что некоторые устройства, рассчитанные именно на последовательную генерацию канальных импульсов, работают далеко не со всеми приемниками именно из-за синхронной генерации этих импульсов. К сожалению не помню конкретные модели…