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

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

  1. Alex19

    Alex19 Гуру

    Поздравляю!
    Сам пока не осилил создание Ардуин, никогда не требовалось, да и паять я особо не умею. Есть друг он за меня паяет, я за него программирую:).

    Ну когда появится время.
     
  2. Честно говоря я ещё PWM от ШИМ ... не особо отличаю, но
    1. 100руб серва работает и от приёмника и от Унки и от ... сервотестера за 200руб
    http://air-hobby.ru/katalog/product/1280-servotester.html
    2..Желтопузый (безкварцевый) ЕСК 500руб в базарный день (народная жёлто-золотая серия) работает от
    приёмника, сервотестера и ... к унке ещё не подключал, но - одно ваше слово ...
    Из чего делаю "неосторожный вывод", что все эти "ис-точники" управляющего сигнала порой взаимозаменяемы.
    Вечером, кстати, чистА ради любо - пытства втЫкну ! :)
    Т.е. то (например, скетч), от чего работает серва , даст жизни и регулю.
    ****************
    Не к ночи сказано:
    В момент подачи 12В на регуль, на его входе должно быть не больше 1000мкс ШИМ(?)
    Иначе он может подумать, что хозяин решил его перепрограммировать и уйдёт в режим настроек. Например так я надысь вкл режим торможения движка и вкл "Динго-беее":

     
    Последнее редактирование: 14 май 2016
  3. Alex19

    Alex19 Гуру

    Разобрался со своим пультом, оказалось работает. Когда-то давно мне сделали из 4 канального, 6-ти и тумблер переключения, вот я про него и забыл.:(

    Сам только сегодня узнал о ШИМ из описания своего ESC, перевод с китайского.
    Если правильно понимаю, 8,16, 32Khz ШИМ, по умолчанию он настроен на 8Khz. Но он запустился от моего пульта который выдает PPM и тут я вошел в ступор.

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

    Да сам был удивлен, что сигнал разный.

    Библиотека Servo запустит как обычную серву, так и обычный ESC, проверено не однократно.

    Да знаю о таком моменте.

    ШИМ это не PPM (PDM), но их его часто путают. Вот и думаю, может китайцы, чего напутали, но тогда не понятно что такое 8Khz. Возможно о расстоянии между импульсами, сейчас попробую заставить работать. Сделать ШИМ 8Khz, если не пойдет попробовать посмотреть как сделать PPM (PDM) с растоянием между импульсов в 8Khz.
     
  4. По старому русскому обычаю ... многие веСЧи особенно хорошо получаются втроём. В Швеции, например, это понимают несколько странно... К чему это я ... Ах да - вот . Могу выдавать идеи с неприличной для своих знаний (да и знания вопроса вообще) скоростью. :rolleyes:
    А пайка - школа молодого бойца - надо разок через руки пропустить, а потом буду кака все взрослые дядьки микры-Шмикры покупать - и по цене тоже самое и та же лотерея.
     
  5. Alex19

    Alex19 Гуру

    Эх найти бы время на реализацию всех интересных и стоящих идей, пока я погрузился в свой Rov c головой - http://forum.amperka.ru/threads/Проект-simplerov.7788/. По этому пока не могу отвлекаться ни на что другое.

    У меня и простая паяльная станция есть, но нет времени и пока я устроился хорошо, за меня делают;).
     
  6. Если бы не зрение ! - там и паять-то нечего... А то ткнул - линза - ткнул -линза... ювелир (Мать ...мать привычно откинулось Эхо). Надо ЮСБ микроскоп купить, но он тоже при пайке мешается, ско ....
     
  7. моя - 400рублекитай. :)
     
  8. Alex19

    Alex19 Гуру

    У меня есть настольная линза с подсветкой, очень полезная вещь.

    Моя дол. 50 но тоже Китай, но дело не в техники а в мастере;).

    ESC на сегодня отложил. Там используется обычный PPM (PDM), от ардуины пока запустил только в 1 сторону. С другими фирменными ESC, проблем не было, гонял в обе стороны, а Китаец на сдается. Видимо глаз замылился.
     
  9. Нет - пока прошивка не моего уменья дело. Я читал, что на некоторые регули ЕСТЬ уже прошивки с реверсом, но неудачная прошивка гасит их (в частности мосфеты) кака свечки, а ждать даже дешОвые регули по месяцу терпелка не позволяет. Поэтому не берусь. :oops: Мне проСЧе купить время в виде готового изделия с ХобиК-а, например. Можно и костыли с твёрдотельными релюшками - фазу перекидывать, но для быстрой автоматики это извращение.
    Тоже хочЮ, но наехал на эту тему буквально месяц назад - обрастаю больше хламом, чем полезняшками...:)
     
  10. Alex19

    Alex19 Гуру

    Так и есть прошивка не обычная, обычный ESC от ХобиК-а. Но раз он работает от пульта в обе стороны, а от Ардуины только в одну, значит беда в моей коде:(.

    У меня есть 4 фирменных для автомобилей с реверсом как раз для Rov. Китайцев хочу запустить, так как не каждый может позволить такие ESC по 30 дол. шт., а китайцев можно купить комплект из 4 за 40 дол. Проект делаю открытым и кто захочет повторить, сможет сэкономить. Так же они меньше по габаритам и весу, что является бесспорным плюсом.

    Вещь полезная, но и хлама у меня как всех хватает:).

    Извините за паузы, много дел.
     
  11. По идее (по описи от автомобильного) ХобиВинг, например - самотестирующаяся... система. Значит она при старте должна вход опросить и принять его за серединКу рычага - т.е 1500мксек, а вот как там калибровка газа заложена вааще не понимаю.
    Вот НЕ кстати - я включал пульт значительно позднее приёмника, значит на входе авторегуля (с реверсом) при ЕГО включении (ДО вкл передатчика ... ) ничего не было ?
    Как тогда он середину газа определил ?:confused:
     
  12. Alex19

    Alex19 Гуру

    Середину газа определил просто, подключил пульт и снял данные показания. Середина у меня 1,521ms, максимум в 1 сторону 1,874ms, в другую 1,119ms. Стартовал, затем выставлял нейтральную позицию, ждал 5 сек. и отправлял импульсы соответствующей длины. И при этом всегда крутился в 1 сторону, а при отправке 1,119ms стоит. Поэтому когда зашел в тупик, решил прерваться.

    У меня так пульт от блока питания всегда включен, включаю второй блок который питает ESC, жду пока ESC пропоет о готовности, дальше все работает. ESC питает приемник, поэтому после включения он смотрит на стик и сообщает о готовности.
     
  13. Так эт у вас, а кака "фирма" распознаёт если юзверь позабыл пульт включить ?!
    А мож он так .... запрограммировался (не прошился !) Вдруг надо его ввести в режим настроек и вкл реверс :
    переключение на реверс ведь бывает "нескольких видов", в зависимости от типа испоЛзуемых пультов - есть курковые, например и там надо кратковременно затормозить, регуль должен полностью остановиться, и только потом ... и.т.д. и.т.п.
    Вот тут по-правильному
    https://yadi.sk/public/?hash=IqCZXVj6czdgrmaq0N29l0/7n7ooca77iUSIOAObeCs=
    ... со слов только вперёд ... так что не фаКт, что не работает.
     
    Последнее редактирование: 15 май 2016
  14. Alex19

    Alex19 Гуру

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

    Реверс уже включен, иначе бы он не работал в обе стороны от пульта.

    Сам реверс работает, не работает мой код. Сегодня может не доберусь, много других дел, может вечером вернусь к поиску проблемы.
     
  15. Не прошло и пол-года ...
    Прототип1.jpg
    И вАще ... Кто не спрятался, а гусь ... в лес смотрит :).
    Теперь надо придумать блок питания, т.к. 300мА оказалось мало-вато....
     
    Alex19 нравится это.
  16. Alex19

    Alex19 Гуру

    Там использована та же идея, для определения длины импульса. В моей последнем коде, длина импульса хранится в переменных valuePDMCh1, valuePDMCh2. После получения данных можно будет передать их map и т.д.

    Единственное, чем можно дополнить в данном коде, произошло ли изменение длины импульса и еще 1 мелочь увидел, но это относится к скорости выполнения прерываний.

    Будут вопросы пишите, правда сейчас с головой погрузился в металлообработку, но буду стараться отвечать по вечерам.
     
  17. Alex19

    Alex19 Гуру

    Добрался до компьютера.

    Вот код.
    Код (C++):

    // PCINT Arduino Nano (Atmega328).

    #define PIN_PORTB_MASK B00000110

    #define PIN_CHL_1     9
    #define PIN_CHL_2     10

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

    // Битовые поля, которые хранят флаг, готовы ли даные.
    struct valuePDMChange
    {
      unsigned Ch1 : 1;
      unsigned Ch2 : 1;
    } volatile pdmChange;

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

      pinMode(PIN_CHL_1, INPUT);
      pinMode(PIN_CHL_2, INPUT);

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

      MC_CRITICAL_SECTION_START

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

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

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

      MC_CRITICAL_SECTION_END
    }

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

        // Можно сделать проверку.
        if ((tempValuePDMCh1 >= 500) && (tempValuePDMCh1 <= 2500))
        {
          // Печатаем полученные значения в Serial.
          Serial.print("Ch1 - ");
          Serial.println(tempValuePDMCh1);

          Serial.print("Map value - ");
          Serial.println(map((uint16_t)tempValuePDMCh1, 500, 2500, 0, 180));

          // Servo.write(map((uint16_t)tempValuePDMCh1, 500, 2500, 0, 180));
          // Servo.writeMicroseconds((uint16_t)tempValuePDMCh1);
        }

        pdmChange.Ch1 = 0;
      }

      if (pdmChange.Ch2)
      {
        MC_CRITICAL_SECTION_START
        uint32_t tempValuePDMCh2 = valuePDMCh2;
        MC_CRITICAL_SECTION_END

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

        pdmChange.Ch2 = 0;
      }
    }

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

      if (changedBits)
      {
        uint32_t currentTime = micros();

        // Проверяем изменилось состояние пина 9.
        if (changedBits & (1 << PB1))
        {
          if (PINB & (1 << PB1))
          {
            // Тут будем засекать High на 9 пине Ардуино.
            timeRisingCh1 = currentTime;
          }
          else
          {
            // Тут будем засекать Low на 9 пине Ардуино.
            valuePDMCh1 = currentTime - timeRisingCh1;
            pdmChange.Ch1 = 1;
          }
        }
        // Проверяем изменилось состояние пина 10.
        if (changedBits & (1 << PB2))
        {
          // Длина импульса в микросекундах для 2 канала.
          if (PINB & (1 << PB2))
          {
            // Тут будем засекать High на 10 пине Ардуино.
            timeRisingCh2 = currentTime;
          }
          else
          {
            // Тут будем засекать Low на 10 пине Ардуино.
            valuePDMCh2 = currentTime - timeRisingCh2;
            pdmChange.Ch2 = 1;
          }
        }
      }
    }
     
    Итак что изменилось, появились битовые поля (сделал для более наглядной работы, можно было просто uint8_t он же byte). pdmChange.Ch1 изменение канала 1, pdmChange.Ch2 изменение канала 2. О битовых полях можно почитать тут - http://lord-n.narod.ru/download/books/walla/programming/Spr_po_C/07/0707.htm.

    Данный код сделан, под Вашу реализацию, для пульта где 4/6 и более каналов, ввел бы массивы, а для 2 каналов оставил переменные. Начну описывать.

    Функция setup:
    MC_CRITICAL_SECTION_START - сохраняем регистр SREG, в котором хранится глобального прерывания (один из битов, которого хранит флаг разрешения всех прерываний). После чего вызываем макрос cli он просто очищает флаг глобального прерывания (запрещаем все прерывания).

    MC_CRITICAL_SECTION_END - восстанавливаем регистр SREG. В данном регистре SREG, мы восстанавливаем настройку флага глобального прерывания (если прерывания, до запуска MC_CRITICAL_SECTION_START были включены, они восстановятся, так как этот флаг хранится в регистре SREG, который мы предварительно сохранили).

    Почему запрещаю, чтобы до loop не сработало прерывание, которое мы все равно не сможем обработать в setup.

    Информация по регистру SREG - http://easyelectronics.ru/avr-uchebnyj-kurs-flagi.html.
    Как альтернатива MC_CRITICAL_SECTION_START и MC_CRITICAL_SECTION_END можно использовать util/atomic.h - http://www.nongnu.org/avr-libc/user-manual/group__util__atomic.html, у нее больше возможностей, но тут достаточно простых макросов.

    Регистр PCMSK0, тут просто включаем необходимые пины. Открываем справочник по регистрам PCINT на Atmega328 - http://avrprog.blogspot.com.by/2013/03/extinterrupts.html. Последняя таблица регистр PCMSK0 (у автора ошибка в названии смотрим последнюю таблицу), какие-то не понятные выводы PCINT7-PCINT0.

    Открываем pinMaping Arduino Nano/UNO
    [​IMG]
    Находим нужные нам пины, ищем PCINTx на против нужного пина, в нашем случае 9 пин - PCINT1 и 10 пин - PCINT2

    Функция loop.
    Проверяем изменилась ли значение if (pdmChange.Ch1), если изменилось сохраняем в локальную переменную и дальше работаем с ней.

    Там снова видим MC_CRITICAL_SECTION_START и MC_CRITICAL_SECTION_END, сделано для выполнения кода внутри данных команд, как атомарного блока. Подробнее тут - http://chipenable.ru/index.php/programming-avr/item/16-atomarnyy-dostup-k-peremennym.html.

    Дальше мы можем сделать проверку tempValuePDMCh1, на корректность if ((tempValuePDMCh1 >= 500) && (tempValuePDMCh1 <= 2500)) и работать с данной переменной как пожелаем.

    К примеру отправить ее через map серве - Servo.write(map((uint16_t)tempValuePDMCh1, 500, 2500, 0, 180)) или на прямую Servo.writeMicroseconds((uint16_t)tempValuePDMCh1), хотя последний использую только для ESC.

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

    Сам еще любитель, учусь по мере необходимости.

    Не знаю удалось мне донести мысль, но если будут вопросы, спрашивайте.
     
    Последнее редактирование: 20 май 2016
  18. Вах ! ... Пап, а ты сЧаЗ с кем разговаривал ? ... (некий анегдот) :)
    Мысль вошла плотно. Притаилась.... :confused:
    ...Чувствую - в душе происходит что-то тонкое, нежное, едва уловимое ... Толи казнить кого хочется, толи расплакаться ... Пала-ач !! ... (некто Король "... чудо") :)
    Собственно сам принцип понятен -
    1. есть (где-то внутри) отдельный аппаратный регистр, который мы заставляем считывать состояния нужных нам пинов (не только 9 и 10 ?) по-битно (каждому порту - свой бит 0 или1 в маске?).
    2. как только состояния изменяются, запускаем процедуру подсчёта времени (как в пульс, только камень не тормозит) и вычисляем частоту ШИМии (опираясь на разность во времени начала состояния порта и конца фронта.
    3. присваиваем переменной это значение и испоЛзуем её по своему усмотрению - либо в серву (через мэп - спроецировать диапазоны приёмника от 1000 до 2000 и сервы 0-180) либо на обработку (например, угла слежения в конкретный мо-мент).
    т.е. я кака лошадь: гдет в глубине души всё понимаю - только сказать ничего не могу - отсутствие знаний по синтаксису и элементарного опыта. Надо ещё в "ампер-примерах" поп-ракти-коваться (время...время...).
    ... Уже готов "стенд" с приёмником и ункой - внешнее питание надо сделать (сервы плывут...).
    СПАСИБО ! Битва продолжается. :)
     
  19. Alex19

    Alex19 Гуру

    У меня аналогичное, когда фрезерую:). Не могу понять режимы резания, пока просто гроблю фрезы.

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

    В программировании все значительно проще, написано в документации к контролеру, что нужно делать для получения какого-то результата и в 99%, это истина.

    Да, до 23 для данного контролера, мы использовали только 2.

    Да. Но давайте не будем использовать слово "порт", а будем использовать "пин". Дело в том, что порт в AVR, имеет немного другое значение. По простому, это группа пинов, если интересно почитайте - http://easyelectronics.ru/avr-uchebnyj-kurs-ustrojstvo-i-rabota-portov-vvoda-vyvoda.html.

    Регистр не один. Начну с тех в которых задаются пины, для Atmega328 это 3 однотипных регистра PCMSK0 (PCINT0-PCINT7), PCMSK1 (PCINT8-PCINT14), PCMSK2 (PCINT16-PCINT23). Каждый регистр 8 битный, по биту на 1 пин, 0 - не обрабатывать пин как прерывание группы пинов, 1 обрабатывать.

    У Atmega328 можно использовать 21 пина, а не только 9 и 10, дальше смотрим картинку pinMaping (она дана выше) и видим, что не все выводы выведены в Ардуину (речь PCINT6 и PCINT7, они не подключены в Ардуино). С регистрами, которые включают пины разобрались.

    Затем регистр который включает прерывание по группе пинов. Регистр PCICP, с 3 битами PCIE0-PCIE3. Если мы запишем в бит PCIE0 1-ку, то будет включено прерывание PCINT0_vect. Прерывание PCINT0_vect, будет работать с пинами, которые указанные в регистре PCMSK0 (PCINT0-PCINT7).

    Чтобы работать с пинами PCMSK1 (PCINT8-PCINT14), надо включать прерывание PCINT1_vect, для этого в бит PCIE1 надо записать единичку.

    Это основные регистры для работы с прерыванием PCINT.

    Да. Мы постоянно крутимся в цикле loop, как только состояние изменилось происходит прерывание, мы завершаем текущую команду и переходим в прерывание. В прерывании делаем необходимые замеры и возвращаемся в loop. Возвращаемся в то место откуда прервались.

    Да.

    Отлично.

    PS. Я сознательно перешел на "пины", "входы" и "прерывание по группе пинов", чтобы не запутать. В документации они называются иначе. Это упрощение, лишь для понятия конкретного примера.

    Очень хорошие учебные курсы по AVR, которые помогли и помогают мне - http://easyelectronics.ru/category/avr-uchebnyj-kurs, http://chipenable.ru/index.php/programming-avr.html, http://www.doneathome.ru/archives/category/уроки,