|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 9 @- n9 {1 ~) O* c: P
5 ]# s/ r- b% p; y3 z$ ?扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。; y4 i- D* }# T1 V% B, y. h% @% n
5 J/ {% h4 p! o' j要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:0 i! S6 D$ N1 |* L' S3 n) p3 }
& c1 p* z0 M: n F. b% b- d
! H) g9 V3 l$ \2 w! tconst char hid_keymap_qwerty[14][8]={
: ^6 T S' p; f, O" r% k {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
' b+ r2 \* @+ L+ H9 t; ^4 \ {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
! Y+ e+ f& c3 |" K {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},
5 q- p3 U2 `+ u! y D2 Y# @ {HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},# [. z' [8 n1 n/ \. ~0 Q( e
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},: ~3 o, U. ]( S
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},4 o2 |7 q( J: N) t' L g# D9 w
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},& m2 ?, _. L5 Z Q" Q
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},4 E, i% T! W% ~" x" N* r$ M
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
( H Z2 T7 _5 l {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
+ A2 {4 S3 [9 Z6 J% O+ F( Z, ] {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
r! p" A1 ]4 r {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
9 o4 T$ t- U1 u: o {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
' {6 z2 q. q# S7 Q- e, \ {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
1 [/ j' c; S: L! b7 P) a+ p0 c3 y' y};
6 ]& i: F) r/ T2 a0 F' a/ h! f
% g& X d4 z5 l c1 O
& ~1 k; T0 k2 L0 X$ w! ]const char hid_keymap_dvorak[14][8]={1 c* l+ y$ c7 |: o7 Z
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc}, J* V2 E( f2 c. t0 t8 J
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
3 C- X, c2 X3 i {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
0 }3 ~( Z( ^, H {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
% S4 U3 ?; w6 V% }& s3 k. w( F {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
3 S( H9 L4 p& r {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
: I/ M& Y; R( O6 i; f- R2 @6 R {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},: C. O: D, B/ p! ^8 B
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},% D6 Z0 A2 Z" G) v) g
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
0 R: ]/ N7 f7 u: t0 W {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE}, l$ e% @7 \ {+ H
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},$ i1 B" ]: I g, g1 ]. H) Q' Y
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},/ c( ?# s, d9 M. E4 ?) n
{HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
% }2 Y1 s8 k ] {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
$ P' M+ s* [5 P};1 J* ?! p2 n/ m, W: l
8 N( o7 I) Z3 d" L4 m- |% }: |0 S4 q! D) e% z
上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
; j6 d0 t O3 m7 \8 ~! [' Y
7 Y3 O/ A7 L6 |! O2 HHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:* L! q5 b( s- G) |6 ^8 f4 ^! L2 |
5 @0 S' I" B' T+ z1 @: z' bvoid update_key_matrix(char row, char col, char onoff)
9 _, L& B7 l# M2 V3 V6 s) M{
( B- F7 |/ A( z) j static uint16_t hid_report[4]={0,0,0,0};
- J( l! a( G$ s1 Q* j) j static char (*hid_keymap)[8]=hid_keymap_dvorak;. u9 M- y$ v( U
) s% X z1 x9 S# v; l5 k
H3 ]- d" D( U8 y y/ J" X5 ~ unsigned char key=hid_keymap[row][col];
" Y* j7 t) _ u$ l X7 ]1 I. E unsigned char *report =(unsigned char *)hid_report;
+ O u6 |' I' S3 d9 |# `+ \/ R char i;
# Y! j: D) ~) b j0 J( z
T+ O: I/ `3 s3 {1 {0 d- q
$ O8 w% B) o/ U" x8 ]( c if(key==HK_MODE); S+ `% e: b' H3 D
{
3 X+ c9 ~5 E% | if(!onoff)
; x+ p$ u# m7 P* e( Y, s& H {
`; T" ^4 q* f* u* A if(hid_keymap==hid_keymap_dvorak). g! d% t7 M$ t' h( c. L- g$ G
{5 {5 l2 L7 G, G! G% z
hid_keymap=hid_keymap_qwerty;$ ^' v1 p, G4 \3 ]
GPIOB->BSRR = (1<<2);
7 v; S8 o* m' z5 p$ Q2 s }0 t6 V/ L3 m" U7 h+ j" T
else9 {! k" P2 d9 J$ {3 d. V, t7 c
{
; t# C7 V S+ t, ~% @ hid_keymap=hid_keymap_dvorak;
4 s3 e! ` k% G, W7 H8 k' d# C t* a GPIOB->BRR = (1<<2); n9 a/ }" }/ _, g8 y
}
+ E8 R4 J$ o! G5 U }; e5 B5 y# J& }- C7 G! W
return;% w0 S+ Q" A) H( T f
}
( L8 k2 K# G! `2 `& ~( l U, v2 _9 C2 W x* M( X8 x
( g% y, K. N% m
if(key>=0x80) // Alt, Ctrl, Shift4 U, B* ~/ a$ F5 ]2 `) H! z/ c
{
9 O2 r' {# e, P& U, \ uint8_t bitset = 1<<(key&7);/ ]* O6 \1 C% E) ~: W- N
if(onoff) // non-zero is key up
0 D4 A" ^. r9 a% w report[0] &= (~bitset);
4 x' ~7 T% X) @. F5 F; E/ D* Y: C else
$ e+ D& V$ R* q# o0 T" d }0 m report[0] |= bitset;
2 U$ M9 v9 R0 r( Y1 @3 O }5 _3 Q% W, F- [! O z! c$ b7 b
else
% v" ]5 C) ^- M; z! V+ W$ d5 g& ^" q {8 f' V `6 m; s: }; g" e
if(onoff) // non-zero is key up
2 ~9 V" z, ^- z; @0 k+ |% L4 } {( n% {( k! R" K% w
for(i=2;i<8;i++)% o: p+ j+ E4 P# h4 e
{. y" E f. C. J# w) i4 T8 j
if(report==key)
. [# Y! _. ?2 V0 X {
, d+ P% w6 k. i. W- s; G, } report=0;" |& p, ~4 A7 ?5 v
break; H) M3 t% W. q7 _# Y% q1 @5 T
}1 h1 O& ^0 a1 Y# n- K: C5 L
}
# a) s1 M. W1 U4 ]' I! _' g# a7 U$ s) C9 P }
2 o. ~7 m3 Z( z/ E3 x* v# { else# F0 Y* \7 ]2 g- R6 `# [( [
{" K% y. v* L6 v8 r1 C
for(i=2;i<8;i++)" A1 o5 _+ ~0 N* F
{% a) Q/ k/ M' L' f7 ^
if(report==key)
5 Q1 H. X( r2 k, K8 `3 g1 N break;
4 D# }) U, A* t4 \ if(report==0)' D, F# v" j# Y/ S% n+ R& z
{
- z! V4 s4 g& S0 e report=key;
: M2 a: D1 ^/ a, }2 K& h break;- m7 ^5 {; {) n/ E- S7 E
}
4 V/ C) @5 F- f! [% ~ }
# O. {2 T' R; y B1 s" o }, v( f" x6 y: n5 k0 h
}0 R' W/ n! t' j" K
for(i=0;i<4;i++)
! D! p- _ O5 D) u5 z" V/ ?8 H4 l USB_PMA[192+i]=hid_report;) \5 u7 h. n+ Z
USB_PMA[5]=8; //COUNT1_TX
* l! l1 c, d% z3 r! m; B if(ep1_wait==0)4 H: x9 v9 S7 Q& m; A
{
+ t7 `% I9 X3 _% r F* _ USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;7 n4 H" k9 d( {# V$ r
ep1_wait=1;
3 t7 M$ N; [1 B }( j g: |0 @) M9 i- l
}
) J0 @. E' _- L! D. v+ \5 u/ ]! J- Y( A% V3 T, P
% H/ ^5 L6 w- N+ q; O完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。' {1 w% L- c+ a3 L {9 t# m
keyboard.zip
(8.7 KB, 下载次数: 6653)
% Z, X0 H' F9 ?: X+ H. Z2 Z7 b* Q
1 p8 W- t0 j: v" V% l$ I
% Q( C5 b. r5 a8 a8 E) [. ? C
3 G9 Q5 }7 z, W' \4 l4 `5 d
" d) F+ O: D4 |# p4 } l, h |
|