Энкодер меняет значение после второго поворота.

88Baf88
Offline
Зарегистрирован: 04.07.2019

Приветствую всех. Програмист я не очень, поэтому прошу помощи.

Нужно что-то попровить или добавить, чтобы при одном повороте энкодера менялось значение(громкость+/-), а не как сейчас при втором.

Работа энкодера описана внизу, строка 432

П.С. Скетч компелируется только в старой IDE (1.0.5)


/// Для работы требуется модифицированный HID.cpp отсюда https://github.com/aduitsis/ardumultimedia
/// Заменить им оригинал в папке C:\Program Files\Arduino\hardware\arduino\cores\arduino
/// Проект: http://pccar.ru/showthread.php?t=19903
/// Контакты: icq - 266-666.

////////Библиотеки////////
#include <Bounce.h>         // Устраняет дребезг кнопок
#include <Timer.h>          // Таймер 

////////Входы////////  
/// Входы энкодера
int EncButtonPin = 2;  //Кнопка энкодера
const int pin_A  = 3;  //вход энкодера А
const int pin_B  = 4;  //вход энкодера В
/// Входы джойстика
int JoyUp        = 7;   //UP
int JoyLeft      = 6;   //LEFT
int JoyDown      = 5;   //DOWN
int JoyRight     = 8;   //RIGHT



////////Убираем дребезг////////
Bounce EncButton      = Bounce(EncButtonPin, 50); //Убираем дребезг кнопки энкодера
Bounce JoyUpButton    = Bounce(JoyUp, 50);        //Убираем дребезг
Bounce JoyLeftButton  = Bounce(JoyLeft, 50);      //Убираем дребезг
Bounce JoyDownButton  = Bounce(JoyDown, 50);      //Убираем дребезг
Bounce JoyRightButton = Bounce(JoyRight, 50);     //Убираем дребезг
////////END Убираем дребезг////////

////////Переменные////////
int longPressStickVal;            //НЕ МЕНЯТЬ//Положение стика

boolean powerOn = LOW;            //Девайс вкл/выкл
boolean needEnter = LOW;          //Надо ли посылать код кнопки ENTER
boolean pPowerOff = LOW;          //Зажигание выключено, запущен таймер отключения
boolean joystickPress = LOW;
boolean joystickLongPress = LOW;
boolean altTabFirstPress = HIGH;  //Первое нажатие alt+tab
boolean longIrPress = LOW;        //Долгое нажатие кнопок с двойной функцией на ИК-пульте
boolean changeVolEnable = HIGH;   //Можно посылать следующее нажатие кнопки громкость (для энкодера)
boolean muted = LOW;              //Надо ли приглушать звук 

/// Для энкодера
unsigned long currentTime;
unsigned long loopTime;
unsigned char encoder_A;
unsigned char encoder_B;
unsigned char encoder_A_prev=0;


////////Таймеры////////
Timer timer;
int encBtnPressTimer;             //Таймер нажатия кнопки энкодера
int joyTimer;                     //Таймер джойстика
int longPressStickTimer;          //Таймер длинного нажатия на стик
int altTabTimer;                  //Таймер ALT+TAB
int releaseVolTimer;              //Отпустить кнопку громкости
int changeVolTimer;               //Чтобы не посылать медиакоды слишком часто при вращении энкодера  
int longIrTimer;                  //Долгое нажатие кнопок с двойной функцией на ИК-пульте
int sendShortIrTimer;             //Короткое нажатие кнопок с двойной функцией на ИК-пульте 
int longIrCounterTimer;           //Таймер сброса длинного нажатия кнопок с двойной функцией на ИК-пульте 

////////Для медиакодов////////
struct kr {
  uint8_t modifiers;
  uint8_t reserved;
  uint8_t keys[6];
};
struct kr r1;

struct cr {
  uint16_t code;
  uint8_t data[5];
};
struct cr r2;

/// Запускается единожды при включении устройства
void setup()   
{
  //Для энкодера
  pinMode(EncButtonPin, INPUT); 
  digitalWrite(EncButtonPin, HIGH);  // подключить подтягивающий резистор 
  pinMode(pin_A, INPUT);
  digitalWrite(pin_A, HIGH);         // подключить подтягивающий резистор
  pinMode(pin_B, INPUT);
  digitalWrite(pin_B, HIGH);         // подключить подтягивающий резистор
  currentTime = millis();
  loopTime = currentTime;

  //Для джойстика
  pinMode(JoyUp, OUTPUT);
  digitalWrite(JoyUp, HIGH);
  pinMode(JoyLeft, OUTPUT);
  digitalWrite(JoyLeft, HIGH);
  pinMode(JoyDown, OUTPUT);
  digitalWrite(JoyDown, HIGH);
  pinMode(JoyRight, OUTPUT);
  digitalWrite(JoyRight, HIGH);

  //Для клавиатуры 
  Keyboard.begin();
  r2.code=0x0000;
  for(int j=0;j<5;j++) r2.data[j] = 0x00;

  r1.modifiers=0x00;
  for(int j=0;j<6;j++) r1.keys[j] = 0x00;

  //Serial.begin(9600); 
}

// Медиакоды
// Тут немного понятнее

#define HID_VOLUP       0x00E9
#define HID_VOLDOWN     0x00EA
#define HID_PLAY        0x00CD // Play/Pause
#define HID_NEXT        0x00B5
#define HID_PREV        0x00B6
#define HID_TRACK_INC   0x00B3 // don't work
#define HID_TRACK_DEC   0x00B4 // don't work
///////////////////////////////
#define HID_STOP        0x00B7
#define HID_MUTE        0x00E2
#define HID_HOME        0x0223
#define HID_CALC        0x0192
#define HID_MAIL        0x018A
#define HID_POWER       0x0034
#define HID_WWW_SEARCH  0x0221
///////////////////////////////
#define KEY_ENTER       0xB0
#define KEY_UP           0xDA  
#define KEY_DOWN  0xD9  
#define KEY_LEFT  0xD8  
#define KEY_RIGHT   0xD7  
#define KEY_ESC   0xB1  
#define KEY_MENU  0xED
#define KEY_ALT         0x82
#define KEY_TAB         0xB3

uint16_t command = 0;




//////////////////////////////////////////////////////////////////////////////////////////////
/// Настройка действий джойстика и энкодера 
//////////////////////////////////////////////////////////////////////////////////////////////
/*
  Если нужно сэмулировать нажатие обычной кнопки:
    Keyboard.write(KEY_LEFT);
    //Serial.println("PRESS LEFT");

  Если нужно сэмулировать нажатие медиа кнопки:
    command = HID_PREV;
    pressMediaKey();
*/
/////////////////////////////////////////////////////////////////////////////////////////////

/// Короткие нажатия
void Joy_Up()
{
  Keyboard.write(KEY_UP);
}
void Joy_Left()
{
  command = HID_PREV;
  pressMediaKey();
}
void Joy_Down()
{
  Keyboard.write(KEY_DOWN);
}
void Joy_Right()
{
  command = HID_NEXT;
  pressMediaKey();
}
void Enc_Left()
{
  changeVolEnc(0); // Vol-
}
void Enc_Right()
{
  changeVolEnc(1); // Vol+
}
void Enc_Press()
{
  //Keyboard.write(KEY_ENTER);
  command = HID_PLAY;                
  pressMediaKey();                
}
/// Длительные нажатия
void Joy_Up_Long()
{
  Keyboard.write(KEY_ESC);
}
void Joy_Left_Long()
{
  command = HID_TRACK_DEC;
  pressMediaKey(); 
}
void Joy_Down_Long()
{
  Keyboard.write(KEY_MENU);
}
void Joy_Right_Long()
{
  command = HID_TRACK_INC;    
  pressMediaKey();     
}
void Enc_Press_Long()
{
  Keyboard.write(KEY_ENTER);
}
void Enc_Press_Left()
{
  //Serial.println("<__");
  /*
  needEnter = LOW;
  timer.stop(encBtnPressTimer); //Обнуляем таймер если крутится энкодер
  //Если до этого делали ALT+TAB отпускаем 
  if(boolean(altTabFirstPress)==LOW){
    altTabFirstPress=HIGH;
    Keyboard.press(KEY_ESC);
    Keyboard.release(KEY_ESC);
    Keyboard.release(KEY_ALT);
    Keyboard.releaseAll();
    return;
  }
  else{ 
    //Serial.println("<__");
    command = HID_HOME;              
    pressMediaKey();
  }
  //*/
}
void Enc_Press_Right()
{
  //Serial.println("__>");
  /*
  needEnter = LOW;
  timer.stop(encBtnPressTimer); // Обнуляем таймер, если крутится энкодер
  doAltTab();
  //*/
}


/////////////////////////////////////////////////////////////////////////////////////////////
/// END Настройка действий джойстика и энкодера
/////////////////////////////////////////////////////////////////////////////////////////////





/// Основной цикл, выполняется все время, пока работает устройство
void loop()  
{ 
  //ACC_Control();
  //Rear_Control();
  Enc_Btn_Control();
  Encoder();

  timer.update();
}

//Обработчик нажатия кнопки энкодера и джойстика
void Enc_Btn_Control()
{
  if(JoyUpButton.update()){
    if(JoyUpButton.read()==LOW){
      longPressStickVal = 0;
      //Serial.println("PressUp");
      timer.stop(encBtnPressTimer); //Обнуляем таймер выключения при длительном удержании кнопки
      timer.stop(joyTimer);
      joystickPress = HIGH;
      longPressStickTimer = timer.after(1000, longStickPress); //Запуск таймера длинного нажатия на стик 
    }
    if(JoyUpButton.read()==HIGH){
      timer.stop(longPressStickTimer); //Обнуляем таймер длительного нажатия
      if(boolean(joystickLongPress)==LOW){

        /// Нажатие кнопки джойстика UP
        Joy_Up();

      }
      else{
        joystickLongPress=LOW;
      }
      joyTimer = timer.after(250, joyPressToggle);
    }
  }
  if(JoyLeftButton.update()){
    if(JoyLeftButton.read()==LOW){
      longPressStickVal = 1;
      //Serial.println("PressLeft");
      timer.stop(encBtnPressTimer); //Обнуляем таймер выключения при длительном удержании кнопки
      timer.stop(joyTimer);
      joystickPress = HIGH;
      longPressStickTimer = timer.after(1000, longStickPress); //Запуск таймера длинного нажатия на стик 
    }
    if(JoyLeftButton.read()==HIGH){
      timer.stop(longPressStickTimer); //Обнуляем таймер длительного нажатия
      if(boolean(joystickLongPress)==LOW){

        /// Нажатие кнопки джойстика LEFT
        Joy_Left();
        
      }
      else{
        joystickLongPress=LOW;
      }
      joyTimer = timer.after(250, joyPressToggle);
    }
  }
  if(JoyDownButton.update()){
    if(JoyDownButton.read()==LOW){
      longPressStickVal = 2;
      //Serial.println("PressDown");
      timer.stop(encBtnPressTimer); //Обнуляем таймер выключения при длительном удержании кнопки
      timer.stop(joyTimer);
      joystickPress = HIGH;
      longPressStickTimer = timer.after(1000, longStickPress); //Запуск таймера длинного нажатия на стик 
    }
    if(JoyDownButton.read()==HIGH){
      timer.stop(longPressStickTimer); //Обнуляем таймер длительного нажатия
      if(boolean(joystickLongPress)==LOW){

        /// Нажатие кнопки джойстика DOWN
        Joy_Down();

      }
      else{
        joystickLongPress=LOW;
      }
      joyTimer = timer.after(250, joyPressToggle);
    }
  }
  if(JoyRightButton.update()){
    if(JoyRightButton.read()==LOW){
      longPressStickVal = 3;
      //Serial.println("PressRight");
      timer.stop(encBtnPressTimer); //Обнуляем таймер выключения при длительном удержании кнопки
      timer.stop(joyTimer);
      joystickPress = HIGH;
      longPressStickTimer = timer.after(1000, longStickPress); //Запуск таймера длинного нажатия на стик 
    }
    if(JoyRightButton.read()==HIGH){
      timer.stop(longPressStickTimer); //Обнуляем таймер длительного нажатия
      if(boolean(joystickLongPress)==LOW){

        /// Нажатие кнопки джойстика RIGHT
        Joy_Right();

      }
      else{
        joystickLongPress=LOW;
      }
      joyTimer = timer.after(250, joyPressToggle);
    }
  }

  if(EncButton.update()){
    /// Если до этого делали ALT+TAB - отпускаем
    if(boolean(altTabFirstPress)==LOW){
      altTabFirstPress=HIGH;        
      Keyboard.releaseAll();//На всякий случай отпустим все кнопки))        
    };

    if(( (JoyUpButton.read() == HIGH) && (JoyLeftButton.read() == HIGH) && (JoyDownButton.read() == HIGH) && (JoyRightButton.read() == HIGH) && (boolean(joystickPress) == LOW) )){
      if(EncButton.read()==LOW){
        longPressStickVal = 10;
        timer.stop(encBtnPressTimer); //Обнуляем таймер выключения при длительном удержании кнопки
        timer.stop(joyTimer);
        //////joystickPress = HIGH; // Обязательно должно быть закомментировано - иначе обычное и долгое нажатия вместе не работают!!!
        longPressStickTimer = timer.after(1000, longStickPress); //Запуск таймера длинного нажатия на стик 
      }
      if(EncButton.read()==HIGH){
        timer.stop(longPressStickTimer); //Обнуляем таймер длительного нажатия
        if(boolean(joystickLongPress)==LOW){
          /// Короткое нажатие центральной кнопки энкодера
          Enc_Press();
        }
        else{
          joystickLongPress=LOW;
        }
        joyTimer = timer.after(250, joyPressToggle);
      }
    }
  } // END EncButton.update()
  
}

/// Длинные нажатия джойстика в стороны
void longStickPress() {
  if(longPressStickVal == 0){
    //Serial.println("PRESS UP LONG");
    Joy_Up_Long();
  }
  if(longPressStickVal == 1){
    //Serial.println("PRESS LEFT LONG");
    Joy_Left_Long();
  }
  if(longPressStickVal == 2){
    //Serial.println("PRESS DOWN LONG");
    Joy_Down_Long();
  }
  if(longPressStickVal == 3){
    //Serial.println("PRESS RIGHT LONG");
    Joy_Right_Long();
  }
  if(longPressStickVal == 10){
    /// Длинное нажатие центральной кнопки энкодера
    Enc_Press_Long();
  }
  joystickLongPress = HIGH;
}

/// Переключалка состояния переменной джойстика
void joyPressToggle() {
  //Serial.println("joyPressToggle");
  joystickPress = LOW;
}


/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/// Обработчик энкодера - реализуем принцип работы инкрементного энкодера////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Encoder() {
  currentTime = millis();
  if(currentTime >= (loopTime + 0.5)){    // проверяем каждые 5мс (200 Гц)
    encoder_A = digitalRead(pin_A);       // считываем состояние выхода А энкодера
    encoder_B = digitalRead(pin_B);       // считываем состояние выхода B энкодера   
    if((!encoder_A) && (encoder_A_prev)){ // если состояние изменилось с положительного к нулю
      if(encoder_B) {
        if ( EncButton.read() == HIGH) {
          //Serial.println("<--");

          /// Крутим энкодер влево
          //Enc_Left();
          changeVolEnc(0); // Vol-
          
        }
        if ( EncButton.read() == LOW) {
          //Serial.println("<__");

          /// Нажатие кнопки энкодера + поворот энкодера влево
          Enc_Press_Left();

        }
      } else {
        if ( EncButton.read() == HIGH) {
          //Serial.println("-->");
          
          /// Крутим энкодер вправо
          //Enc_Right();
          changeVolEnc(1); // Vol+
          
        }
        if ( EncButton.read() == LOW) {
          //Serial.println("__>");
          
          /// Нажатие кнопки энкодера + поворот энкодера вправо
          Enc_Press_Right();
          
        }          
      }  
    }  
    encoder_A_prev = encoder_A;     // сохраняем значение А для следующего цикла
    loopTime = currentTime;
  }             
}

/////////////////////////////////////////////////////////////
/// Различные служебные функции
/////////////////////////////////////////////////////////////

/// Меняем громкость с энкодера:
/// changeVolEnc(0) = Vol-
/// changeVolEnc(1) = Vol+
void changeVolEnc(boolean arg){ 
  timer.stop(changeVolTimer);
  changeVolTimer = timer.after(170, toggleChangeVolEnable); 
  //Serial.println(arg) ; 
  if(arg==0){
    if(boolean(changeVolEnable)==HIGH){
      muted = LOW;
      changeVolEnable = LOW;    
      command = HID_VOLDOWN;
      r2.code = command;
      HID_SendReport(3,&r2,sizeof(struct cr));       
      //Serial.println("VOL -");
    }
  }
  if(arg==1){
    if(boolean(changeVolEnable)==HIGH){
      muted = LOW;
      changeVolEnable = LOW;    
      command = HID_VOLUP;     
      r2.code = command;
      HID_SendReport(3,&r2,sizeof(struct cr));       
      //Serial.println("VOL +");
    }
  }                
}
void toggleChangeVolEnable(){
  timer.stop(changeVolTimer);
  changeVolEnable = HIGH;
  r2.code = 0x0000;
  HID_SendReport(3,&r2,sizeof(struct cr));  
  //Serial.println("VOL R");
}

/// Эмуляция нажатия медиа кнопок
void pressMediaKey(){
  //onPress
  r2.code = command;
  HID_SendReport(3,&r2,sizeof(struct cr));
  //onRelease
  r2.code = 0x0000;
  HID_SendReport(3,&r2,sizeof(struct cr));
}

/// Функционал ALT+TAB
void doAltTab(){
  if(boolean(altTabFirstPress)==HIGH){
    altTabFirstPress = LOW;
    Keyboard.press(KEY_ALT);
    Keyboard.press(KEY_TAB);
    Keyboard.release(KEY_TAB);
  }
  else{
    Keyboard.press(KEY_TAB);
    Keyboard.release(KEY_TAB);
  }
}
b707
Offline
Зарегистрирован: 26.05.2017

код большой так просто не найти. Тем более в программе есть явные ошибки. Например, прямо в самом начале работы с энкодером - строка 434 - написана чушь, так со временем не работают

88Baf88
Offline
Зарегистрирован: 04.07.2019

Писали его в далеком 2013 году. Он загружается и работает, только проблема с поворотами. 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

88Baf88 пишет:

только проблема с поворотами. 

В этом коде много проблем. Обратитесь к его автору. Разребать их все просто так врядли найдутся охотники.