【转】Arduino 控制USB设备(5)解析USB键盘的例子

时间:2024-02-25 20:46:37

下面是一个获得 USB 键盘数据的例子【参考1】。原理上说,是将键盘切换为 Boot Protocol 这样就避免了需要具体解析HID的麻烦。

001 /* MAX3421E USB Host controller LCD/keyboard demonstration */
002 //#include <Spi.h>
003 #include "Max3421e.h"
004 #include "Usb.h"
005  
006 /* keyboard data taken from configuration descriptor */
007 #define KBD_ADDR        1
008 #define KBD_EP          1
009 #define KBD_IF          0
010 #define EP_MAXPKTSIZE   8
011 #define EP_POLL         0x0a
012 /**/
013 //******************************************************************************
014 //  macros to identify special charaters(other than Digits and Alphabets)
015 //******************************************************************************
016 #define BANG        (0x1E)
017 #define AT          (0x1F)
018 #define POUND       (0x20)
019 #define DOLLAR      (0x21)
020 #define PERCENT     (0x22)
021 #define CAP         (0x23)
022 #define AND         (0x24)
023 #define STAR        (0x25)
024 #define OPENBKT     (0x26)
025 #define CLOSEBKT    (0x27)
026  
027 #define RETURN      (0x28)
028 #define ESCAPE      (0x29)
029 #define BACKSPACE   (0x2A)
030 #define TAB         (0x2B)
031 #define SPACE       (0x2C)
032 #define HYPHEN      (0x2D)
033 #define EQUAL       (0x2E)
034 #define SQBKTOPEN   (0x2F)
035 #define SQBKTCLOSE  (0x30)
036 #define BACKSLASH   (0x31)
037 #define SEMICOLON   (0x33)
038 #define INVCOMMA    (0x34)
039 #define TILDE       (0x35)
040 #define COMMA       (0x36)
041 #define PERIOD      (0x37)
042 #define FRONTSLASH  (0x38)
043 #define DELETE      (0x4c)
044 /**/
045 /* Modifier masks. One for both modifiers */
046 #define SHIFT       0x22
047 #define CTRL        0x11
048 #define ALT         0x44
049 #define GUI         0x88
050 /**/
051 /* "Sticky keys */
052 #define CAPSLOCK    (0x39)
053 #define NUMLOCK     (0x53)
054 #define SCROLLLOCK  (0x47)
055 /* Sticky keys output report bitmasks */
056 #define bmNUMLOCK       0x01
057 #define bmCAPSLOCK      0x02
058 #define bmSCROLLLOCK    0x04
059 /**/
060 EP_RECORD ep_record[ 2 ];  //endpoint record structure for the keyboard
061  
062 char buf[ 8 ] = { 0 };      //keyboard buffer
063 char old_buf[ 8 ] = { 0 };  //last poll
064 /* Sticky key state */
065 bool numLock = false;
066 bool capsLock = false;
067 bool scrollLock = false;
068 bool line = false;
069  
070 void setup();
071 void loop();
072  
073 MAX3421E Max;
074 USB Usb;
075  
076 void setup() {
077   Serial.begin( 9600 );
078   Serial.println("Start");
079   Max.powerOn();
080   delay( 200 );
081 }
082  
083 void loop() {
084     Max.Task();
085     Usb.Task();
086     if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) {
087  //wait for addressing state
088         kbd_init();
089         Usb.setUsbTaskState( USB_STATE_RUNNING );
090     }
091     if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) { 
092 //poll the keyboard 
093         kbd_poll();
094     }
095 }
096 /* Initialize keyboard */
097 void kbd_init( void )
098 {
099  byte rcode = 0;  //return code
100 /**/
101     /* Initialize data structures */
102     ep_record[ 0 ] = *( Usb.getDevTableEntry( 0,0 )); 
103                            //copy endpoint 0 parameters
104     ep_record[ 1 ].MaxPktSize = EP_MAXPKTSIZE;
105     ep_record[ 1 ].Interval  = EP_POLL;
106     ep_record[ 1 ].sndToggle = bmSNDTOG0;
107     ep_record[ 1 ].rcvToggle = bmRCVTOG0;
108     Usb.setDevTableEntry( 1, ep_record );             
109                            //plug kbd.endpoint parameters to devtable
110     /* Configure device */
111     rcode = Usb.setConf( KBD_ADDR, 0, 1 );                   
112     if( rcode ) {
113         Serial.print("Error attempting to configure keyboard. Return code :");
114         Serial.println( rcode, HEX );
115         while(1);  //stop
116     }
117     /* Set boot protocol */
118     rcode = Usb.setProto( KBD_ADDR, 0, 0, 0 );
119     if( rcode ) {
120         Serial.print("Error attempting to configure boot protocol. Return code :");
121         Serial.println( rcode, HEX );
122         while( 1 );  //stop
123     }
124     delay(2000);
125     Serial.println("Keyboard initialized");
126 }
127  
128 /* Poll keyboard and print result */
129 /* buffer starts at position 2, 0 is modifier key state and 1 is irrelevant */
130 void kbd_poll( void )
131 {
132  char i;
133  static char leds = 0;
134  byte rcode = 0;     //return code
135     /* poll keyboard */
136     rcode = Usb.inTransfer( KBD_ADDR, KBD_EP, 8, buf );
137     if( rcode != 0 ) {
138         return;
139     }//if ( rcode..
140     for( i = 2; i < 8; i++ ) {
141      if( buf[ i ] == 0 ) {  //end of non-empty space
142         break;
143      }
144       if( buf_compare( buf[ i ] ) == false ) {   //if new key
145         switch( buf[ i ] ) {
146           case CAPSLOCK:
147             capsLock =! capsLock;
148             leds = ( capsLock ) ? leds |= bmCAPSLOCK : leds &= ~bmCAPSLOCK;   
149                       // set or clear bit 1 of LED report byte
150             break;
151           case NUMLOCK:
152             numLock =! numLock;
153             leds = ( numLock ) ? leds |= bmNUMLOCK : leds &= ~bmNUMLOCK;      
154                                   // set or clear bit 0 of LED report byte
155             break;
156           case SCROLLLOCK:
157             scrollLock =! scrollLock;
158             leds = ( scrollLock ) ? leds |= bmSCROLLLOCK : leds &= ~bmSCROLLLOCK;
159                                   // set or clear bit 2 of LED report byte
160             break;
161           case DELETE:
162             line = false;
163             break;
164           case RETURN:
165             line =! line;
166             break
167           default:
168             //Serial.print(HIDtoA( buf[ i ], buf[ 0 ] ));
169             break;
170         }//switch( buf[ i ...
171         Serial.print(buf[ i ],HEX);
172         Serial.print(\' \');       
173         Serial.println(buf[ 0 ],HEX);       
174         rcode = Usb.setReport( KBD_ADDR, 0, 1, KBD_IF, 0x02, 0, &leds );
175         if( rcode ) {
176           Serial.print("Set report error: ");
177           Serial.println( rcode, HEX );
178         }//if( rcode ...
179      }//if( buf_compare( buf[ i ] ) == false ...
180     }//for( i = 2...
181     for( i = 2; i < 8; i++ ) {                    //copy new buffer to old
182       old_buf[ i ] = buf[ i ];
183     }
184 }
185 /* compare byte against bytes in old buffer */
186 bool buf_compare( byte data )
187 {
188  char i;
189  for( i = 2; i < 8; i++ ) {
190    if( old_buf[ i ] == data ) {
191      returntrue );
192    }
193  }
194  returnfalse );
195 }
196  
197 /* HID to ASCII converter. Takes HID keyboard scancode, returns ASCII code */
198 byte HIDtoA( byte HIDbyte, byte mod )
199 {
200   /* upper row of the keyboard, numbers and special symbols */
201   if( HIDbyte >= 0x1e && HIDbyte <= 0x27 ) {
202     if(( mod & SHIFT ) || numLock ) {    //shift key pressed
203       switch( HIDbyte ) {
204         case BANG:  return( 0x21 );
205         case AT:    return( 0x40 );
206         case POUND: return( 0x23 );
207         case DOLLAR: return( 0x24 );
208         case PERCENT: return( 0x25 );
209         case CAP: return( 0x5e );
210         case AND: return( 0x26 );
211         case STAR: return( 0x2a );
212         case OPENBKT: return( 0x28 );
213         case CLOSEBKT: return( 0x29 );
214       }//switch( HIDbyte...
215     }
216     else {                  //numbers
217       if( HIDbyte == 0x27 ) {  //zero
218         return( 0x30 );
219       }
220       else {
221         return( HIDbyte + 0x13 );
222       }
223     }//numbers
224   }//if( HIDbyte >= 0x1e && HIDbyte <= 0x27
225   /**/
226   /* number pad. Arrows are not supported */
227   if(( HIDbyte >= 0x59 && HIDbyte <= 0x61 ) &&
228                    ( numLock == true )) {  // numbers 1-9
229     return( HIDbyte - 0x28 );
230   }
231   if(( HIDbyte == 0x62 ) && ( numLock == true )) {  //zero
232     return( 0x30 );
233   }
234   /* Letters a-z */
235   if( HIDbyte >= 0x04 && HIDbyte <= 0x1d ) {
236     if((( capsLock == true ) && ( mod & SHIFT ) == 0 )
237           || (( capsLock == false ) && ( mod & SHIFT ))) { 
238                      //upper case
239       return( HIDbyte + 0x3d );
240     }
241     else {  //lower case
242       return( HIDbyte + 0x5d );
243     }
244   }//if( HIDbyte >= 0x04 && HIDbyte <= 0x1d...
245   /* Other special symbols */
246   if( HIDbyte >= 0x2c && HIDbyte <= 0x38 ) {
247     switch( HIDbyte ) {
248       case SPACE: return( 0x20 );
249       case HYPHEN:
250         if(( mod & SHIFT ) == false ) {
251          return( 0x2d );
252         }
253         else {
254           return( 0x5f );
255         }
256       case EQUAL:
257        if(( mod & SHIFT ) == false ) {
258         return( 0x3d );
259        }
260        else {
261         return( 0x2b );
262        }
263        case SQBKTOPEN:
264          if(( mod & SHIFT ) == false ) {
265           return( 0x5b );
266          }
267          else {
268           return( 0x7b );
269          }
270        case SQBKTCLOSE:
271          if(( mod & SHIFT ) == false ) {
272           return( 0x5d );
273          }
274          else {
275           return( 0x7d );
276          }
277        case BACKSLASH:
278          if(( mod & SHIFT ) == false ) {
279            return( 0x5c );
280          }
281          else {
282            return( 0x7c );
283          }
284        case SEMICOLON:
285          if(( mod & SHIFT ) == false ) {
286            return( 0x3b );
287          }
288          else {
289            return( 0x3a );
290          }
291       case INVCOMMA:
292         if(( mod & SHIFT ) == false ) {
293           return( 0x27 );
294         }
295         else {
296           return( 0x22 );
297         }
298       case TILDE: 
299         if(( mod & SHIFT ) == false ) {
300           return( 0x60 );
301         }
302         else {
303           return( 0x7e );
304         }
305       case COMMA:  
306         if(( mod & SHIFT ) == false ) {
307           return( 0x2c );
308         }
309         else {
310           return( 0x3c );
311         }
312       case PERIOD:
313         if(( mod & SHIFT ) == false ) {
314           return( 0x2e );
315         }
316         else {
317           return( 0x3e );
318         }
319       case FRONTSLASH:
320         if(( mod & SHIFT ) == false ) {
321           return( 0x2f );
322         }
323         else {
324           return( 0x3f );
325         }
326       default:
327         break;
328     }//switch( HIDbyte..
329   }//if( HIDbye >= 0x2d && HIDbyte <= 0x38..
330   return( 0 );
331 }

实验依然使用上一次的USB小键盘。上面的按键分布如下:

usbskb1

关于键值的介绍可以在【参考1】找到

NumLock OFF的情况下,各输出键值:

usbskb2
*输出三次62,相当于输出3个0

NumLock ON的情况下,各输出键值:
usbskb3
*输出三次62外加一个53

运行结果

kbr

本文完整代码下载 LCDkbd

参考:
1. https://github.com/felis/USB_Host_Shield/tree/master/examples/descriptor_parser USB_Host_Shield/examples/LCDkbd/ 本文原始代码
2. http://www.quadibloc.com/comp/scan.htm