Клавиатура HID на UNO R3

Тема в разделе "Arduino & Shields", создана пользователем D1ma-38, 31 окт 2016.

  1. D1ma-38

    D1ma-38 Нуб

    Здравствуйте, как сделать чтоб ардуино повторяла нажатие клавиш в точности как на HID-клавиатуре.
    имею такой код:
    Код (C++):
    uint8_t buf[8] = { 0 };  /* Keyboard report buffer */

    #define PIN_X 2

    int state = 1;

    void setup()
    {
      Serial.begin(9600);

      pinMode(PIN_X, INPUT);
      // Enable internal pull-ups
      digitalWrite(PIN_X, 1);
      delay(200);
    }

    void loop()
    {
      state = digitalRead(PIN_X);
      if (state != 1) {
        buf[2] = 27;    // Letter X
        Serial.write(buf, 8); // Ssend keypress
        releaseKey();
      }
    }

    void releaseKey()
    {
      buf[2] = 0;
      Serial.write(buf, 8); // Release key
      delay(500);
    }
    взял с этого сайта.

    У меня получается при зажатии кнопки на длительное время на ардуино, аналогично многократному нажатию клавиши на клавиатуре.
    Допустим если нажать и удерживать кнопку "Х" на клавиатуре то она пошлет код кнопки "27" и когда отпустишь то пошлет код "0". А если нажать и удерживать кнопку на ардуино то она сразу отправит код "27" и "0" не смотря на то что я кнопку ещё не отпустил, и при длительном удерживании кнопки, будет просто слать "27" и "0".
     
  2. rkit

    rkit Гуру

    D1ma-38 нравится это.
  3. D1ma-38

    D1ma-38 Нуб

    Переписал код так, но теперь кнопка не "отжимается" обратно т.е. код "27" идет бесконечно, как сделать чтоб он шёл пока клавиша нажата, а при отпускании приходил "0". Я не силен в программировании :(
    Код (C++):
    /* Arduino USB Keyboard HID demo
    * Cut/Copy/Paste Keys
    */


    uint8_t buf[8] = { 0 };  /* Keyboard report buffer */

    #define PIN_X 2

    boolean buttonWasUp = true;       // была ли кнопка отпущена?


    int state = 1;

    void setup()
    {
      Serial.begin(9600);

      pinMode(PIN_X, INPUT_PULLUP);
      // Enable internal pull-ups
      digitalWrite(PIN_X, 1);
      delay(200);
    }

    void loop()
    {
                                      // определить момент «клика» несколько сложнее, чем факт того,
                                      // что кнопка сейчас просто нажата. Для определения клика мы
                                      // сначала понимаем, отпущена ли кнопка прямо сейчас...

      boolean buttonIsUp = digitalRead(PIN_X);

                                      // ...если «кнопка была отпущена и (&&) не отпущена сейчас»...
      if (buttonWasUp && !buttonIsUp){
                                      // ...может это «клик», а может и ложный сигнал (дребезг),
                                      // возникающий в момент замыкания/размыкания пластин кнопки,
                                      // поэтому даём кнопке полностью «успокоиться»...
      delay(10);
                                      // ...и считываем сигнал снова
      buttonIsUp = digitalRead(PIN_X);
      if (!buttonIsUp) {              // если она всё ещё нажата...
        buf[2] = 27;                  // Letter X
        Serial.write(buf, 8);         // Ssend keypress
        }
      }

       buttonWasUp = buttonIsUp;
    }
     
  4. D1ma-38

    D1ma-38 Нуб

    Сделал так. Если кнопка одна то всё хорошо работает, но как добавляется ещё кнопки то снова работает не правильно.

    Код (C++):
    void loop()
      {
        if(digitalRead(PIN_X)==HIGH)             //если кнопка нажата ...
          {
            buf[2] = 27;                         //Letter X
            Serial.write(buf, 8);                //Ssend keypress
            digitalWrite(LED_RED,HIGH);          //включаем светодиод
          }
        else if (digitalRead(PIN_X)==LOW)        //если не нажата...
          {
            buf[2] = 0;
            Serial.write(buf, 8);                //Release key
            digitalWrite(LED_RED,LOW);           //выключаем
          }
        if(digitalRead(PIN_L)==HIGH)             //если кнопка нажата ...
          {
            buf[2] = 6;                          //Letter C
            Serial.write(buf, 8);                //Ssend keypress
            digitalWrite(LED_YELLOW,HIGH);       //включаем светодиод
          }
        else if (digitalRead(PIN_L)==LOW)
          {
            buf[2] = 0;
            Serial.write(buf, 8);                //Release key  
            digitalWrite(LED_YELLOW,LOW);        //выключаем
          }
        if(digitalRead(PIN_V)==HIGH)             //если кнопка нажата ...
          {
            buf[2] = 25;                         //Letter V
            Serial.write(buf, 8);                //Ssend keypress
            digitalWrite(LED_GREEN,HIGH);        //включаем светодиод
          }
       else if (digitalRead(PIN_V)==LOW)
          {
            buf[2] = 0;
            Serial.write(buf, 8);                //Release key    
            digitalWrite(LED_GREEN,LOW);         //выключаем
          }
      }
     
  5. D1ma-38

    D1ma-38 Нуб

    Я так понимаю просто else if все срабатывают поэтому при появлении высокого уровня например на "PIN_X" он тут же сбрасывается от низких "PIN_L" и "PIN_V" как с эти бороться я не знаю.
     
  6. rkit

    rkit Гуру

    Код (C++):
    word button[] = { 10, 11, 12 };
    word buttonCode[] = { 27, 6, 25 };
    #define ARRAY_SIZE sizeof(button) / sizeof(word)
    bool buttonWas[ARRAY_SIZE];
    bool buttonIs[ARRAY_SIZE];
    long unbounce[ARRAY_SIZE];
    long unbounceInterval = 50;
    uint8_t buf[8] = { 0 };

    void setup() {
      Serial.begin(9600);
      for(word i = 0; i < ARRAY_SIZE; i++) {
        buttonWas[i] = buttonIs[i] = unbounce[i] = 1;
        pinMode(button[i], INPUT_PULLUP);
      }
    }

    void loop() {
      long curTime = millis();
      for(word i = 0; i < ARRAY_SIZE; i++) {
        buttonIs[i] = digitalRead(button[i]);
        if (unbounce[i] + unbounceInterval > curTime) continue;
        if (buttonIs[i] != buttonWas[i]){
          unbounce[i] = curTime;
          buttonWas[i] = buttonIs[i];
          if (!buttonIs[i]){
            buf[2] = buttonCode[i];
            Serial.write(buf, 8);
          } else {
            buf[2] = 0;
            Serial.write(buf, 8);
          }
        }
      }
    }
     
    MAX9TOR и D1ma-38 нравится это.
  7. D1ma-38

    D1ma-38 Нуб

    Большое спасибо!!! Где можно почитать по подробнее про sizeof и word, чтоб представлять что происходит в скетче?
     
  8. rkit

    rkit Гуру

    В гугле.
    sizeof(button) / sizeof(word) возвращает количество элементов в массиве word button[]
     
  9. MAX9TOR

    MAX9TOR Нуб

    В ваш код я хочу добавить джойстик hw-504, где по оси x angle >= 45 && angle <= 135 будет срабатывать 'w' и angle <= -45 && angle >= -135 срабатывать 's'. По оси y angle < 45 && angle > -45 будет срабатывать 'd' и (angle < -135 && angle >= -180) || (angle <= 180 && angle > 135) срабатывать 'a'. И соответственно в положении по осям 500 не чего не должно срабатывать.

    Вот что я сделал, но не работает, как сделать по другому. Этот код работает через ком порт как отладчик из проета azeron_gamepad.ino:
    Код (C++):
    word button[] = { 13, 12, 11, 10, 9, 8, 7, 6, 5, A5, A4, A0 };
    word buttonCode[] = { 10, 29, 30, 9, 27, 31, 224, 6, 32, 21, 8, 44 };
    #define ARRAY_SIZE sizeof(button) / sizeof(word)
    bool buttonWas[ARRAY_SIZE];
    bool buttonIs[ARRAY_SIZE];
    long unbounce[ARRAY_SIZE];
    long unbounceInterval = 50;
    uint8_t buf[8] = { 0 };

    //-------------------------------------
    // добавил из azeron_gamepad.ino
    #define KEY_RELEASE(x)
    #define KEY_PRESS(x)

    //Globals
    const int xCenter = 250;    // Tweak for your D-pad's center values, should be 250
    const int yCenter = 250;
    const int xDeadband = 150;  // Sets the size of the center deadband
    const int yDeadband = 150;

    // D-pad: UP = w, RIGHT = d, DOWN = s, LEFT = a, DPadNone is "center value"
    const char dPadUp = 26; //'w';
    const char dPadRt = 7; //'d';
    const char dPadDn = 22; //'s';
    const char dPadLt = 4; //'a';
    const char dPadNone = 0; //'0';
    //-------------------------------------

    void setup() {
      Serial.begin(9600);
      for(word i = 0; i < ARRAY_SIZE; i++) {
        buttonWas[i] = buttonIs[i] = unbounce[i] = 1;
        pinMode(button[i], INPUT_PULLUP);
      }
    }

    //-------------------------------------
    // добавил из azeron_gamepad.ino
    void loop()
    {
      readJoystick();
      readKeys();
    }


    void readJoystick()
    {
      float angle = 0.0;
      static char lastKeyPressed = dPadNone;
      int joyX = analogRead(A2);  // Or A3, rotates 0 angle (0 degrees is full right by default)
      int joyY = analogRead(A3);  // Or A2, rotates 0 angle
      double mapJoyX = map(joyX, 0, 1023, 0, 500);
      double mapJoyY = map(joyY, 0, 1023, 0, 500);

      if ((mapJoyX <= xCenter + xDeadband && mapJoyX >= xCenter - xDeadband) && (mapJoyY <= yCenter + yDeadband && mapJoyY >= yCenter - yDeadband))
      {
        angle = 1000.0;
        if (lastKeyPressed != dPadNone)
        {
          KEY_RELEASE(lastKeyPressed);
          lastKeyPressed = dPadNone;
        }
      }
      else
      { // Else determine its angle
        angle = atan2(mapJoyY - yCenter , mapJoyX - xCenter) * 57.2957795;
      }
      if ((angle >= 45 && angle <= 135))
      {  // UP
        if (lastKeyPressed != dPadUp)
        {
          if (lastKeyPressed != dPadNone)
          {
            KEY_RELEASE(lastKeyPressed);
          }
          lastKeyPressed = dPadUp;
          KEY_PRESS(dPadUp)
        }
      }
      else if (angle < 45 && angle > -45)
      {  // RIGHT
        if (lastKeyPressed != dPadRt)
        {
          if (lastKeyPressed != dPadNone)
          {
            KEY_RELEASE(lastKeyPressed);
          }
          lastKeyPressed = dPadRt;
          KEY_PRESS(dPadRt)
        }
      }
      else if (angle <= -45 && angle >= -135)
      {  // DOWN
        if (lastKeyPressed != dPadDn)
        {
          if (lastKeyPressed != dPadNone)
          {
            KEY_RELEASE(lastKeyPressed);
          }
          lastKeyPressed = dPadDn;
          KEY_PRESS(dPadDn)
        }
      }
      else if ((angle < -135 && angle >= -180) || (angle <= 180 && angle > 135))
      { // LEFT
        if (lastKeyPressed != dPadLt)
        {
          if (lastKeyPressed != dPadNone)
          {
            KEY_RELEASE(lastKeyPressed);
          }
          lastKeyPressed = dPadLt;
          KEY_PRESS(dPadLt)
        }
      }
    }
    //-------------------------------------

    void readKeys()// добавил из azeron_gamepad.ino
    {
      long curTime = millis();
      for(word i = 0; i < ARRAY_SIZE; i++) {
        buttonIs[i] = digitalRead(button[i]);
        if (unbounce[i] + unbounceInterval > curTime) continue;
        if (buttonIs[i] != buttonWas[i]){
          unbounce[i] = curTime;
          buttonWas[i] = buttonIs[i];
          if (!buttonIs[i]){
            buf[2] = buttonCode[i];
            Serial.write(buf, 8);
          } else {
            buf[2] = 0;
            Serial.write(buf, 8);
          }
        }
      }
    }
     
    Последнее редактирование: 20 фев 2022