下面是一个获得 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 |
return( true );
|
192 |
}
|
193 |
}
|
194 |
return( false );
|
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小键盘。上面的按键分布如下:
关于键值的介绍可以在【参考1】找到
NumLock OFF的情况下,各输出键值:
NumLock ON的情况下,各输出键值:
*输出三次62外加一个53
运行结果
本文完整代码下载 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