Ich baue gerade ein Gerät, das ein Signal an eine Schaltung geben soll, wenn man eine "Num"(Zahlen)-Taste einer an den PC angeschlossenen Tastatur betätigt. Das UART dient mir aber derweil für Debug-Zwecke. Die Scancodes der Tastatur werden auch richtig empfangen, aber es mischen sich auch Host -> KB-Kommandos dazu, zumindest nach einem ACK(FA) der Tastatur. Kann es sein, dass ein Kommandoparameter ohne vorheriges "loslassen"(High) der Clock-Leitung gesendet wird? Wenn ich auf der Tastatur keine Taste betätige sendet sie in regelmäßigen Intervallen(1sec) FE == Resend. Es könnt aber auch vom Computer kommen. Ansonsten funktioniert die Tastatur einwandfrei. Ich teste das Ganze aber auf einem Laptop, kann das der Grund sein? Hier ein paar Links, die mir als Infirmationsquelle dienten: http://www.computer-engineering.org http://www.beyondlogic.org/keyboard/keybrd.htm http://elektronik-kompendium.de/public/arnerossius/schaltungen/avr/kdbleds.htm Danke schon mal im Voraus, Bei euch weiß sicher einer den Fehler :) MisterMime
Die Tastatur ist übrigends an PB3 und 4 angeschlossen und ein MAX232(zum PC) an TXD(PD1) und der AVR ist ein Tiny2313
Hallo, Kann mir bitte Jemand mit einem Oszi so ein Bild machen? http://www.computer-engineering.org/index.php?title=Image:Waveform2.jpg Zumindest an der Stelle, wenn die Tastatur eine Antwort (FA) geschickt hat und der Host einen Parameter schickt. Den Übergang zumindest. Werden da beide Leitungen kurz High? Bei dem Einschalten einer Tastaturled wird ja: zuerst E0 vom Host gesendet FA von der Tastatur eine Bitmaske für den Ledstatus und noch ein FA Wäre sehr nett.
Du mußt mit Deinem Gerät prüfen, ob der PS2-port gerade frei ist, also die interne Computertastatur gerade nicht ´rumdödelt. Dazu mußt Du den idle Zustand der Clock und Datenleitung, direkt bevor das Gerät senden will, nochmals überprüfen (beide müssen "High" sein). Es werden Timings in den Spezifikationen genannt, die einzuhalten sind, sonst gibt es Datensalat. Ist der Bus gerade nicht frei, muß Dein Gerät die Scancodes solange speichern können, bis der Bus wieder frei ist. Guck mal auch bei www.marjorie.de, da gibt´s ´ne schön kompakte Beschreibung.
Die interne Tastatur gibt nix an dem Keyboard-Anschluss aus. Ich seh da nur Teile der Initialisierungsdaten wenn ich die externe anstecke. Es wird nur z.B. ein "Numlock-led-ein"-Signal gesendet wenn ich auf der internen was drücke sonst nix. Aber dass ich auf HIGH bei beiden Leitungen warten muss kann schon sein, ich schau mir das gleich nochmal an.
Wenn ich zusätlich noch ein wait für das andere beim Ende von Discard und Process einfüge kommen nur falsche Werte heraus. Es muss irgendwie an dem Übergang zum nächsten Byte liegen. Wenn der Host zusätzlich zum Kommando noch einen Parameter sendet.
Wenn man:
1 | sbis Pin, DATA |
2 | rcall discard |
am Ende von Process einfügt dann wir bei dem Einschalten der Num-Led das zweite FA durch ein E9(06 wird vom Host gesendet) oder FF ersetzt(wenn 00 ges wird.)... So: (ein)FA E9 (aus)FA FF so sollte es sein: FA FA FA FA Die Parameter sollten nicht empfangen werden. Mit denen: FA 06 FA FA 00 FA Da rutschen dann die Parameter in das zweite ACK (FA) ??
Ich versteh nur Bahnhof... Bei meinem Joystick-Adapter, den ich mal gebaut habe, habe ich einen externen Tastaturanschluß angefügt, um das Teil zwischen die PS/2 Leine hängen zu können. Was mein Adapter tut, ist diesen externen Anschluß zu kontrollieren, ob da beide Leitungen High sind. Die Tastatur hat als Vorrang vor den Joysticks. Wenn Die Leitungen Datenverkehr anzeigen, darf nichts vom Gerät auf den Bus gegeben werden, solange bis für mindestens eine Bytelänge Ruhe ist. Irgendwo stand dieser Mindestabstand mal beschrieben. Die Tastatur selbst kontrolliert auch den Idlezustand, wenn das Gerät sendet, muß sie die Daten speichern, bis der Bus wieder frei ist und darf dann erst wieder senden. Das funktioniert eigentlich sehr zuverlässig.
Ich will mit meinem Gerät ja keine Daten senden sondern nur auf eine Übertragung von der Tastatur reagieren. Wenn man eine Taste am Ziffernblock drückt. Bei meiner Routine kommen aber seltsamerweise Kommandos von der Tastatur zum Keyboard an. Hier mal ein Beispiel: (Bei Betätigen der Caps-Lock Taste, großschreiben) Erstmal ohne herausfiltern der Host -> KB- Kommandos.+ Tastatur: 58 - Betätigung der Capslock-Taste/Scancode PC: ED - Set Status Leds Tastatur: FA - Acknowledge/Verstanden PC: 04 = 0b00000100 - Bitmaske für eingeschaltete Numlockled Tastatur: FA - -||- Die Leitung ist kurz Idle Tastatur: (Taste wird losgelassen) F0 - "Loslass"-Code 58 - Der Scancode der Capslocktaste, wie oben Fertig Mein Code empfängt aber folgenes: 58 FA 04 FA F0 58 Das ED ist, wie es sollte nicht da, aber 04 sehrwohl, obwohl es vom PC gesendet wird. Es sollte so sein: 58 FA FA F0 58 FA kann ich ja ignorieren und den auf F0 folgenden Scancode, dann hab ich nur mehr 58 -- So wie es sein soll, aber das wird ja später gemacht. Kann es sein, dass (die Tastatur gibt ja CLK vor!) nach einem ACK von einem Befehl der einen Parameter hat, die Leitung zwischen ACK und Parameter nicht im Idle-Zustand ist? Die Timings sind ja nicht wichtig, da der µC ja nur "lauscht" und nicht senden will. Das war jetzt zwar lang, aber ich hoffe, dass es verständlich ist :) Ich dachte mir schon, der Thread wird zum Selbstgespräch... Danke, dass du mir helfen willst TravelRec. ..., MM
Ja nöö, das Timing ist schon wichtig, wenn der Controller alles mitbekommen soll. Außerdem muß der Controller schnell genug den Bus scannen und immer den Idle-Zustand checken. Daß das Gerät nichts senden soll, ist erstmal hilfreich. Vom Prinzip her kann Dein Gerät doch aber genau feststellen, was der PC sendet und was von der Tastatur kommt (siehe hier: http://www.marjorie.de/ps2/ps2_protocol.htm die Diagramme unten). Demzufolge ist das Ausmaskieren nichtrelevanter Bytes doch kein Problem, oder?
Ja, bei den Kommandos ist es ja kein Problem, bei den Kommandos funktioniert es ja. Aber nachdem ein FA von der Tastatur(ACK für das Kommando) kommt, wie es sollte sendet ja der PC eine Antwort. Diese Antwort bekommt mein Code auch, obwohl er ihn, indem er in der Hauptschleife wartet bis CLK oder DATA Low wird verwerfen. Aber anscheinend ist die Leitung zwischen dem FA und dem Parameter nicht frei. Übrigends ist die Seite die gleiche wie www.computer-engineering.org , nur halt übersetzt... Die Links hab ich ja ganz oben schon gepostet. Eigentlich sollten die Hostkommandos gar nicht stimmen, weil der Zustand bei CLK=High statt Low gelesen wird.(zumindest ist es nicht garantiert)
Najaaa, aber bevor der PC etwas sendet, MUSS er doch einen langen Clock-Low Puls geben, der seine Daten quasi einleitet und die Tastatur zum Senden der Clocks animiert. Wenn dieser lange Puls von Deinem Code wahrgenommen wird, kann doch das kommende Gelaber getrost verworfen werden, bis der PC dann mal wieder fertig ist.
Andere Frage: hast Du ein Oszi oder einen Logic-Analyzer? Dann guck Dir doch mal die Schnittstellensignale an und das, was Dein Code daraus macht...
Beim langen brauch ich doch wieder einen Timer oder zumindest eine Zählschleife... Könntest du mal kurz in einen Chat mit mir gehen, dann können wir das schneller besprechen :)
Hab ich eben nicht. Aber der Unterschied ist ja, dass CLK statt DATA LOW wird(beim Start) da brauch ich doch nicht schaun wie lang CLK low ist, oder?
Wie kommst Du darauf? CLK timet doch die Übertragung! http://de.wikipedia.org/wiki/PS/2-Schnittstelle
Schau mal bei der Überschrift Protokoll, beim Punkt 4: Zuerst zieht die Tastatur Data auf low (Startbit), um den Beginn eines zu übertragenden Bytes zu kennzeichnen. Danach wird von der Tastatur Clock für eine Weile auf low gezogen. Beim "Daten vom PC"-Bild ist CLK ja am Ende Low, kann es sein, dass es nicht HIGH geht sondern der Parameter( 02 ) ohne "Einleitung"(fallende Flanke an CLK) gesendet wird?
Auch unter der Überschrift Protokoll, ganz zu Anfang steht für den Zustand CLK=0 "PC ist beschäftigt" bzw. "PC wird resettet". Und dann "Grundsätzlich kommt der Takt von der Tastatur, sowohl zum Senden von Daten an den PC, als auch zum Empfang von Daten vom PC." Also muss der Clock für jedes Zeichen erst wieder auf HIGH gehen, um das Startbit der nächsten Sendung zu übertragen. Allenfalls könnte der PC nach Erkennen des Acknowledge-Bits auf sein Busy verzichten und das DATA-Low übergangslos fortsetzen, aber ob das Praxis ist, weiß ich nicht.
Hallo Maierhofer! (MisterMime) Dun schreibtst so wirres Zeug das ich Kopfweh davon bekomm, hast du sonst nichts zu tun? @ alle anderen: Ihr seid genauso schlimm ;D
Ach nochwas,........ Blub. Hier gibts ja nicht mal eine Editier-Funktion, tzzzzz.
Es gibt eine Editier-Funktion man muss nur regestriert sein.
Hat irgendwer ein Speicheroszi, und kann er mir eine Aufnahme von der Tastaturkommunikation machen? Im ersten Post sind Links gepostet, auf denen die Pinbelegungen sind. Einfach die eingänge an DATA und CLK hängen, sind Opencollector/drain-Ausgänge(0-5V) ...
Was ist nun wirklich Dein Problem? Wie das Protokoll geht, kann es inzwischen ja eigentlich nicht mehr sein. Oder? Gruß Johannes
Das weiß ich eigentlich schon, ich versteh aber nicht warum mein "Programm" auch die Kommandoparameter empfängt und warum ein mal pro Sekunde Resend gesendet wird... Vielleicht, eine "Überwachung", damit der Laptop weiß, dass die Tastatur nicht abgesteckt wurde. Die CLK-Leitung wird seltsamerweise auch getoggelt, wenn keine Daten gesendet werden. Wenn nur jemand mal versuchen würde den Code "nachzuvollziehen"...... ..., Mistermime
Um das zu verifizieren, nimm einfach mal ´nen anderen Computer, meinethalben einen normalen Tower-PC. Und die Clock-Leitung kann NUR die Tastatur toggeln, niemand sonst (höchstens Dein Gerät....).
Es ist offenbar doch noch das Protokoll, wo Dein Verständnis klemmt. Also fangen wir noch einmal ganz von hinten an :-) Dass die CLK-Leitung auch getoggelt wird, wenn keine Daten gesendet werden, ist alles andere als seltsam, sondern das ganz normale "Busy" vom PC, das jederzeit und auch rein prophylaktisch vorkommen kann, da die Tastatur ja den Takt erzeugt und von sich aus halt nicht ahnen kann, wann der PC empfangen kann und wann nicht. Das ist wie mit dem berühmten "Bitte nicht stören"-Schild an der Hotelzimmertür: Das hängt man ja auch nicht erst dann auf, wenn das Zimmermädchen schon am (doppelt belegten) Bett steht... Dann die zyklische "Rückversicherung" per Resend - ich denke, mit Deiner Vermutung liegst Du nicht daneben. Derlei hat übrigens einen eigenen Namen: Phantom. Und schließlich ist die Sache mit den Kommandoparametern "in der Literatur" vielleicht nicht völlig klar beschrieben, aber doch streng logisch: Wenn ein bestimmtes Kommando ein Parameterbyte braucht, weiß das sowohl der Sender als auch der Empfänger. Von daher ist es überflüssig, die Sendung des Parameterbytes per RTS-Prozedur erneut anzumelden, sondern es reicht, wenn der Sender (PC) von sich aus nur erneut das Startbit vorgibt. Im übrigen hab ich Deinen Code zwar nicht bis ins Letzte "nachvollzogen", aber immerhin soweit, um noch anzumerken, dass der AVR-DEC-Befehl durchaus mehr kann, als Du ihm zutraust. Ansonsten finde ich ihn etwas zu sehr "klein in klein" formuliert. Konkret ist er nicht in der Lage, mehrere Bytes zu überblicken - was zum Ausblenden der fraglichen Sendungen vom PC aber unbedingt nötig ist. Ich hoffe, mal ein bisschen geholfen zu haben. Gruß Johannes
Falls es noch interresse besteht, folgt hier ist mein Code. Kommunikation in beide Richtungen möglich. Getestet mit Terminalprogramm Docklight. Viel Spaß damit Gruß Daniel
1 | /*****************************************************
|
2 | This program was produced by the
|
3 | CodeWizardAVR V1.25.2 Standard
|
4 | Automatic Program Generator
|
5 | © Copyright 1998-2006 Pavel Haiduc, HP InfoTech s.r.l.
|
6 | http://www.hpinfotech.com
|
7 | |
8 | Project : PS2toRS232
|
9 | Version : 1.0
|
10 | Date : 21.12.2006
|
11 | Author : Daniel xxx
|
12 | Company :
|
13 | Comments:
|
14 | |
15 | |
16 | Chip type : ATtiny2313
|
17 | Clock frequency : 7,372800 MHz
|
18 | Memory model : Tiny
|
19 | External SRAM size : 0
|
20 | Data Stack size : 32
|
21 | |
22 | Beschreibung siehe wiki->
|
23 | http://de.wikipedia.org/wiki/PS/2-Schnittstelle
|
24 | *****************************************************/
|
25 | |
26 | #include <tiny2313.h> |
27 | #include <io.h> |
28 | // Standard Input/Output functions
|
29 | #include <stdio.h> |
30 | |
31 | #define DATA 2 //INT0
|
32 | #define CLOCK 3 //INT1
|
33 | #define LED0 5
|
34 | #define LED1 6
|
35 | #define UDRE 5
|
36 | |
37 | unsigned char recieve_bit; |
38 | unsigned char checksum; |
39 | unsigned char recieve_byte[10]; |
40 | unsigned char keyboard_byte[10]; |
41 | unsigned char todo; |
42 | unsigned char send_byte; |
43 | unsigned char rec_byte; |
44 | // External Interrupt 0 service routine
|
45 | interrupt [EXT_INT0] void ext_int0_isr(void) |
46 | {
|
47 | while (PIND.CLOCK==1); //Warten bis CLOCK=LOW |
48 | while (PIND.CLOCK==0); //Warten bis CLOCL=HIGH |
49 | GIMSK = 0x80; //INT0 sperren und INT1 aktivieren |
50 | recieve_bit = 0; |
51 | checksum = 0; |
52 | }
|
53 | |
54 | // External Interrupt 1 service routine
|
55 | interrupt [EXT_INT1] void ext_int1_isr(void) |
56 | {
|
57 | if(PIND.DATA==0){recieve_byte[recieve_bit]=0;PORTD.LED1=0;} |
58 | if(PIND.DATA==1){recieve_byte[recieve_bit]=1;PORTD.LED1=1;} |
59 | while (PIND.CLOCK==0); //Warten bis CLOCL=HIGH |
60 | recieve_bit++; |
61 | if (recieve_bit==10) |
62 | {
|
63 | GIMSK = 0x00; |
64 | todo=1; |
65 | }
|
66 | }
|
67 | |
68 | // USART Receiver interrupt service routine
|
69 | interrupt [USART_RXC] void usart_rx_isr(void) |
70 | {
|
71 | rec_byte=UDR; |
72 | todo=2; |
73 | }
|
74 | |
75 | void READ_BYTE_FROM_KEYBOARD(void); |
76 | void WRITE_BYTE_TO_KEYBOARD(void); |
77 | void SEND_UART(void); |
78 | |
79 | void main(void) |
80 | {
|
81 | // Port D initialization
|
82 | // Func6=Out Func5=Out Func4=In Func3=In Func2=In Func1=Out Func0=In
|
83 | // State6=1 State5=1 State4=P State3=P State2=P State1=0 State0=P
|
84 | DDRD = 0b01100000; |
85 | PORTD = 0b01111101; |
86 | |
87 | // Crystal Oscillator division factor: 1
|
88 | #pragma optsize-
|
89 | CLKPR=0x80; |
90 | CLKPR=0x00; |
91 | #ifdef _OPTIMIZE_SIZE_
|
92 | #pragma optsize+
|
93 | #endif
|
94 | // Port D initialization
|
95 | // Func6=Out Func5=Out Func4=In Func3=In Func2=In Func1=Out Func0=In
|
96 | // State6=1 State5=1 State4=P State3=P State2=P State1=0 State0=P
|
97 | DDRD = 0b01100010; |
98 | PORTD = 0b01111001; |
99 | // USART initialization
|
100 | // Communication Parameters: 8 Data, 1 Stop, No Parity
|
101 | // USART Receiver: On
|
102 | // USART Transmitter: On
|
103 | // USART Mode: Asynchronous
|
104 | // USART Baud rate: 115200
|
105 | UCSRB=0x98; |
106 | UBRRL=0x03; |
107 | |
108 | todo=0; |
109 | |
110 | // External Interrupt(s) initialization
|
111 | // INT0: On
|
112 | // INT0 Mode: Low level
|
113 | // INT1: On
|
114 | // INT1 Mode: Low level
|
115 | // Interrupt on any change on pins PCINT0-7: Off
|
116 | GIMSK=0x40; |
117 | MCUCR=0x00; |
118 | EIFR=0xC0; |
119 | PORTD &= ~(1<<LED0); |
120 | // Global enable interrupts
|
121 | #asm("sei")
|
122 | |
123 | while (1) |
124 | {
|
125 | if(todo==1)READ_BYTE_FROM_KEYBOARD(); |
126 | if(todo==2 && PIND.CLOCK==1 && PIND.DATA==1)WRITE_BYTE_TO_KEYBOARD(); |
127 | };
|
128 | }
|
129 | |
130 | void WRITE_BYTE_TO_KEYBOARD(void) |
131 | {
|
132 | unsigned char command; |
133 | unsigned char x; |
134 | #asm("cli")
|
135 | command=rec_byte; |
136 | for(x=0;x<8;x++)keyboard_byte[x]=0; |
137 | if(command>=128){command = command - 128; keyboard_byte[7] = 1;} |
138 | if(command>= 64){command = command - 64; keyboard_byte[6] = 1;} |
139 | if(command>= 32){command = command - 32; keyboard_byte[5] = 1;} |
140 | if(command>= 16){command = command - 16; keyboard_byte[4] = 1;} |
141 | if(command>= 8){command = command - 8; keyboard_byte[3] = 1;} |
142 | if(command>= 4){command = command - 4; keyboard_byte[2] = 1;} |
143 | if(command>= 2){command = command - 2; keyboard_byte[1] = 1;} |
144 | if(command>= 1)keyboard_byte[0]=1; |
145 | keyboard_byte[8] = 1; |
146 | keyboard_byte[9] = 1; |
147 | for(x=0;x<8;x++) keyboard_byte[8]^= keyboard_byte[x]; |
148 | PORTD.LED0 = 0; |
149 | //100µs CLOCK auf LOW
|
150 | DDRD.CLOCK = 1; //CLOCK->AUSGANG |
151 | PORTD.CLOCK = 0; |
152 | TCNT0 = 0x00; |
153 | TCCR0B = 0x03; |
154 | while(TCNT0 <= 10); |
155 | TCCR0B = 0x00; |
156 | //Request to send mit DATA auf LOW
|
157 | PORTD.DATA = 0; //Startbitsignalisieren |
158 | DDRD.DATA = 1; //DATA->Ausgang |
159 | TCNT0 = 0x00; |
160 | TCCR0B = 0x03; |
161 | while(TCNT0 <= 2); |
162 | TCCR0B = 0x00; |
163 | //CLOCK wieder als Eingang mit HIGH durch PULLUP
|
164 | DDRD.CLOCK = 0; //CLOCK->Eingang |
165 | PORTD.CLOCK = 1; |
166 | //Daten werden bei LOW geschrieben und vom Eingabegerät mit HIGH übernommen
|
167 | while(PIND.CLOCK==1); |
168 | while(PIND.CLOCK==0); |
169 | while(PIND.CLOCK==1); |
170 | for(x=0;x<9;x++) |
171 | {
|
172 | if(keyboard_byte[x]==0) PORTD.DATA = 0; |
173 | else PORTD.DATA = 1; |
174 | while(PIND.CLOCK==0); |
175 | while(PIND.CLOCK==1); |
176 | }
|
177 | |
178 | DDRD.DATA = 0; //DATA->Eingang |
179 | // TCNT0 = 0x00;
|
180 | // TCCR0B = 0x03;
|
181 | // while(TCNT0 <= 1);
|
182 | //TCCR0B = 0x00;
|
183 | while(PIND.DATA==1); |
184 | while(PIND.CLOCK==1); |
185 | while(PIND.CLOCK==0); |
186 | while(PIND.DATA==0); |
187 | todo=0; |
188 | #asm("sei")
|
189 | }
|
190 | void READ_BYTE_FROM_KEYBOARD(void) |
191 | {
|
192 | unsigned char x; |
193 | unsigned char chk=1; |
194 | unsigned char note=0; |
195 | DDRD.CLOCK = 1; |
196 | PORTD.CLOCK = 0; |
197 | for(x=0;x<8;x++)chk^= recieve_byte[x]; |
198 | if(chk==recieve_byte[8]) |
199 | {
|
200 | if(recieve_byte[0]==1)note=note+ 1; |
201 | if(recieve_byte[1]==1)note=note+ 2; |
202 | if(recieve_byte[2]==1)note=note+ 4; |
203 | if(recieve_byte[3]==1)note=note+ 8; |
204 | if(recieve_byte[4]==1)note=note+ 16; |
205 | if(recieve_byte[5]==1)note=note+ 32; |
206 | if(recieve_byte[6]==1)note=note+ 64; |
207 | if(recieve_byte[7]==1)note=note+128; |
208 | send_byte=note; |
209 | SEND_UART(); |
210 | }
|
211 | todo=0; |
212 | DDRD.CLOCK = 0; |
213 | PORTD.CLOCK = 1; |
214 | GIMSK = 0x40; |
215 | }
|
216 | |
217 | |
218 | void SEND_UART(void) |
219 | {
|
220 | while(UCSRA.UDRE==0); |
221 | UDR = send_byte; |
222 | }
|
Ein bischen sehr spät aber doch noch, die funktionierende Version vo dem ganzen. Danke für eure Hilfe, Leute! Schade, dass mir keiner eine Logikanalysator-"Aufnahme" gemacht hat... Aber ich habe sie dann mit einem Playstation SingStar-Mikrophonadapter, der Stereo hat aufnehmen können.
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.