Как сделать, чтобы Rotary Encoder делал 10 шагов одновременно?

rotary-encoder joystick

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

Ротари: https:// www.reichelt.de/drehimpulsegeber-15-impulse-30-rastungen-vertikal-ec11mvbfx-p315144.html?&nbc=1 (на этом сайте также есть изображения и спецификации.)

Переключатель: https: //www.reichelt.de/miniatur-kippschalter-ein-aus-ein-3-a-250-v-goobay-10023-p285990.html?&nbc=1

Проводка: (изображение ниже)

        1--------Pin16 |  Pin A3----Switch
Rotary  2--------GND   |  GND-------|
        3--------PIN17 |

Поворотный энкодер не выдает никаких выходных данных, ни Serial.print, ни игровой контроллер. Также нет выхода ни в одном из положений переключателя.

ОБНОВЛЕНИЕ: После использования массивов и циклов, как научил меня @jsotola, он работает почти так, как должен, но иногда, хотя переключатель выключен, он щелкает десять раз. Код выглядит сокращенно теперь

#include <Arduino.h>
#include <Joystick.h>
#include <BasicEncoder.h>
#include <TimerOne.h>

int EncoderPins[] = {
  4, 5, 6, 7, 8, 9, 10, 11
};
int EncoderCount = 8;

BasicEncoder encoder4(EncoderPins[6], EncoderPins[7], HIGH, 2);

void timer_service() {
  encoder4.service();
}

#define joyButton16 EncoderPins[6]  // Rotary4
#define joyButton17 EncoderPins[7]  // Rotary4
#define joyButton18 21              // HDG_SWITCH := Переключатель для выбора между одинарным и 10 шагами

// Джойстик (джойстик HID ID, тип джойстика, количество кнопок, количество переключателей, включить X, включить Y, включить Z, включить Rx, включить Ry, включить Rz, включить руль направления, включить дроссельную заслонку, включить акселератор, включить тормоз, включить рулевое управление )
Joystick_ Joystick(0x15, JOYSTICK_TYPE_JOYSTICK, 19, 0,
                   true /*X*/, false/*Y*/, false/*X*/,
                   false/*Rx*/, false/*Ry*/, false/*Rz*/,
                   false/*Rudder*/, false/*Throttle*/, false/*Acc*/,
                   false/*Brake*/, false/*Steer*/);

const bool initAutoSendState = true; // код отправляется непрерывно и не ждет опроса

int EncoderState[] = {
  0, 0, 0, 0
};

void setup() {
  for (int q  = 0; q < EncoderCount; q++)
  {
    pinMode(EncoderPins[q], INPUT_PULLUP);
  }

  Serial.begin(9600);
  Joystick.begin();

  Timer1.initialize(100);
  Timer1.attachInterrupt(timer_service);
}

void loop() {
  GET_CHANGE();

  int CurrentButton18State = !digitalRead(joyButton18);
  switch(CurrentButton18State){
    case 0: 
      switch(EncoderState[3]){
        case  1: clickButton(15); Serial.println(EncoderState[3]); break;
        case -1: clickButton(16); Serial.println(EncoderState[3]); break;
        } break;
    case 1:
      switch(EncoderState[3]){
        case  1: clickTen(15); break;
        case -1: clickTen(16); break;
        } break;
  }
}

void clickButton(int pin) {
  Joystick.setButton(pin, 1);
  delay(2);
  Joystick.setButton(pin, 0);
}

void clickTen(int pin) {
  for (int ii = 0; ii < 10; ii++)
  {
    clickButton(pin);
    Serial.println("step: "); Serial.println(ii);
    delay(10);
  }
}
void GET_CHANGE()
{
  for(int E = 0; E<4; E++)
  switch(E) {
    case 3: EncoderState[E] = encoder4.get_change(); break;
  }
}

, 👍-2

Обсуждение

Пожалуйста, сократите код до минимума, который обеспечивает описанное вами поведение. Этот код предназначен для Arduino Uno? Если это так, контакт A3 Arduino (контакт вашего переключателя) физически совпадает с контактом 17 (один из контактов вашего энкодера). Контакты 0 и 1 — это контакты Serial RX/TX, которые вы не можете использовать для других целей, если вам нужен ввод/вывод через последовательный порт., @StarCat

@StarCat, там написано Arduino Micro, @Juraj

@StarCat, поскольку «A3» является маркером на самой плате, я подумал, что это будет легче понять, конечно, каждый аналоговый вывод можно использовать как цифровой (в коде я так делаю). Я выкладываю полный скетч, потому что я не знаю, может быть проблема в другой части, то в двух переключателях. Кнопки на контактах 0/1 могут быть подключены к распределителю напряжения на другом контакте., @Chritzeltopf

почему вы говорите о выборе между 10 шагами и 1 шагом, когда вы не можете заставить работать энкодер? ... пожалуйста, сосредоточьте свой вопрос на проблеме, @jsotola

Нет выхода, ни во включенном, ни в выключенном положении переключателя, @Chritzeltopf

Какой «поворотный энкодер» и «переключатель» вы имеете в виду? Когда я гуглю эти слова, кажется, что есть миллионы вариантов. Переключатель встроен в поворотный энкодер? У меня проблемы с просмотром вашего поворотного энкодера с моего компьютера. Как насчет того, чтобы поделиться ссылкой на производителя, спецификацией или изображением?, @VE7JRO

*Я выкладываю полный скетч, потому что не знаю, может быть, проблема в другой части, а не в двух переключателях.* - Если бы вы сократили код только до части энкодера, вы бы это обнаружили, не так ли?, @Nick Gammon

@jsotola Ротари выше, к которым не подключен переключатель, работают., @Chritzeltopf

@VE7JRO добавил их, @Chritzeltopf

Опять же, пожалуйста, сократите свой источник до минимума, который все еще раскрывает вашу проблему., @the busybee

1. Я присоединяюсь к другим комментаторам: вы публикуете слишком много кода. См. [Как создать минимальный воспроизводимый пример] (https://stackoverflow.com/help/minimal-reproducible-example). 2. Может быть не связано с вашей проблемой, но ваш код предполагает, что BasicEncoder::get_change() всегда возвращает −1, 0 или 1. Это может быть не всегда так, особенно если учесть, что у вас довольно много delay() ` в вашем коде., @Edgar Bonet

@EdgarBonet Я прочитал ссылку, которую вы разместили, и сегодня днем уменьшу код (с помощью Jsotola). get_change() должна выдавать либо 1, либо - 1, если используется ротор, и 0, если он стоит на месте, не так ли?, @Chritzeltopf

Что касается значения, возвращаемого get_change(): как [указано в документации] (https://github.com/micromouseonline/BasicEncoder#get_change), get_change() возвращает «количество отсчетов с момента последнего вызова метод". Если цикл выполняется очень быстро, это почти всегда будет в пределах ±1. В документации предлагается: «Попробуйте добавить задержку в loop(), чтобы увидеть более крупные изменения». У вас уже довольно много задержек., @Edgar Bonet

@EdgarBonet, так что вы думаете, я должен сравнить, выше или ниже, чем 1 v -1?, @Chritzeltopf

И это я мог бы зациклить, чтобы оно нажимало кнопку, которую я часто поворачивал, не так ли?, @Chritzeltopf

я хочу извинить за сокращение кода, что поздно, но теперь это так, раньше не было времени и забыл, когда я написал вопрос, @Chritzeltopf


1 ответ


2

Это не ответ на вопрос, а совет по упрощению кода.

Это фрагмент вашего кода.


void loop() {

// еще немного кода здесь


  int encoder1State = encoder1.get_change();
  switch (encoder1State) {
    case 1:
      Joystick.setButton(8, 1);
      delay(25);
      Joystick.setButton(8, 0);
      //Serial.println(encoder1State);
      break;
    case -1:
      Joystick.setButton(9, 1);
      delay(25);
      Joystick.setButton(9, 0);
      //Serial.println(encoder1State);
      break;
    case 0:
      break;
  }
  int encoder2State = encoder2.get_change();
  switch (encoder2State) {
    case 1:
      Joystick.setButton(10, 1);
      delay(25);
      Joystick.setButton(10, 0);
      //Serial.println(encoder1State);
      break;
    case -1:
      Joystick.setButton(11, 1);
      delay(25);
      Joystick.setButton(11, 0);
      //Serial.println(encoder1State);
      break;
    case 0:
      break;
  }
  int encoder3State = encoder3.get_change();
  switch (encoder3State) {
    case 1:
      Joystick.setButton(12, 1);
      delay(25);
      Joystick.setButton(12, 0);
      //Serial.println(encoder1State);
      break;
    case -1:
      Joystick.setButton(13, 1);
      delay(25);
      Joystick.setButton(13, 0);
      //Serial.println(encoder1State);
      break;
    case 0:
      break;
  }
  int currentButton20State = !digitalRead(joyButton20);
  int encoder4State = encoder4.get_change();
  switch (currentButton20State) {
    case 0:
      switch (encoder4State) {
        case 1:
          Joystick.setButton(14, 1);
          delay(25);
          Joystick.setButton(14, 0);
          Serial.println(encoder4State);
          break;
        case -1:
          Joystick.setButton(15, 1);
          delay(25);
          Joystick.setButton(15, 0);
          Serial.println(encoder4State);
          break;
        case 0:
          break;
      } break;
    case 1:
      switch (encoder4State) {

        case 1:
          TenRotaryStepsUP();
          break;
        case -1:
          TenRotaryStepsDOWN();
          break;
        case 0:
          break;
      } break;
  }

  //ПолучитьПарамИзFS2020();
  //ПоказатьFlightParam();

  delay(10);

}

void TenRotaryStepsUP()
{
  for (int i = 0; i < 10; i++)
  {
    Joystick.setButton(14, 1);
    delay(25);  //для тестирования установите большее число, например 500
    Joystick.setButton(14, 0);
    Serial.println("step: "); Serial.println(i);
    delay(10);
  }
}

void TenRotaryStepsDOWN()
{
  for (int i = 0; i < 10; i++)
  {
    Joystick.setButton(15, 1);
    delay(25);
    Joystick.setButton(15, 0);
    Serial.println("step: "); Serial.println(i);
    delay(10);
  }
}

Его можно упростить, поместив повторяющийся код в функции.


void loop() {

// еще немного кода здесь


  int encoder1State = encoder1.get_change();
//Serial.println(encoder1State);
  switch (encoder1State) {
    case 1:
      clickButton(8);
      break;
    case -1:
      clickButton(9);
      break;
    case 0:
      break;
  }

  int encoder2State = encoder2.get_change();
  switch (encoder2State) {
    case 1:
      clickButton(10);
      break;
    case -1:
      clickButton(11);
      break;
    case 0:
      break;
  }

  int encoder3State = encoder3.get_change();
  switch (encoder3State) {
    case 1:
      clickButton(12);
      break;
    case -1:
      clickButton(13);
      break;
    case 0:
      break;
  }

  int currentButton20State = !digitalRead(joyButton20);

  int encoder4State = encoder4.get_change();
  switch (currentButton20State) {

    case 0:
      switch (encoder4State) {
        case 1:
          clickButton(14);
          break;
        case -1:
          clickButton(15);
          break;
        case 0:
          break;
      } break;

    case 1:
      switch (encoder4State) {
        case 1:
          clickTen(14);
          break;
        case -1:
          clickTen(15);
          break;
        case 0:
          break;
      } break;
  }

  //ПолучитьПарамИзFS2020();
  //ПоказатьFlightParam();

  delay(10);

}

void clickButton(int pin) {
  Joystick.setButton(pin, 1);
  delay(25);
  Joystick.setButton(pin, 0);
}

void clickTen(int pin) {
  for (int i = 0; i < 10; i++)
  {
    clickButton(pin);
    Serial.println("step: "); Serial.println(i);
    delay(10);
  }
}   

Вы даже можете отформатировать свой код таким образом.

switch (encoder3State) {
  case  1:      clickButton(12);      break;
  case -1:      clickButton(13);      break;
  case  0:                            break;
}

ИЗМЕНИТЬ

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

https://www.arduino.cc/en/Tutorial/BuiltInExamples/Arrays

например. используйте lastButtonState[1] вместо lastButton1State и joyButton[1] вместо joyButton1

что позволит использовать циклы for для повторения одного и того же действия для нескольких контактов

int currentButton2State = !digitalRead(joyButton2);
if (currentButton2State != lastButton2State) {
  Joystick.setButton(1, currentButton2State);
  if (currentButton2State == 1) {
    delay(1);
    Joystick.setButton(1, 0);
  }
  lastButton2State = currentButton2State;
}

становится

int currentButtonState[pin] = !digitalRead(joyButton[pin]);
if (currentButtonState[pin] != lastButtonState[pin]) {
  Joystick.setButton(pin-1, currentButtonState[pin]);
  if (currentButtonState[pin] == 1) {
    delay(1);
    Joystick.setButton(pin-1, 0);
  }
  lastButtonState[pin] = currentButtonState[pin];
}
,

Спасибо @jsotola, попробую, когда вернусь домой!, @Chritzeltopf

добавил больше информации, @jsotola

Спасибо, я попробую это сегодня днем (также я уменьшу код в вопросе), @Chritzeltopf

Вы также можете обрабатывать несколько шагов кодировщика с помощью чего-то вроде if(encoder3State>0) while(encoder3State--) clickButton(12); if(encoder3State<0) while(encoder3State++) clickButton(13);., @Edgar Bonet