|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
1 d5 Y6 W+ `6 |) u7 W6 x
' U# v# ~& P5 I- r扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
4 b) Y- j" n+ d; t9 h% @6 c+ K) u# @& I' z6 R8 v7 _
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:. ?* {5 n% ^! V
; C7 C8 P9 G a$ s8 v
% E: \7 Q7 |" j6 \* Mconst char hid_keymap_qwerty[14][8]={
7 [+ n% c$ F! y! }7 Y& T; j7 @ {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},0 s, r' g3 E+ s/ V
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
8 s! L% N& U+ }3 ? {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},, s8 q" \" m, e+ b n' Q
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},- f" |) }/ |3 \4 }. }5 N
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},3 P% e6 T! X4 D* V4 a( \8 U
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},2 P; `5 E" C( ]4 q
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
7 G8 @% a! w8 w; ?% | {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
9 s( J, J6 Y/ m6 a; }8 u {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
* _" W( s& |4 `! N" B {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},* i! P+ e; x& G
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
% m5 M8 i; F c5 a+ q% R+ L {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},- I* N4 L( m7 s
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
; T" i2 x& B$ p4 C2 g3 l0 l+ a {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
, C5 R4 u9 h& q$ |2 r0 A};5 M6 o( S8 i( a3 ]2 S
8 q# v/ u( u* Y7 j# S& u
, z: T: Y3 z/ m: D; _, W9 pconst char hid_keymap_dvorak[14][8]={
+ j. c5 j% q$ p% G {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
3 C4 y& x% U0 J- t4 |3 n0 q {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},, C; K; ?" A" v: o
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
) \" ?6 t) \* N B. G$ ~8 O P {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},9 I/ w, R" U. x; i% Y! O
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
3 k5 Y# R5 r9 E* P" Z {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
' h4 L8 b( @! X/ Y+ B# }% y {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},. K+ |; l U; X8 S
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
2 P% l' d4 { \6 C0 g9 z; Q( j% X5 n( c {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},7 m% w: ~* S% L
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
+ q2 r7 d" `5 `$ m7 p {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},* O: s* k( }! w/ p7 C- X# T
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},) H4 T! E5 T$ u$ Z7 w
{HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},4 j# g& I% M- x) c" r( T' n8 T
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}8 y; S; B! l: Y Z
};& i' K: V. {% V; E" ]4 m
+ N1 C. X2 h3 Z7 g
8 o! b1 |' C8 S. I上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。# e7 U0 _) u4 S! |
- h7 t3 C1 s c/ m* rHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:: U# Q' {" z1 l8 r# B
* j( B5 }3 n, N+ s) p- R) yvoid update_key_matrix(char row, char col, char onoff)) V' [' B2 F& v. e
{7 G! [0 W/ m& q6 O9 z6 E6 i
static uint16_t hid_report[4]={0,0,0,0};
" ~. U- b9 Z6 v static char (*hid_keymap)[8]=hid_keymap_dvorak;
7 K8 u$ J) `6 E6 Z+ W( V: j& A( f: u; o
$ N" |+ d1 b0 q) ^# n0 H+ X
unsigned char key=hid_keymap[row][col];. P2 y; N9 @! Q. i( m3 X" }
unsigned char *report =(unsigned char *)hid_report;
2 w1 c N- G/ M4 `3 y( _& H- g) }. f char i;
4 I" g0 k" _. ^: ^0 n
9 f6 S% e% r7 L; \
4 G# ^' Z N* D c if(key==HK_MODE)
$ b; A, s V' P8 H% X {3 s, O. k/ z. N( s
if(!onoff)' e: q5 G8 ~0 x8 X: o! b- M, J: ]; H
{$ v; z5 F6 D3 e- U& V) b
if(hid_keymap==hid_keymap_dvorak)1 M% V. e7 `- P1 S" a' x
{
, U: k& |8 X5 p hid_keymap=hid_keymap_qwerty;
* y4 ~: d2 N( h8 _( k. c GPIOB->BSRR = (1<<2);/ r3 U$ a2 X* ^6 K7 ~; |# u
}0 t0 \) k) }- T& o' N2 ]+ U4 N" x5 h
else' u8 F; V. k |' S S% u
{) z. s2 k" N5 p
hid_keymap=hid_keymap_dvorak;
1 y# ~. \: }; b0 ^6 x& K GPIOB->BRR = (1<<2);
" ]6 r, F- E* k7 ^$ g; s }1 h* p3 X. Y" d5 c; i9 Z# t9 a$ c: e
}
7 l9 T6 S2 L- q return;
( x; _3 J( r2 a- ^ {3 @ }4 Y3 i( ^# C( Y+ y1 D8 B
' U* _% n5 }, H1 y
8 l1 m5 @8 i# l4 M$ H( P if(key>=0x80) // Alt, Ctrl, Shift" C; b+ P8 O0 `6 {- ]4 f! `4 ^ P
{" U/ L1 ?, p& w( Q* I+ |
uint8_t bitset = 1<<(key&7);
( L6 n1 E. u2 `7 j2 ?2 m5 | if(onoff) // non-zero is key up$ B8 \ \. _6 B: i4 c
report[0] &= (~bitset); i4 @1 G5 B# Y% ^2 T
else
; y0 @9 F8 c" H2 f& Y) n1 ^) K report[0] |= bitset;6 I- A3 K) @ U D* Q, L, T$ o7 O
}
/ [. C# x H" l! S+ \- \' a else3 `8 o5 k, Y; E% j+ U
{
' ?) t( l& e8 n if(onoff) // non-zero is key up/ G0 `0 r: {3 I7 T
{
) [8 C- q& ~& l( G: f% f for(i=2;i<8;i++)
! l% H+ E% Q+ {5 Y {
' |: ?8 u0 B H1 b7 C, y if(report==key)" M3 b( k5 d4 a# U, Y6 J K2 t. J
{6 ^0 L. Q: _5 Z6 J
report=0;6 `+ v8 k7 l8 A
break;" ~% x9 p& u5 @% ~) W6 ?2 s6 \
}! U$ U/ G: j+ [" u( @
}( c; a( m2 T: H$ r& f T
}
) }7 \; U; m! q/ h* R1 P/ A else7 y7 T: Q; ^0 v5 H, j* g
{
( }0 P& D; q) [; ] for(i=2;i<8;i++)3 y5 p: H4 j/ Z
{
: G- t) ^' x2 R$ K5 Q/ k( G- m \ if(report==key)
! ^0 O, J) T: W/ U; K# I" ` break;$ S! R# b5 Q0 Y9 z& o/ _4 _* i) e
if(report==0)1 V2 q1 X1 N. O1 L6 |
{0 \! |3 C& |9 A1 S/ _7 D1 i% P4 y
report=key;+ f4 v% a! L5 a0 i1 Q' e
break;7 ?+ Q, {: G {+ r. T2 J
}
1 n, K: L. a0 y/ Z* {1 i }
7 M7 I$ c/ K$ L' v) c4 B }
1 `, w7 w) B! S8 K4 v! B8 ] }
2 B" a3 E/ i9 o/ L; x! X; L for(i=0;i<4;i++) b0 a. H9 q% m; Y1 O
USB_PMA[192+i]=hid_report;
3 e {0 r& ^8 s, {. \$ v1 @# A USB_PMA[5]=8; //COUNT1_TX
- Q) N# g. D. L0 u3 J if(ep1_wait==0)
- b o* y" A) W6 Z: `! P {- l! B( h; M& D2 p- D
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;; S; n& f0 p; _! B. J
ep1_wait=1;( ]* T; e$ b# {9 ?: P
}
. g9 E; s" n, n3 X3 o}4 ^3 a6 S* t' p( K6 B% H5 s
! h( H r; K% K& Q6 C0 A1 ~: K; Q2 D/ n% e
完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。2 K3 S4 A4 a) H
keyboard.zip
(8.7 KB, 下载次数: 6346)
. M8 {0 t e& [& y' U$ M2 {. L/ ?& B7 F( C
* y) j# _* _8 }$ O* }
5 Q/ ]1 p) I" w0 M3 h5 g
* d& t( T5 v! ` |
|