Forum: Mikrocontroller und Digitale Elektronik V-USB: HIDKeys ignoriert ersten Tastendruck


von Patrick (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Zusammen!

Ich habe einen USB-Taster entwickelt, der am PC als USB-Tastatur erkannt 
wird, und der bei einem Tastendruck die Kombination alt+n sendet. Dafür 
habe ich das HIDKeys-Projekt verwendet:
http://www.obdev.at/products/vusb/hidkeys.html

Nun wird aber immer nach dem Anschluss an den PC der erste Tastendruck 
ignoriert. Ich muss immer zweimal drücken, bis alt+n beim PC ankommt.

Hat jemand Erfahrung mit HIDKeys? Wo ist das Problem? Ich hab Euch mal 
die main.c angehängt.

Danke für Eure Hilfe!

von Ernestus P. (malzeit) Benutzerseite


Lesenswert?

Wie kurz/lang ist dein Tastenimpuls. Sehr kurze Impulse (ein paar µs) 
können von der Software übersehen werden, wenn ich es auf die schnelle 
richtig überschaut habe.

Edit: Du benutzt auch Pull-up, und nicht Pull-down?

von Patrick (Gast)


Angehängte Dateien:

Lesenswert?

Danke für Deine Antwort.

Ich habs eben ausprobiert. Es spielt keine Rolle, wie lange der erste 
Tastendruck ist (einige ms bis mehrere s). Er wird einfach nicht 
ausgeführt.

Mein Taster ist mit der Schaltung im Anhang am AVR dran (zwischen P1 und 
P2).

von Ernestus P. (malzeit) Benutzerseite


Lesenswert?

Du hast dich eigentlich recht an die Vorgabe gehalten. Das etwas 
wesentliches herausgekürzt wurde kann ich nicht erkennen.

Jetzt kannst du noch deine einzigen direkten Änderungen falsifizieren. 
Da du nur einen Eingang benutzt ändere die Tastenabfrage etwa so ab.

        if( (lastKey != key) && keyDidChange == 0){ // erst altes 
abarbeiten
            if(key == 1) { // nur zwei Zustaende
              lastkey = 1;
            } else {
              lastkey = 0;
            }
            // lastKey = key;
            keyDidChange = 1;
        }


BTW: Kondensatoren parallel zu Schaltern sind nicht gesund.

von Kai W. (kai-w)


Lesenswert?

Eine Lösung kann ich Dir leider auch nicht anbieten, aber mein 
HIDKeys-Projekt verhält sich genauso, unabhängig ob ich die Eingänge mit 
Tastern, Relais oder einem anderen Controller ansteuere.

Gruß Kai

von Mario M. (Gast)


Lesenswert?

Hier ebenfalls!

Der erste Tastendruck nach einer Weile Nichtbenutzung wird nicht 
erzeugt. Der "Befehl" kommt von einem Barcode-Scanner, dessen erstes 
Zeichen dann jeweils nicht angezeigt wird...

Lg
Mario

von Patrick (Gast)


Lesenswert?

Danke für Eure Hilfe. Ich habs jetzt so gelöst:
1
buildReport(lastKey);
2
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
3
4
  for(;;){  /* main event loop */
Vor der Endlosschleife sende ich gleich, dass kein Taster gedrückt ist. 
Damit funktioniert es bei mir. Vielleicht hilft das den anderen auch.

von Ernestus P. (malzeit) Benutzerseite


Lesenswert?

Patrick schrieb:
> Vor der Endlosschleife sende ich gleich, dass kein Taster gedrückt ist.
> Damit funktioniert es bei mir. Vielleicht hilft das den anderen auch.

Klänge irgendwo plausibel, da das Betriebssystem erstmal von der 
Tastatur hören will, das keine Taste gedrückt ist.

Mario M. schrieb:
> Der erste Tastendruck nach einer Weile Nichtbenutzung wird nicht
> erzeugt. Der "Befehl" kommt von einem Barcode-Scanner, dessen erstes
> Zeichen dann jeweils nicht angezeigt wird...

Vielleicht wäre es dann auch sinnvoll immer vor dem Senden eines 
Tastendrucks ein "keine Taste gedrückt" Signal zum senden. Könnte ja 
sein das der Hack mit V-USB doch zu sehr vom Standard abweicht und 
irgendwelche Timeouts verletzt.

von Kai W. (kai-w)


Lesenswert?

Danke für den Tipp - ich werd's bei Gelegenheit mal ausprobieren (hab' 
das Projekt grade nicht zur Hand)

von Ernestus P. (malzeit) Benutzerseite


Lesenswert?

Ok eigentlich sollte der folgende Abschnitt im main.c das schon 
erledigen. Komisch aber, das Patrick seine Behelfslösung dann 
funktioniert.

        if(TIFR & (1<<TOV0)){   /* 22 ms timer */
            TIFR = 1<<TOV0;
            if(idleRate != 0){
                if(idleCounter > 4){
                    idleCounter -= 5;   /* 22 ms in units of 4 ms */
                }else{
                    idleCounter = idleRate;
                    keyDidChange = 1;
                }
            }

        }

von Ernestus P. (malzeit) Benutzerseite


Lesenswert?

Windows setzt die idleRate wohl auf Null und daher läuft kein idle-Timer

http://proyectosfie.com/html/usb/libro/capitulo13.pdf

> if(idleRate != 0){

Mit einer if-Verzweigung könnte man im Fall ohne idle-Timer vor dem 
Senden eines "Taste gedrückt" immer ein "keine Taste gedrückt" senden 
und hoffen, das man sich damit keine weiteren Probleme einhandelt.

von MWS (Gast)


Lesenswert?

Kommentare ein wenig unpassend ?
1
PORTC = 0x01;   /* disable pull-up for PC0 */

Alle Pins außer PC0 als Ausgang und in Kombination mit obiger Zeile Low:
1
DDRC = 0xfe;    /* PC0 as input */

keyPressed() scannt Pins von 0-6 und wird PC1 als gedrückt erkennen, da 
Low.

Rückgabewert = 2, damit wird key zu 2, woraus hier:
1
*(int *)reportBuffer = pgm_read_word(keyReport[key]);

ein Zufriff auf die 3. Progmem-Zelle erfolgt, obwohl hier mit NUM_KEYS = 
1 nur 2 definiert wurden:
1
static const uchar  keyReport[NUM_KEYS + 1][2] PROGMEM

Damit wird ständig eine unvorhersehbare Kombination geschickt und es ist 
eigentlich verwunderlich, daß es so überhaupt geht.

von Osche R. (Gast)


Lesenswert?

MWS schrieb:

> Damit wird ständig eine unvorhersehbare Kombination geschickt und es ist
> eigentlich verwunderlich, daß es so überhaupt geht.

Das mag wohl sein, hat aber nichts mit dem eigentlichen Problem des OP 
zu tun. Den gleichen Effekt habe ich auch bei diesem Projekt beobachtet:
http://www.schatenseite.de/dulcimer.html Der Bug bzw das Feature scheint 
aber schon in der Musterlösung von OBDev drinzustecken.

Wenn man die Tastatur eine Weile liegenlässt, wird der erste Tastendruck 
ignoriert und erst der zweite übertragen.

Ausserdem passiert es ab und zu, dass die zuletzt gedrückte Taste als 
Dauerfeuer gesendet wird. Der unerwünschte Repeat hört erst auf, wenn 
man eine andere Taste drückt.

Ich habe den usbdrv Release 2009-08-22 verwendet, der atmega324p läuft 
mit 12MHz.


Patrick

von MWS (Gast)


Lesenswert?

Patrick S. schrieb:
> Das mag wohl sein, hat aber nichts mit dem eigentlichen Problem des OP
> zu tun.

Da Du auch nicht erklären kannst, worin der Fehler denn nun genau 
besteht, halte ich's für gewagt zu behaupten daß so ein grober Schnitzer 
nichts damit zu tun hat. Aber selbst wenn's so wär', bevor man sich an 
die unerklärlichen Fehler wagt, schaltet man erst mal die erklärlichen 
ab.

Patrick S. schrieb:
> Wenn man die Tastatur eine Weile liegenlässt, wird der erste Tastendruck
> ignoriert und erst der zweite übertragen.

Was steht dem entgegen, wie bereits von Pastell angesprochen, einen 
Null-Tastencode zu senden, und in Abständen kleiner als die 
"Liegenlasszeit" dies zyklisch zu wiederholen ?

von neanderthaler (Gast)


Lesenswert?

Patrick S. schrieb:
> Der Bug bzw das Feature scheint
> aber schon in der Musterlösung von OBDev drinzustecken.

Jo, ist bei meinem HID-Keys auch so. ATmega8 auf Lochraster, genau nach 
dem Vorschlag von Obdev.
Es wird nach dem Einschalten immer genau der erste Tastendruck 
verschluckt, das Terminal und xev zeigen dabei garnix an. Dann klappts 
aber problemlos, ohne Hänger o.ä., auch nach laaanger Pause (>12 
Stunden).

Gruß,
Jörn

von Patrick (Gast)


Lesenswert?

Anstelle des Sendens for der Endlosschleife, kann man auch die Variable 
keyDidChange mit 1 initialisieren. Dann wird einmal der Teil ausgeführt:
1
if(keyDidChange && usbInterruptIsReady()){
2
            keyDidChange = 0;
3
            /* use last key and not current key status in order to avoid lost
4
               changes in key status. */
5
            buildReport(lastKey);
6
            usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
7
      }
Da lastKey am Anfang 0 ist, wird auch hier ein "keine Tasten gedrückt" 
gesendet. Ich hab das noch nicht ausprobiert, aber es müsste eigentlich 
funktionieren.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.