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!
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?
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).
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.
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
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
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.
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.
Danke für den Tipp - ich werd's bei Gelegenheit mal ausprobieren (hab' das Projekt grade nicht zur Hand)
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; } } }
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.
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.
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
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 ?
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.