Помогите встроить в код джойстик

Тема в разделе "Моторы, сервоприводы, робототехника", создана пользователем МихаилП, 16 мар 2016.

  1. МихаилП

    МихаилП Нерд

    Вот код, не получается встроить джойстик.Скачал книгу читаю. читаю, но ничего пока не получается. а проект горит.. Надеюсь на вашу помощь.
    #include "Stepper.h"
    #define STEPS 32 // Number of steps for one revolution of Internal shaft
    // 2048 steps for one revolution of External shaft

    volatile boolean TurnDetected; // need volatile for Interrupts
    volatile boolean rotationdirection; // CW or CCW rotation

    const int PinCLK=2; // Generating interrupts using CLK signal
    const int PinDT=3; // Reading DT signal
    const int PinSW=4; // Reading Push Button switch

    int RotaryPosition=0; // To store Stepper Motor Position

    int PrevPosition; // Previous Rotary position Value to check accuracy
    int StepsToTake; // How much to move Stepper

    // Setup of proper sequencing for Motor Driver Pins
    // In1, In2, In3, In4 in the sequence 1-3-2-4
    Stepper small_stepper(STEPS, 8, 10, 9, 11);

    // Interrupt routine runs if CLK goes from HIGH to LOW
    void isr () {
    delay(4); // delay for Debouncing
    if (digitalRead(PinCLK))
    rotationdirection= digitalRead(PinDT);
    else
    rotationdirection= !digitalRead(PinDT);
    TurnDetected = true;
    }

    void setup () {
    pinMode(PinCLK,INPUT);
    pinMode(PinDT,INPUT);
    pinMode(PinSW,INPUT);
    digitalWrite(PinSW, HIGH); // Pull-Up resistor for switch
    attachInterrupt (0,isr,FALLING); // interrupt 0 always connected to pin 2 on Arduino UNO
    }

    void loop () {
    small_stepper.setSpeed(600); //Max seems to be 700
    if (!(digitalRead(PinSW))) { // check if button is pressed
    if (RotaryPosition == 0) { // check if button was already pressed
    } else {
    small_stepper.step(-(RotaryPosition*50));
    RotaryPosition=0; // Reset position to ZERO
    }
    }

    // Runs if rotation was detected
    if (TurnDetected) {
    PrevPosition = RotaryPosition; // Save previous position in variable
    if (rotationdirection) {
    RotaryPosition=RotaryPosition-1;} // decrase Position by 1
    else {
    RotaryPosition=RotaryPosition+1;} // increase Position by 1

    TurnDetected = false; // do NOT repeat IF loop until new rotation detected

    // Which direction to move Stepper motor
    if ((PrevPosition + 1) == RotaryPosition) { // Move motor CW
    StepsToTake=50;
    small_stepper.step(StepsToTake);
    }

    if ((RotaryPosition + 1) == PrevPosition) { // Move motor CCW
    StepsToTake=-50;
    small_stepper.step(StepsToTake);
    }
    }
    }
     
  2. Megakoteyka

    Megakoteyka Оракул Модератор

    Отформатируйте код и вставьте его в тэг, пожалейте глаза читающих.
    Напишите подробно, чего вы хотите добиться. Слова "встроить джойстик в код" понятны только вам.
     
  3. МихаилП

    МихаилП Нерд

    Код (C++):
    #include "Stepper.h"
    #define STEPS  32   // Number of steps for one revolution of Internal shaft
                        // 2048 steps for one revolution of External shaft
    volatile boolean TurnDetected;  // need volatile for Interrupts
    volatile boolean rotationdirection;  // CW or CCW rotation
    const int PinCLK=2;   // Generating interrupts using CLK signal
    const int PinDT=3;    // Reading DT signal
    const int PinSW=4;    // Reading Push Button switch
    int RotaryPosition=0;    // To store Stepper Motor Position
    int PrevPosition;     // Previous Rotary position Value to check accuracy
    int StepsToTake;      // How much to move Stepper
    // Setup of proper sequencing for Motor Driver Pins
    // In1, In2, In3, In4 in the sequence 1-3-2-4
    Stepper small_stepper(STEPS, 8, 10, 9, 11);
    // Interrupt routine runs if CLK goes from HIGH to LOW
    void isr ()  {
      delay(4);  // delay for Debouncing
      if (digitalRead(PinCLK))
        rotationdirection= digitalRead(PinDT);
      else
        rotationdirection= !digitalRead(PinDT);
      TurnDetected = true;
    }
    void setup ()  {
     
    pinMode(PinCLK,INPUT);
    pinMode(PinDT,INPUT);
    pinMode(PinSW,INPUT);
    digitalWrite(PinSW, HIGH); // Pull-Up resistor for switch
    attachInterrupt (0,isr,FALLING); // interrupt 0 always connected to pin 2 on Arduino UNO
    }
    void loop ()  {
      small_stepper.setSpeed(600); //Max seems to be 700
      if (!(digitalRead(PinSW))) {   // check if button is pressed
        if (RotaryPosition == 0) {  // check if button was already pressed
        } else {
            small_stepper.step(-(RotaryPosition*50));
            RotaryPosition=0; // Reset position to ZERO
          }
        }
      // Runs if rotation was detected
      if (TurnDetected)  {
        PrevPosition = RotaryPosition; // Save previous position in variable
        if (rotationdirection) {
          RotaryPosition=RotaryPosition-1;} // decrase Position by 1
        else {
          RotaryPosition=RotaryPosition+1;} // increase Position by 1
        TurnDetected = false;  // do NOT repeat IF loop until new rotation detected
        // Which direction to move Stepper motor
        if ((PrevPosition + 1) == RotaryPosition) { // Move motor CW
          StepsToTake=50;
          small_stepper.step(StepsToTake);
        }
        if ((RotaryPosition + 1) == PrevPosition) { // Move motor CCW
          StepsToTake=-50;
          small_stepper.step(StepsToTake);
        }
      }
    }
     
  4. МихаилП

    МихаилП Нерд

    Как не стараюсь не выходит встроить джойстик:(
     
  5. CryNET

    CryNET Гик

    А что этот код выполняет, где используется?
     
  6. AlexU

    AlexU Гуру

    Посмотрите внимательней на обработчик прерывания:
    Код (C++):
    void isr ()  {
      delay(4);  // delay for Debouncing
      if (digitalRead(PinCLK))
        rotationdirection= digitalRead(PinDT);
      else
        rotationdirection= !digitalRead(PinDT);
      TurnDetected = true;
    }
    использование delay(4) не смущает?
     
  7. МихаилП

    МихаилП Нерд

    Код используется для управления шаговым двигателем с помощью энкодера. А я хочу использовать джойстик вместо энкодера. Щелчок энкодера влево делает шаг в лево, вправо, шаг в право. Нажатие на энкодер, возвращается в нулевую точку.
     
  8. МихаилП

    МихаилП Нерд

    Смущает, но я новичок в этом деле. Вот и копаюсь и туплю. Он там не к чему?
     
  9. AlexU

    AlexU Гуру

    Немного пояснений: перед вызовом обработчика прерываний (в данном случае функции isr() ) будут замаскированы все прерывания (т.е. выключены). А для правильной работы функции delay() нужны включенные прерывания. Исходя из вышесказанного -- при первом же вызове обработчика прерывания isr() контроллер зависнет.
    Судя по комментарию задержка используется для борьбы с дребезгом кнопки, в прерываниях с этим борятся немного по другому, например так:
    Код (C++):

    unsigned long lastCLKtime = 0;
    void isr ()  {
      if ((millis() - lastCLKtime) > 4)  // delay(4) for Debouncing
      {
        lastCLKtime = millis();
        if (digitalRead(PinCLK))
          rotationdirection= digitalRead(PinDT);
        else
          rotationdirection= !digitalRead(PinDT);
        TurnDetected = true;
      }
    }
    Если возникнет следующее прерывание ранее чем через 5 ms, то это прерывание будет проигнорировано обработчиком. Для обработки прерывания разница между сохранённым временем lastCLKtime и текущим millis() должна быть больше 4.
    Но было бы неплохо и на схему взглянуть -- может случиться так, что с дребезгом можно будет не бороться, если дребезг не будет влиять на корректность работы устройства.
     
  10. МихаилП

    МихаилП Нерд

    Дело в том, что я не могу подключить джойстик, а clk и dt это выходы с энкодера.
     
  11. ostrov

    ostrov Гуру

    millis() в прерывании тоже работать не будет, ибо он тоже работает на прерывании. С дребезгом в этом случае следует бороться аппаратно.
     
  12. AlexU

    AlexU Гуру

    Работать будет -- во время обработки прерывания будет возвращать одно и то же значение и это не приведет к зависанию контроллера.

    Я бы сделал задержку равную половине периода CLK.
    Код (C++):
    if ((millis() - lastCLKtime) > 4) // вместо 4 написать длительность половины периода в ms
     
  13. AlexU

    AlexU Гуру

    Сразу не сообразил -- судя по Вашему коду, энкодер по сигналу CLK выдаёт один бит данных, так или нет?
    Если не так, то что выдаёт энкодер?
     
  14. МихаилП

    МихаилП Нерд

    Все верно, выдает один бит.
     
  15. AlexU

    AlexU Гуру

    Есть высокая вероятность, что никакого дребезга не будет. Но, если вы хотите перестраховаться, то в постах #9 и #13 описан один из способов борьбы с дребезгом. И функцию 'delay()' в обработчиках прерываний никогда не используйте.
    Тот способ аппаратного прерывания, что предложен пользователем 'ostrov', может не подойти в Вашем случае. Он рассчитан на то, что кнопки нажимаются с небольшой частотой. А частота CLK мажет быть довольно высокой для НЧ фильтра, встроенного между кнопкой и пином контроллера, в том способе.
     
  16. AlexU

    AlexU Гуру

    Но это мы разобрались с задержкой в обработчике прерывания.
    Теперь посмотрим на логику:
    Код (C++):
    if (digitalRead(PinCLK))
         rotationdirection= digitalRead(PinDT);
    else
         rotationdirection= !digitalRead(PinDT);
    TurnDetected = true;
    Что этим кодом Вы хотели сказать?
     
  17. ostrov

    ostrov Гуру

    Время "пробоя" RC-цепи всегда можно подобрать. Для кнопок это 20-40мс.

    Я не понял как это millis() работает в прерываниях? Разве есть в нем смысл, если он возвращает одно и то же значение?
     
  18. AlexU

    AlexU Гуру

    Одно и то же значение будет в пределах одного вызова обработчика прерывания. Во время следующего вызова значение может быть другим. Главное, что бы в котроллере корректно обрабатывались прерывания по переполнению для Timer0. Именно обработчик прерывания по переполнению для Timer0 обеспечивает подсчет времени, который впоследствии можно узнать через функцию 'millis()'.
     
  19. ostrov

    ostrov Гуру

    Заинтриговали, не поленюсь проверю сегодня работает ли millis() внутри прерывания. Имею подозрения, что он не увеличивается. А если так, то он мало отличается от delay() по своей нужности.
     
  20. Tomasina

    Tomasina Сушитель лампочек Модератор

    не должно работать, ибо в них прерывания запрещены.
    Вот что внутри millis():
    Код (C++):
    unsigned long millis()
    {
        unsigned long m;
        uint8_t oldSREG = SREG;
        // disable interrupts while we read timer0_millis or we might get an
        // inconsistent value (e.g. in the middle of a write to timer0_millis)
        cli();
        m = timer0_millis;
        SREG = oldSREG;
        return m;
    }