Как избавиться от задержки? Arduino и PS2 Keyboard

krikus
Offline
Зарегистрирован: 22.07.2011

Решил подключить к Ардуино PS2 клавиатуру - получилось. Пробовал использовать библиотеки PS2Keyboard и еще много других. Во всех библиотеках есть задержка между нажатиями клавиш, т.е. нажимаю клавишу и удерживаю - вначале срабатывает 1 раз, а позже нажатия начинают повторятся с небольшой задержкой. Да, это все хорошо для набирания текста, но мне нужно без задержек, т.е нажал и куча срабатываний без задержек, как с кнопкой, подключенной к ардуино. Думаю дело в библиотеке, а иначе как в компьютерных играх совершать какие-либо движения?

---

Заранее Спасибо.

gwer
Offline
Зарегистрирован: 09.06.2012

Не знаю, как у вас, но лично у меня всегда так. В любой программе для ввода текста (да даже в поле, в котором сейчас набираю комментарий) если зажать клавишу, вначале прописывается один символ, потом спустя 2 секунды вводятся остальные. Обе задержки изменяются в настройках, но совсем избежать первой не удается. Думаю, это все должно обрабатываться программно уже.

MAFia
Offline
Зарегистрирован: 26.10.2011

Эта задержка исключительно реализуется операционной системой. К примеру, есть в разных языках программирования комманды на подобие  ReadKey, читающие нажатую кнопку. Помнится еще на QBasic в консоле игру шарики писал, используя подобную комманду. Так что, внимательно изучи библиотеку, может найдешь, как избавится от задержки. А лучше - пойми принцип, на котором работает обмен данными с ПС2 и напиши сам с нуля. Не думаю, что это сильно  сложно.

krikus
Offline
Зарегистрирован: 22.07.2011

Принцип - изучил, нашел скетч, работающий вообще без библиотеки - то же самое. Может есть спец.режим в контроллере клавиатуры? Вот тот самый скетч:

/*
PS/2 Keyboard Input
*/

#define LED 13
#define CLK 2
#define DAT 3

// if I put the keyboard map in here then keys[scan code] would return 
// the ascii value of the scan code.
unsigned char keys[128] =
{
};

void setup()
{
  pinMode(LED, OUTPUT);
  pinMode(CLK, INPUT);
  pinMode(DAT, INPUT);
  digitalWrite(CLK, HIGH);
  digitalWrite(DAT, HIGH);
  delayMicroseconds(50);
  Serial.begin(9600);
}

void loop()
{
  byte b = readkey(); 
  if (b == 0xF0)
  {
    // key released
    b = readkey();
  }
  else
  {
    Serial.print(b, HEX);
    Serial.print(" ");
  }
}

byte readkey()
{
  byte _start = 0;
  byte buf = 0;
  byte _parity = 0;
  byte _stop = 0;
  
  waitClockLow();
    
  _start = digitalRead(DAT);

  if (_start == 0)
  {
    waitClockLow();
    for (byte c=0; c<8; c++)
    {
      buf = buf | (digitalRead(DAT) << c);
      waitClockLow();
    }
  
    _parity = digitalRead(DAT);
    waitClockLow();
  
    _stop = digitalRead(DAT);
  }
  return buf;
}

void waitClockLow()
{
  if (digitalRead(CLK) == LOW)
    while (digitalRead(CLK) == LOW)
    {
    }
  while (digitalRead(CLK) == HIGH)
  {
  }
}

Из скетча видно - единственное, что может оказать задержку, это функция waitClockLow - и то, она работает в зависимости от состояния clock-пина клавиатуры.

krikus
Offline
Зарегистрирован: 22.07.2011

Спасибо всем, проблему решил. Нужно было просто перевести клавиатуру в режим считывания @make and release@. ЗДесь мы регистрируем только нажатие и отпускание клавиши :-), почти это мне и надо было. Чтобы перевести ее в этот режим нужно:

  kbd.write(0xF0); //Отправляем: переключить scan key на ...
  kbd.write(0x03); //...3
  delayMicroseconds(20); //Задержка(на всякий случий)
  kbd.write(0xF8); //Отправляем: переключить режим считывания
                     //...на make/release
  delayMicroseconds(20); 

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Здравствуйте. А у меня вопрос:

При нажатии клавиши Q я получаю

15
F0
15
 
Как я понимаю, при нажатии код 15 и при отпускании код 15.
Как мне избавиться от второго кода при отпускании?
volatile uint8_t q = 1;
volatile uint8_t w = 0;

void setup() {
  pinMode(2, INPUT);
  attachInterrupt(1, ps2Keyboard, FALLING);
  Serial.begin(57600);

}


void ps2Keyboard() {
  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {
    Serial.println(w, HEX);
    q = 1;
    w = 0;
  }
}

 

 

Green
Offline
Зарегистрирован: 01.10.2015

Сохраняйте w перед 15. Это будет скэн код. А в лупе, при скэне == f0, следующий пропускаете.
Только есть ещё keypad и такие как Print Screen, Pause... На их коды посмотрите.

sadman41
Offline
Зарегистрирован: 19.10.2016

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

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Многобайтовые скан-коды (а, тем более, скан-коды переменной длины) нужно обрабатывать конечным автоматом. А реакцию предусмотреть не после каждого принятого байта, а только после завершения последовательности.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {

    if (w != 0xF0) {
      r = w;
    } else {
      Serial.println(r, HEX);
    }

    q = 1;
    w = 0;
  }
}

Вот такой вариант (не для всех клавиш)

 

Green
Offline
Зарегистрирован: 01.10.2015

Оно, как бы, и не сложно, но и не с наскоку. А ещё есть светодиодики, которыми тоже хочется управлять... https://www.youtube.com/watch?v=BgdzBgIMACc

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Почему Serial.println(r, HEX) (и case) срабатывает два раза?

Но срабатывают дважды только те клавиши, которые указаны в case 

#include <Adafruit_NeoPixel.h>

#define PIN  10
#define NUMPIXELS 192

Adafruit_NeoPixel strip (NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


volatile uint8_t q = 1;
volatile uint8_t w = 0;
volatile uint8_t r = 0;


void setup() {
  strip.begin();
  strip.setBrightness(255);
  strip.clear();
  strip.show();

  pinMode(2, INPUT);
  attachInterrupt(1, ps2Keyboard, FALLING);
  Serial.begin(9600);

}


void diod_on(uint8_t na, uint8_t con) {
  for (int i = na; i <= con; i++) {
    strip.setPixelColor(i, strip.Color(255, 216, 0));
    strip.show();
  }
}



void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {

    if (w != 0xF0) {
      r = w;
    } else {

      //noInterrupts();
      Serial.println(r, HEX);

      switch (r) {
        case 0x1D://Q
          diod_on(0, 10);
          break;
      }

      //interrupts();
    }
    q = 1;
    w = 0;
  }
}




void loop() {}

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

"Ругается" на функцию diod_on

При таком коде при нажатии на клавишу Q в мониторе порта получаю

15
Q
 
далее ничего не происходит, при нажатии любой клавиши.
 
#include <Adafruit_NeoPixel.h>

#define PIN  10
#define NUMPIXELS 192

Adafruit_NeoPixel strip (NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


volatile uint8_t q = 1;
volatile uint8_t w = 0;
volatile uint8_t r = 0;

bool flag = false;



void setup() {
  strip.begin();
  strip.setBrightness(255);
  strip.clear();
  strip.show();

  pinMode(2, INPUT);
  attachInterrupt(1, ps2Keyboard, FALLING);
  Serial.begin(9600);

}


void diod_on(uint16_t na, uint16_t con) {
  for (int i = na; i <= con; i++) {
    strip.setPixelColor(i, strip.Color(255, 216, 0));
    strip.show();
  }
}



void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {

    if (w != 0xF0) {
      r = w;
    } else {
      flag = true;
    }
    q = 1;
    w = 0;
  }
}


void loop() {

  if (flag) {
    flag = false;
    Serial.println(r, HEX);

    switch (r) {
      case 0x15:
        Serial.println("Q");
        diod_on(0, 10);
        break;

      case 0x1D:
        Serial.println("W");
        break;

    }
  }
}

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Если ещё точнее, то ругань на strip.show();

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
  for (uint16_t i = na; i <= con; i++) {
    strip.setPixelColor(i, strip.Color(255, 216, 0));
    strip.show();
    delay(10);
  }

Задержка не решила проблему

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Чо пишет то (дословно)?

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Дак ничего не пишет.

Нажимаю любые" клавиши, кроме Q и W в монитор порта получаю коды.

Стоить только нажать Q (или W) в монитор порта получу 15 Q (1D W) и на этом всё, больше на нажатие клавиш не реагирует.

Если убрать strip.show(), всё ОК

#include <Adafruit_NeoPixel.h>

#define PIN  10
#define NUMPIXELS 192

Adafruit_NeoPixel strip (NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


volatile uint8_t q = 1;
volatile uint8_t w = 0;
volatile uint8_t r = 0;

bool flag = false;



void setup() {
  strip.begin();
  strip.setBrightness(255);
  strip.clear();
  strip.show();

  pinMode(2, INPUT);
  attachInterrupt(1, ps2Keyboard, FALLING);
  Serial.begin(9600);

}


void diod_on(uint16_t na, uint16_t con) {
  for (int i = na; i <= con; i++) {
    strip.setPixelColor(i, strip.Color(255, 216, 0));
    strip.show();
    delay(10);
  }
}



void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {

    if (w != 0xF0) {
      r = w;
    } else {
      flag = true;
    }
    q = 1;
    w = 0;
  }
}


void loop() {

  if (flag) {
    flag = false;
    Serial.println(r, HEX);

    switch (r) {
      case 0x15:
        Serial.println("Q");
        diod_on(0, 10);
        break;

      case 0x1D:
        Serial.println("W");
        strip.setPixelColor(1, strip.Color(255, 216, 0));
        strip.show();
        break;

    }
  }
}

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Вынести из цикла strip.show пробовала?

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Да.

Так код 

      case 0x1D:
        Serial.println("W");
        WS2812B.setPixelColor(1, WS2812B.Color(255, 216, 0));
        WS2812B.show();
        break;

бьз цикла

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Если убираю код

void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {

    r = w;
    flag = true;
    /*
        if (w != 0xF0) {
          r = w;
        } else {
          flag = true;
        }*/
    q = 1;
    w = 0;
  }
}

Получаю в монитор

15
Q
F0
15
Q
 
И далее всё работает и на кнопки реагирует

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

В чем смысл всех этих r, w и тп (кто так вообще переменные называет?!)?

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Сделала проверку получаемых кодов

void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {

    Serial.println(w, HEX);

    if (w != 0xF0) {
      r = w;
    } else {
      flag = true;
    }

    q = 1;
    w = 0;

  }
}


void loop() {

  if (flag) {
    flag = false;
    Serial.println(r, HEX);


    switch (r) {
      case 0x15:
        Serial.println("Q");
        diod_on(0, 10);
        break;

      case 0x1D:
        Serial.println("W");
        WS2812B.setPixelColor(1, WS2812B.Color(255, 216, 0));
        WS2812B.show();
        break;

    }
  }
}

При первом нажатии на Q получаю

15
F0
15
Q
 
Всё ОК
 
При повторном нажатии получаю
2A
E0
2A
 
Косяк....другие клавиши тоже неверно определяются

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

BOOM пишет:

В чем смысл всех этих r, w и тп (кто так вообще переменные называет?!)?

НУ пока будут называться так

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018
void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {

    if (w != 0xF0) {
      r = w;
      flag = true;
    }
    q = 1;
    w = 0;
  }
}

Попробуй, но я не до конца понимаю причём тут show...

Ну и вот q. Вначале оно равно 1, первое условие не выполняется, выполняется второе и q = 2. И в конце этого же if опять оно приравнивается 1. Как оно 11 достигнет - для меня загадка.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Работает. Но получаю код нажатия и отпускания

15
Q
15
Q
 
Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

BOOM пишет:

Ну и вот q. Вначале оно равно 1, первое условие не выполняется, выполняется второе и q = 2. И в конце этого же if опять оно приравнивается 1. Как оно 11 достигнет - для меня загадка.

Я, честно говоря, скопировала этот код, потому что не разобралась как он работает.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Ну я тоже не догоняю. На этом «мои полномочия все» )))

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Как ещё вариант:

void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {

    if (w != r) {
      r = w;
      flag = true;
    }
    q = 1;
    w = 0;
  }
}

Правда я не знаю что за 0xF0 и зачем его фильтровать...

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

15 это код клавиши Q при нажатии

А F0 15 это два кода при отпускании клавиши

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018
void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {

    if (w != r && w != 0xF0) {
      r = w;
      flag = true;
    }
    q = 1;
    w = 0;
  }
}

Мошт так?

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Получаю два кода 

15
Q
15
Q
 
1D
W
1D
W
 
BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Странно, не должно же...

Мошт ещё кто по умнее заглянет и подскажет...

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018
void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {
    if (w != 0xF0) {
      if (w != r) {
        r = w;
        flag = true;
      }
    }
    q = 1;
    w = 0;
  }
}

 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

24 это E
2D это R
 
BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Хочешь сказать так только Q и W «двоятся»? 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

Да

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Покажи весь последний код.

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017
#include <Adafruit_NeoPixel.h>

#define PIN  10
#define NUMPIXELS 192

Adafruit_NeoPixel WS2812B (NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);


volatile uint8_t q = 1;
volatile uint8_t w = 0;
volatile uint8_t r = 0;

bool flag = false;



void setup() {
  WS2812B.begin();
  WS2812B.setBrightness(255);
  WS2812B.clear();

  pinMode(2, INPUT);

  attachInterrupt(1, ps2Keyboard, FALLING);
  Serial.begin(9600);

}


void diod_on(uint16_t na, uint16_t con) {
  for (int i = na; i <= con; i++) {
    WS2812B.setPixelColor(i, WS2812B.Color(255, 216, 0));
    WS2812B.show();
  }
}



void ps2Keyboard() {

  if (q > 1 && q < 11)w |= digitalRead(2) << q - 2;
  if (++q > 11) {
    if (w != 0xF0) {
      if (w != r) {
        r = w;
        flag = true;
      }
    }
    q = 1;
    w = 0;
  }
}

void loop() {

  if (flag) {
    flag = false;
    Serial.println(r, HEX);


    switch (r) {
      case 0x15:
        Serial.println("Q");
        diod_on(0, 10);
        r = 0;
        break;

      case 0x1D:
        Serial.println("W");
        WS2812B.setPixelColor(1, WS2812B.Color(255, 216, 0));
        WS2812B.show();
        r = 0;
        break;

    }
  }
}

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Нипанятна. Надо подумать.

SAB
Offline
Зарегистрирован: 27.12.2016

клавиатуру поменяй.

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Как вариант...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

SAB пишет:

клавиатуру поменяй.

На книгу о вкусной и здоровой пище. 

Irinka
Irinka аватар
Offline
Зарегистрирован: 28.06.2017

С клавиатурой всё в порядке)