Как избавиться от задержки? Arduino и PS2 Keyboard
- Войдите на сайт для отправки комментариев
Пт, 29/06/2012 - 12:33
Решил подключить к Ардуино PS2 клавиатуру - получилось. Пробовал использовать библиотеки PS2Keyboard и еще много других. Во всех библиотеках есть задержка между нажатиями клавиш, т.е. нажимаю клавишу и удерживаю - вначале срабатывает 1 раз, а позже нажатия начинают повторятся с небольшой задержкой. Да, это все хорошо для набирания текста, но мне нужно без задержек, т.е нажал и куча срабатываний без задержек, как с кнопкой, подключенной к ардуино. Думаю дело в библиотеке, а иначе как в компьютерных играх совершать какие-либо движения?
---
Заранее Спасибо.
Не знаю, как у вас, но лично у меня всегда так. В любой программе для ввода текста (да даже в поле, в котором сейчас набираю комментарий) если зажать клавишу, вначале прописывается один символ, потом спустя 2 секунды вводятся остальные. Обе задержки изменяются в настройках, но совсем избежать первой не удается. Думаю, это все должно обрабатываться программно уже.
Эта задержка исключительно реализуется операционной системой. К примеру, есть в разных языках программирования комманды на подобие ReadKey, читающие нажатую кнопку. Помнится еще на QBasic в консоле игру шарики писал, используя подобную комманду. Так что, внимательно изучи библиотеку, может найдешь, как избавится от задержки. А лучше - пойми принцип, на котором работает обмен данными с ПС2 и напиши сам с нуля. Не думаю, что это сильно сложно.
Принцип - изучил, нашел скетч, работающий вообще без библиотеки - то же самое. Может есть спец.режим в контроллере клавиатуры? Вот тот самый скетч:
/* 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-пина клавиатуры.
Спасибо всем, проблему решил. Нужно было просто перевести клавиатуру в режим считывания @make and release@. ЗДесь мы регистрируем только нажатие и отпускание клавиши :-), почти это мне и надо было. Чтобы перевести ее в этот режим нужно:
kbd.write(0xF0); //Отправляем: переключить scan key на ... kbd.write(0x03); //...3 delayMicroseconds(20); //Задержка(на всякий случий) kbd.write(0xF8); //Отправляем: переключить режим считывания //...на make/release delayMicroseconds(20);Здравствуйте. А у меня вопрос:
При нажатии клавиши Q я получаю
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; } }Сохраняйте w перед 15. Это будет скэн код. А в лупе, при скэне == f0, следующий пропускаете.
Только есть ещё keypad и такие как Print Screen, Pause... На их коды посмотрите.
Достаточно на клавиатуре клавиш с многобайтовым скан-кодом нажатия и кодом отпускания. Некислое ветвление получается, если полностью все кнопки пытаться обработать.
Многобайтовые скан-коды (а, тем более, скан-коды переменной длины) нужно обрабатывать конечным автоматом. А реакцию предусмотреть не после каждого принятого байта, а только после завершения последовательности.
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; } }Вот такой вариант (не для всех клавиш)
Оно, как бы, и не сложно, но и не с наскоку. А ещё есть светодиодики, которыми тоже хочется управлять... https://www.youtube.com/watch?v=BgdzBgIMACc
Почему 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() {}"Ругается" на функцию diod_on
При таком коде при нажатии на клавишу 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; } } }Если ещё точнее, то ругань на strip.show();
for (uint16_t i = na; i <= con; i++) { strip.setPixelColor(i, strip.Color(255, 216, 0)); strip.show(); delay(10); }Задержка не решила проблему
Чо пишет то (дословно)?
Дак ничего не пишет.
Нажимаю любые" клавиши, кроме 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; } } }Вынести из цикла strip.show пробовала?
Да.
Так код
case 0x1D: Serial.println("W"); WS2812B.setPixelColor(1, WS2812B.Color(255, 216, 0)); WS2812B.show(); break;бьз цикла
Если убираю код
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; } }Получаю в монитор
В чем смысл всех этих r, w и тп (кто так вообще переменные называет?!)?
Сделала проверку получаемых кодов
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 получаю
В чем смысл всех этих r, w и тп (кто так вообще переменные называет?!)?
НУ пока будут называться так
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 достигнет - для меня загадка.
Работает. Но получаю код нажатия и отпускания
Ну и вот q. Вначале оно равно 1, первое условие не выполняется, выполняется второе и q = 2. И в конце этого же if опять оно приравнивается 1. Как оно 11 достигнет - для меня загадка.Я, честно говоря, скопировала этот код, потому что не разобралась как он работает.
Ну я тоже не догоняю. На этом «мои полномочия все» )))
Как ещё вариант:
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 и зачем его фильтровать...
15 это код клавиши Q при нажатии
А F0 15 это два кода при отпускании клавиши
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; } }Мошт так?
Получаю два кода
Странно, не должно же...
Мошт ещё кто по умнее заглянет и подскажет...
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; } }Хочешь сказать так только Q и W «двоятся»?
Да
Покажи весь последний код.
#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; } } }Нипанятна. Надо подумать.
клавиатуру поменяй.
Как вариант...
клавиатуру поменяй.
На книгу о вкусной и здоровой пище.
С клавиатурой всё в порядке)