Управление ШИМ

Тема в разделе "Схемотехника, компоненты, модули", создана пользователем Игорюшка Владимирович, 12 май 2016.

  1. Энкодер подключён к 2 и 3 пинам Ардуино, на которых возможно управление прерываниями.
    Как одновременно с его работой считать два кнала Р.У. , которые выдают ШИМ ?
    Энкодер считает путь и определяет направление, но надо ещё посредством "обычного" 2.4 МГц приёмника управлять скоростью движения и поворотом. Возможно ли это на А328 ?
     
  2. Alex19

    Alex19 Гуру

    Честно говоря, мне не до конца понятен вопрос.
    Поэтому будут вопросы.

    На 2 и 3 пине прерывания энкодера, тут все просто. К слову у Atmega328, кроме обычных прерываний, есть прерывания порта (PCINTx). Кстати, что за энкодер, лучше, какой у него сигнал?

    У Вас есть 2 канала, которые возвращают ШИМ, Вам требуется узнать ширину импульса (время между High и Low). Если я правильно Вас понимаю, то на какие пины заведены эти каналы и как снимаете показания pulseIn или таймером?

    Да возможно.
     
  3. Энкодер "из" двух датчиков
    http://duino.ru/Datchik-prepyatstvii.html .
    Когда датчики срабатывают хорошо - считает правильно и вперёд и назад. Но очень маленький "гистерезис" - т.е. настроить чЮЙствительность в них оч трудно и со временем (например, уже с утра) начинает пропускать переключение - там светАдиоды и видно срабатывание самого датчика. Они "вродИ" с цифровым выходом.
    Я только пытаюсь понять, как это сделать, чтобы не мешать энкодеру : pulseIn
    http://arduino.ua/ru/prog/PulseIn сможет ли "работать сразу с двух ног", измеряя ШИМ ?
     
  4. Alex19

    Alex19 Гуру

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

    Источник - http://cxem.net/uprav/uprav39.php.

    Возможно нужно детальнее изучить их или заменить.

    Надо глянуть, сейчас надо преваться.
     
  5. Спасибо -
    считывая ШИМ с двух каналов сразу, я смогу, в зависимоти от показаний пройденного пути, повернуть сервой в автоматическом режиме.
    Один канал заранее "выставит" (на расстоянии передатчика) начальный угол сервы, а ардушка его запомнит,
    второй - заранее "выставит" скорость поворота (или конечный угол сервы - ограничение ), и ардушка её (или его) тоже запомнит.
    Собственно, это "дистанционная настройка режимов" работы одной сервы, но она "привязана" к расстоянию от энкодера, поэтому хочется выполнить всё на "одном корпусе" А328.
    Сама машинка тоже управляется передатчиком, но "эти" каналы не задействованы в ардушке :).
     
  6. Alex19

    Alex19 Гуру

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

    Если разобраться с этим, то проблем с подключением и настройкой нет, можно использовать 2, 3 ножку. Можно к примеру 7 и 8 или других (прерывание PCINT), с этим проблем нет, будут вопросы готов пояснить.

    По pulseIn
    И так из описания тут - http://arduino.ua/ru/prog/PulseIn
    Не поверим:), и заглянем в код.Сам pulseIn - https://github.com/arduino/Arduino/...ware/arduino/avr/cores/arduino/wiring_pulse.c

    Там вызов countPulseASM - https://github.com/arduino/Arduino/.../arduino/sam/cores/arduino/wiring_pulse_asm.S

    Вот эта функция вся в while. Если проверять 2 канала с помощью pulseIn, работать это будет так.
    1. Измеряем длину импульса 1 канала. Если в это время происходит изменение длительности импульса 2 канала мы это пропустим.
    2. Измеряем импульс 2 канала. Если в это время происходит изменение длительности 1 канала, мы это пропустим.
    Подходит ли Вам это надо смотреть сам сигнал, к слову у Вас не ШИМ а PPM (или как он там называется), подробнее тут - http://wiki.amperka.ru/робототехника:сервоприводы.

    Так же когда-то читал, не могу вспомнить где, что использование с pulseIn с прерываниями, это зло.

    Как я бы делал, энкодер на 2 и 3 пин или на канал PCINT. А определение длины импульса на PCINT, вот пример - http://www.instructables.com/id/RC-Quadrotor-Helicopter/step12/Arduino-Demo-PWM-Input/ шаг 12. Или тут, проект MultiWii - https://github.com/multiwii/multiwii-firmware/blob/upstream_shared/RX.cpp, идея почти такая же, но посложнее. Если надумаете идти таким путем пишите, подскажу.

    UPD.

    Не совсем понимаю, зачем это если их можно задать прямо в коде, возможно Вы динамически их меняете, но и это возможно.

    Тут не понял, что значит расстояние от энкодера, оно меняется?

    Если немного выйти за рамки стандартных библиотек Arduino, то не вижу проблем, если оставаться в их рамках, то они будут.
     
    Последнее редактирование: 12 май 2016
  7. Вах ! Эт надо переварить....
    Итак - Дано:
    Уже работающий энкодер, который уже выводит от 0 до 9999 см на четырёхразрядный семисегментник
    http://forum.amperka.ru/threads/Как-подключить-led-display-module-for-arduino-595-driver.8322/#post-74658
    учитывая направление - прибавляет или вычитает.
    Энкодер подключён к 2 и 3 пинам. Индикатор к 7,6,5 пинам.
    Серву планирую подключить к любому с вых ШИМ. Она будет в каждый момент времени (проход Луп) "показывать направление" в соответствии с пройденным расстоянием - т.е.
    каждой точка - свой угол. Вычисляется по формуле треугольника относительно конкретного места на пути (которое показывает индикатор).
    Задача :
    Выставить и запомнить два угла сервы (диапазон изменения - от и до) именно с пульта (не приближаясь к машинке.
    А для этого надо :
    считывать ШИМ с двух свободных выводов АТ386 и
    держать их в виде двух постоянно обновляемых переменных в ардушке.
    Вопрос - как реализовать эту процедурку, не мешая энкодеру.
    Собственно, я только начинаю осваивать азы и PulseIn() ещё не использовал, а тем более "два впараллель".

    Корректный термин — PDM (Pulse Duration Modulation). В нём крайне важна длина импульсов и не так важна частота их появления.
    Т.е. надо измерить длинну...
     
    Последнее редактирование: 12 май 2016
  8. За время моего пребывания на этой планете ни один иностранный язык мной так и не овладел, а технический гулоперевод для непосвящённого - ещё хуже.Я видел эту статью, но не рискнул вникнуть :rolleyes:.
    Надо сначала понять принцип, как работает.... :oops:

    void setup()
    {
    DDRC = 0; // pins as input
    // enable PCINT 18 to 23
    PCICR |= (1 << PCIE2);
    PCMSK2 = 0xFC;
    Serial.begin(115200);
    }

    typedef struct {
    byte edge;
    unsigned long riseTime;
    unsigned long fallTime;
    unsigned int lastGoodWidth;
    } tPinTimingData;
    volatile static tPinTimingData pinData[6 + 1];
    volatile static uint8_t PCintLast;

    ISR(PCINT2_vect)
    {
    uint8_t bit;
    uint8_t curr;
    uint8_t mask;
    uint32_t currentTime;
    uint32_t time;
    // get the pin states for the indicated port.
    curr = PINC & 0xFC;
    mask = curr ^ PCintLast;
    PCintLast = curr;
    currentTime = micros();
    // mask is pcint pins that have changed.
    for (uint8_t i=0; i < 6; i++) {
    bit = 0x04 << i;
    if (bit & mask) {
    // for each pin changed, record time of change
    if (bit & PCintLast) {
    time = currentTime - pinData.fallTime;
    pinData.riseTime = currentTime;
    if ((time >= 10000) && (time <= 26000))
    pinData.edge = 1;
    else
    pinData.edge = 0; // invalid rising edge detected
    }
    else {
    time = currentTime - pinData.riseTime;
    pinData.fallTime = currentTime;
    if ((time >= 800) && (time <= 2200) && (pinData.edge == 1)) {
    pinData.lastGoodWidth = time;
    pinData.edge = 0;
    }
    }
    }
    }
    }

    void loop()
    {
    Serial.println();
    for (byte i = 0; i < 6; i++) {
    Serial.print("C");
    Serial.print((int)i + 1);
    Serial.print(": ");
    Serial.print(pinData.lastGoodWidth);
    Serial.print(", ");
    }
    delay(500);
    }


    - это разве для унки ? :confused:
     
  9. Alex19

    Alex19 Гуру

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

    Энкодера там не видно, но не суть, главное тут
    Для сервы и библиотеки Servo не нужен пин с ШИМ-ом, ей нужен таймер 1 и цифровой пин (при этом мы потеряем ШИМ на 9 и 10 пине).

    Честно говоря не понял, саму идею, может туплю. Машинкой мы ездим, выставляем какие-то улы для сервы и запоминаем их значение и изменение, пока в голове такая картина.

    Что еще подключено кроме 1 сервы, 2 каналов ШИМ (1 скорость, 2 поворот), энкодера и экрана?

    Постоянно обновляемых, все относительно.

    Если пока меняется 1 канал, может произойти изменения 2 канала и наоборот, то PulseIn тут не к месту. Если они меняются последовательно, то можно использовать PulseIn, если его точность Вас устраивает.

    Да с терминами у меня беда, мы говорим с Вами о длине.

    Знание языков сильно упрощает. Но без них можно жить.

    Как это работает в грубо, чтобы понять суть.
    Заводим прерывание порта, на любое изменение пинов, подключаем 2 канала к данному прерыванию. Срабатывает прерывание, проверяем какой канал. Смотрим HIGH, сохраняем начальное время из millis, ждем следующего прерывания, проверяем какой канал, если тот же убеждаемся, что LOW получаем конечное время из millis. Дальше отнимаем конечное от начального, так работает этот пример - http://www.instructables.com/id/RC-Quadrotor-Helicopter/step12/Arduino-Demo-PWM-Input/.

    Минус данного примера, есть неточность в определении времени, так как millis не изменяется в прерывании, но погрешность не велика.

    Вот пример прерывания PCINT для Atmega32u4 - https://github.com/SimpleRov/AVR/blob/master/Interrupt/Interrupt.cpp, делал на днях.
    void SetupPortInterrupt0() - настройка.
    ISR(PCINT0_vect) - прерывание.

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

    UPD 2.
    Не заметил.

    Нет ATmega644PA, но разница не велика. Чтобы было какое-то представление о PCINT, справочник регистров на русском - http://avrprog.blogspot.com.by/2013/03/extinterrupts.html, подробного описания на русском не нашел.
     
    Последнее редактирование: 13 май 2016
  10. Эт я так объясняю.
    Вот начало затеи. http://forum.amperka.ru/threads/Компютерная-мЫшь.8020/#post-71988

    Для ардушки это выглядит так :
    Есть прямая, по которой слева-направо (туда-типа-сюда) ездит РУ модель.
    Башня на серве. Тоже управляется одним каналом РУ.
    1.Вкл. режим "засечки цели" :
    РУ-ем наводим башню на статичную цель. (ардушка запоминает угол, считывая ШИМ со вх пина)
    РУ-ем едем мимо неё. (энкодер считает расстояние)
    стоп.
    повторно РУ-ем наводим башню на статичную цель. (и ардушка запоминает ВТОРОЙ угол - считывая ШИМ со вх пина)
    ГеомЭтрически "получается" треугольник с от-энкодеренным основанием и двумя заданными и запомненными ардушкой углами.

    2.ВКл режим слежения.
    ездим по (вдоль) основания треугольника - башня на цели (ардушка сама считает и отдаёт серве нужный угол ограниченный (а вернее : вычисленный! ) двумя ранее считанными с пина).

    Переключение режимов происходит так же по "команде" с другого ШИМ вх.

    На данном этапе - надо научиться
    считать ШИМ с двух свободных входов. Чтобы РУ переключать режимы и менять угол сервы. И ... не мешать энкодеру.
    13 и 12 тоже заняты под индикацию и уже работают. Нужен будет ещё одна нога под индикацию режимов "наведение" - "работа".
     
    Последнее редактирование: 13 май 2016
  11. Alex19

    Alex19 Гуру

    Теперь стало понятно, что Вы делаете.

    Хорошо, теперь понятно какие ноги свободны.

    Начнем, с прерываний по PCINT.

    9 и 10 пин не задействованы, к тому же при использовании библиотеки Servo мы потеряем встроенную поддержку ШИМ на этих пинах.
    Код (C++):

    // PCINT Arduino Nano (Atmega328).

    // Запоминаем регистр SREG и отключить прерывание.
    #ifndef MC_CRITICAL_SECTION_START
    #define MC_CRITICAL_SECTION_START  uint8_t _sreg = SREG; cli();
    #endif

    // Восстанавливаем регистр SREG.
    #ifndef MC_CRITICAL_SECTION_END
    #define MC_CRITICAL_SECTION_END    SREG = _sreg;
    #endif

    // Последнее значение порта B.
    volatile uint8_t lastValuePortB = 0;

    void setup()
    {
      // put your setup code here, to run once:
      Serial.begin(115200);

      // Канал 1, передатчика.
      pinMode(9, INPUT);
      // Канал 2, передатчика.
      pinMode(10, INPUT);

      // Настройка PCINT на 9 и 10 пин Arduino.
      // Порт B, бит 1 и 2 AVR.
      // PCINT1, PCINT2.

      MC_CRITICAL_SECTION_START

      // PCICR (Pin Change Interrupt Enable) - регистр разрешающий прерывания по изменению состояния группы выводов.
      // PCIEn - биты которые разрешают прерывания по изменению состояния группы выводов. Когда бит PCIEn и бит I регистра SREG установлены в 1 - прерывания по изменению состояния на группе выводов PCIEn разрешены.
      // Очищаем регистр разрещающий прерывания по изменению состояния группы выводов.
      PCICR |= (0 << PCIE0);

      // PCMSKn (Pin Change Mask Register) - регистр включающий выводы конкретной группы портов на прерываний по изменению состояния.
      PCMSK0 |= (0 << PCINT7) | (0 << PCINT6) | (0 << PCINT5) | (0 << PCINT4) | (0 << PCINT3) | (1 << PCINT2) | (1 << PCINT1) | (0 << PCINT0);

      // PCIFR (Pin Change Interrupt Flag Register) - регистр флагов прерываний по изменению состояния группы выводов. Указывает от какой группы поступило прерывание.
      // Очищаем регистр флагов прерываний по изменению состояния группы выводов.
      PCIFR = PCIFR & (1 << PCIF0);

      // PCICR (Pin Change Interrupt Enable) - регистр разрешающий прерывания по изменению состояния группы выводов.
      // PCIEn - биты которые разрешают прерывания по изменению состояния группы выводов. Когда бит PCIEn и бит I регистра SREG установлены в 1 - прерывания по изменению состояния на группе выводов PCIEn разрешены.
      PCICR |= (1 << PCIE0);

      MC_CRITICAL_SECTION_END
    }

    void loop()
    {
    }

    /// <summary>
    /// Прерывание по изменению состояния группы выводов 0.
    /// </summary>
    ISR(PCINT0_vect)
    {
      // Получаем измененные биты порта B.
      uint8_t changedBits = PINB ^ lastValuePortB;
      // Сохраняем последнее значение порта B.
      lastValuePortB = PINB;

      // Канал 1, передатчика.
      if (changedBits & (1 << PB1))
      {
        if (PINB & (1 << PB1))
        {
          // Тут будем засекать High на 9 пине Ардуино.
        }
        else
        {
          // Тут будем засекать Low на 9 пине Ардуино.
        }
      }

      // Канал 2, передатчика.
      if (changedBits & (1 << PB2))
      {
        if (PINB & (1 << PB2))
        {
          // Тут будем засекать High на 10 пине Ардуино.
        }
        else
        {
          // Тут будем засекать Low на 10 пине Ардуино.
        }
      }
    }
     
    Это не конечный код, пока само прерывание ISR(PCINT0_vect), просто набросал, чтобы была возможность понять. Надо будет разобраться как лучше реализовать само прерывание, возможно это будет облегченная версия - http://www.instructables.com/id/RC-Quadrotor-Helicopter/step12/Arduino-Demo-PWM-Input/.

    Теперь в вкратце о самом PCINTx, это прерывание на порт (по простому на группу пинов, до 8 пинов на прерывании).

    Основная разница между обычным прерыванием которое Вы используете для энкодеров:
    1. PCINT это прерывание на группу пинов до 8шт. Эта группа пинов заранее определена, мы можем лишь выбирать какие пины подключать к прерыванию, какие нет. Из-за этого, если пинов более 1, необходимо в самом прерывании проверять на каком пине произошло прерывание.
    2. PCINT не настраивается и срабатывает при любом изменении уровня LOW, HIGH. Необходимо в самом прерывании проверять уровень.

    Честно говоря, даже не знаю как пояснить данную тему, по сути она подымает множество тем, начиная от работы с битами заканчивая работой с прерыванием. А как понял у Вас нет опыта работы с AVR, поэтому наверно надо делать иначе. Сделать (просто саму может потребоваться аналогичное), а потом решайте, надо Вам это изучать или нет, если решить подскажем с чего начинать.

    Пока подумаю как лучше сделать прерывание и сохранение данных.
     
    Последнее редактирование: 14 май 2016
  12. ...Я этА .... кузнец ... в мирУ ...:rolleyes: НО :
    ...если я чего решил .... (Некто В.С. Высоцкий) :)
    Теперь мне надо денёк репку поморщить, чтоб хотя бы понять - принцип (как камнем управлять в данном случае надо исходя из вашего кода и ссылей). А дальше дело синтаксиса - дело наживное.
    Собственно, можно опуститься до уровня нескольких унок :
    одна энкодорит и считает,
    другая - принимает с приёмника и .... (тут может быть отдельная тема - чЮть ниже РеЛическое отступление)
    третья занимается сервами (- по жизни пушка ведь ещё и ... опускается !)

    ... Отступление (читать: мечты).
    РУ пульт - это не совсем удобные с точки зрения эргономики джойстики (именно для данного случая). Навести на цель можно ... либо точно, либо ... быстро ! :eek:
    Они имеют диапазон 1000мкс -2000мкс (вых с приёмниа) и ср точку около 1500мс. Т.е. влево-вправо, вверх-вниз. В данной ситуации "оператору" было бы сподручнее иметь:
    1. "слепую зону" в середине (около 5%-7%) от дрожания рук и случайного прикосновения.
    2. Джойстик (читать: приёмник) выдаёт прямую зависимость вых от наклона, а удобнее было бы так:
    "плавный" старт и чем сильнее наклон, тем быстрее серва отрабатывает "достижение" до предела (т.е. выше скорость её) и перед максимальным углом плавно останавливается. Конечно, если "оператор" вернёт стик в центр, движение "в сторону наклона" плавно прекращается.
    Этим бы и могла заняться "вторая" ардушка со "свободными" 2 и 3 пином.
    Правда Унки меж собой как-то общаться должны ... :rolleyes: :D.

    ... Но... будем думать по порядку (мозг человеку даётся один, и использовать его надо членораздельно :), а то лопнет.)
    И ещё. Спасибо вам за поддержку.
    (Если есть дежурная Лошадь - приводите. Я её это... подкую :))
     
  13. Alex19

    Alex19 Гуру

    Великий В.С. Высоцкий!

    Если говорить о данном коде, то тут по сути 4 элемента.

    1. Работа с битами, превосходная статья (по моему мнению) - http://chipenable.ru/index.php/prog...s-kak-rabotat-s-bitami-makroopredeleniya.html.
    Пояснит 0<< PCIE0, if((changedBits &(1<< PINB1))).
    2. Работа с портами - http://easyelectronics.ru/avr-uchebnyj-kurs-ustrojstvo-i-rabota-portov-vvoda-vyvoda.html.
    3. PCINT он полностью описан комментариями, там всего 3 регистра.
    4. Работа с прерываниями.

    Ну надо еще объединить их в сеть. Объединение в сеть, задача сложность которой зависит от требуемых характеристик сети и производительности.

    Слепую зону можно сделать, второе посложнее но то же можно.

    В любом случае, планирую cделать для себя, управление с этим джойстиком. Сегодня уже не доберусь, буду смотреть завтра. Так, что наши пути, частично совпадают.;)
     
  14. В искусстве (разработки эргонимики джойстиков) - главное вовремя остановиться, и темА не менее:

    Ещё один вариант (разновидность) "стиля реакции" Исп.Ус-ва на отклонение (почти "стандарт"):
    Серва плавно набирает скорость и плавно останавливается соответственно углу джойстика - т.е. "догоняет" его угол отклонения. Как буд-то я дёргаю не за стик, а за длинную резинку (пружинку), привязанную к стику. :)
    Может так и назвать "микропроект" - резиновый стик ?
    Тогда предыдущий вариант реакции стика будет ... надо придумать.

    Эт пока вообще не знаю.
    С "джойстивовой" уны - постоянно идут две переменные координат, переменные с разрешением сервы и может ещё один канал - "служебный" - выстрел, фонари, ... переключение режимов...
    С энкодерной - направление и расстояние.
    На "сервячной" унке - пересчёт двух серв, релюшки фонарей, ... и вх.переключения режимов - непосредственное управление с пульта для наводки обоими сервами и работа "в автомате" удержания цели.
    Собственно - все данные идут в последнюю на исполнение и их "не так много".
    ...Сегодня лазерный фонарик пришёл в пушку !! :rolleyes:
     
    Последнее редактирование: 13 май 2016
  15. ИгорьК

    ИгорьК Гуру

    Точно помню. Есть устройство типа маленькой видеокамеры для Ардуино, которое решает Вашу задачу - удержание направления на цель и сопровождение её. 100% есть у буржуев по цене около 200 американских рублей.
     
  16. Да будь у меня
    мы бы уже все в лёжку лежали !! :D
    Конечно, и на более мощных ....дуинках есть сиСьтемы распознавания лица (и в мыльницах за 2тыс русских рублей - для фокусировки). А я лично (лет ...много назад) видел, как веб-камера за мужуком следила, поворачиваясь (может на тепло?). Да и сейчас в видео наблюдении наверняка такое применяется - срабатывание на изменение картинки и т.д.. Но... распознать дерево или мишень или (.т.е.) ничего кроме лица эти системы не могут.
    К-тому-же-мы-же не ищем лёгких путей. :)
    ХочЮ хоть чуть-чуть ардушкам научиться, а моргающие светАдиоды уже не возбуждают (годы, наверное :rolleyes: ).
    Присоединяйтесь, барон ! ( - соотечественники б.Мюнхаузена) - в УмД-ах ведь нужны сисЬтемы позиционирования спутниковых антенн (а-ля ААТрекер) или ПТZ-образные камеры или ...:)
     
    Последнее редактирование: 14 май 2016
  17. ...дорога всегда вдвое короче, когда рядом хороший попутчик ! (Некто Саид из пустыни) :)
     
  18. Alex19

    Alex19 Гуру

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

    Итак готовый код на 2 канала, 1 канал на 9 пине, 2 канал на 10 пине.
    Код (C++):
    // PCINT Arduino Nano (Atmega328).

    #ifndef MC_CRITICAL_SECTION_START
    #define MC_CRITICAL_SECTION_START  uint8_t _sreg = SREG; cli();
    #endif

    #ifndef MC_CRITICAL_SECTION_END
    #define MC_CRITICAL_SECTION_END    SREG = _sreg;
    #endif

    // Переменная в которой храним время перехода в HIGH для 1 канала.
    volatile uint32_t timeRisingCh1 = 0;
    // Длина импульса в микросекундах для 1 канала.
    volatile uint32_t valuePDMCh1  = 0;
    // Переменная в которой храним время перехода в HIGH для 2 канала.
    volatile uint32_t timeRisingCh2 = 0;
    // Длина импульса в микросекундах для 2 канала.
    volatile uint32_t valuePDMCh2 = 0;
    // Переменная в которой храним последнее значение порта B.
    volatile uint8_t lastValuePortB = 0;

    void setup()
    {
      // put your setup code here, to run once:
      Serial.begin(115200);

      pinMode(9, INPUT);
      pinMode(10, INPUT);

      // Настройка PCINT на 9 и 10 пин Arduino.
      // Порт B, бит 1 и 2 AVR.
      // PCINT1, PCINT2.

      MC_CRITICAL_SECTION_START

      // PCICR (Pin Change Interrupt Enable) - регистр разрешающий прерывания по изменению состояния группы выводов.
      // PCIEn - биты которые разрешают прерывания по изменению состояния группы выводов. Когда бит PCIEn и бит I регистра SREG установлены в 1 - прерывания по изменению состояния на группе выводов PCIEn разрешены.
      // Очищаем регистр разрещающий прерывания по изменению состояния группы выводов.
      PCICR |= (0 << PCIE0);

      // PCMSKn (Pin Change Mask Register) - регистр включающий выводы конкретной группы портов на прерываний по изменению состояния.
      PCMSK0 |= (0 << PCINT7) | (0 << PCINT6) | (0 << PCINT5) | (0 << PCINT4) | (0 << PCINT3) | (1 << PCINT2) | (1 << PCINT1) | (0 << PCINT0);

      // PCIFR (Pin Change Interrupt Flag Register) - регистр флагов прерываний по изменению состояния группы выводов. Указывает от какой группы поступило прерывание.
      // Очищаем регистр флагов прерываний по изменению состояния группы выводов.
      PCIFR = PCIFR & (1 << PCIF0);

      // PCICR (Pin Change Interrupt Enable) - регистр разрешающий прерывания по изменению состояния группы выводов.
      // PCIEn - биты которые разрешают прерывания по изменению состояния группы выводов. Когда бит PCIEn и бит I регистра SREG установлены в 1 - прерывания по изменению состояния на группе выводов PCIEn разрешены.
      PCICR |= (1 << PCIE0);

      // Сохраняем последнее значение порта B.
      lastValuePortB = PINB;

      MC_CRITICAL_SECTION_END
    }

    void loop()
    {
      // Забираем полученные значения.
      MC_CRITICAL_SECTION_START
      uint32_t tempValuePDMCh1 = valuePDMCh1;
      uint32_t tempValuePDMCh2 = valuePDMCh2;
      MC_CRITICAL_SECTION_END

      // Печатаем полученные значения в Serial.
      Serial.print("Ch1 - ");
      Serial.println(tempValuePDMCh1);
      Serial.print("Ch2 - ");
      Serial.println(tempValuePDMCh2);
    }

    /// <summary>
    /// Прерывание по изменению состояния группы выводов 0.
    /// </summary>
    ISR(PCINT0_vect)
    {
      // Получаем измененные биты порта B.
      uint8_t changedBits = PINB ^ lastValuePortB;
      // Сохраняем последнее значение порта B.
      lastValuePortB = PINB;

      uint32_t currentTime = micros();

      // Проверяем изменилось состояние пина 9.
      if (changedBits & (1 << PB1))
      {
        if (PINB & (1 << PB1))
        {
          // Тут будем засекать High на 9 пине Ардуино.
          timeRisingCh1 = currentTime;
        }
        else
        {
          // Тут будем засекать Low на 9 пине Ардуино.
          valuePDMCh1 = currentTime - timeRisingCh1;
        }
      }

      // Проверяем изменилось состояние пина 10.
      if (changedBits & (1 << PB2))
      {
        // Длина импульса в микросекундах для 2 канала.
        if (PINB & (1 << PB2))
        {
          // Тут будем засекать High на 10 пине Ардуино.
          timeRisingCh2 = currentTime;
        }
        else
        {
          // Тут будем засекать Low на 10 пине Ардуино.
          valuePDMCh2 = currentTime - timeRisingCh2;
        }
      }
    }
    Сейчас надо отъехать, вернусь готов пояснить.
     
  19. Alex19

    Alex19 Гуру

    Честно говоря данные пульты управления я не сильно жалую. Основные причины:
    1. Малое кол-во каналов, стандартные 4,6. Те, что имеют большое кол-во каналов, дороговаты.
    2. Не видел с поддержкой разных типов каналов. Сейчас столкнулся с ESC работающих в режиме PWM (ШИМ), наверно есть пульты с управлением через ШИМ.

    Куда более приятны PS2 джойстики или от других игровых контролеров. Просто у меня был такой пульт, решил подключить и проверить, а он уже не дышит. Планировал подключить к нему валяющиеся ESC с моторами.

    Можно сделать все, что можно объяснить логическим языком. Если так, то так и т.д. Главное, чтобы ресурсов контролера хватило, или переходить на другие.

    Мне доводилось делать сеть на RS-485, в сети полно примеров на других интерфейсах, но если требования к скорости, надежности высоки, требуют знаний и времени.

    Моя задумка подключить к данному джойстику ESC провалилась. Во первых он умер, а во вторых, те ESC, что хотел подключить работаю с PWM 8Khz. Придется остаться на обычных PS2 джойстиках, проводные без проблем, а вот с радио все руки не доходят проверить.

    UPD. Сейчас разбираюсь как подключить эти ESC c PWM 8Khz, а из документации, только мануал на китайском:(.
     
  20. И у меня шильдо-груз завёлся ! Теперь будет, на чём попробовать !
    http://forum.amperka.ru/threads/Самодельная-Унка.8200/page-2#post-75105
    Вопросы ... на стадии формирования ...осознания окружающей действительности ...посредством чтения скетча ....
    Мучительно подбираю слова .... :)