|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 ' L0 _2 K. r4 _, s) ?: q" k
8 q; {7 m: i8 a( U2 y扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。; c6 J- H, B+ {1 C2 @
' R2 ?0 y6 W* |. c0 B* X/ f- F要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:
2 {; O- X( j! e d) j7 d# | o! z1 ]$ J. K3 a
. U0 M- G. I; K( l2 W8 T5 ?const char hid_keymap_qwerty[14][8]={
( z1 V% T) H" @: e; m- f' G {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},2 s7 Y" I- i: V
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},% S0 O1 A: y1 T% r1 k( W
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},1 |4 q5 n$ b% K- u B
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
/ \% ?0 F+ Y, ^( {& z. S$ A {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
- P1 U; V. s2 I {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},
; _/ J: ?% R2 u {HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},9 H7 W; k9 v% v3 Q, u }8 J
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
$ D8 `+ p: @- i* {# v {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
6 P% E( q1 W+ K: P3 Y% u6 e' { {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},6 D+ p: u7 S, m3 W, R
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
% v* q) ^+ e7 l, q# F3 \' S [, G {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},0 F/ w$ J' b- s4 ?: ]- u
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
) h9 D+ [; ?9 I) t {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}3 x# |7 m3 U9 R4 ^8 ^; y, F
};7 e( Y1 B" c, G1 X! ]6 t
8 s; h; c5 F8 p$ g, v" L- p
: X. A8 J& _4 Xconst char hid_keymap_dvorak[14][8]={
9 N' N/ w9 a% L$ p1 u1 S {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},4 d6 N8 C0 i1 c
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},, S# m1 \6 ~. E+ u' L2 a/ o5 f( g
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},6 @8 m3 ]5 L$ n6 }
{HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
) u9 x' R. B2 b( }2 I {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},7 Q- ]5 x% t) R p& @) {$ I
{HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},, a, V2 v% g. k: x' m
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},8 u9 M) ^ l* u: ]% n/ u
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
- Q, u0 m' k2 J6 ~0 h/ r4 l) Z {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},8 x* P ?% F) b7 U
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},# t% j& h' \' V) |7 K0 }+ E
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE}," V+ N8 w7 d7 N8 ^3 y
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
4 J* m' I% @8 E8 x; e+ L+ R4 E {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},: U9 l1 z. s' p6 m+ w
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
+ [+ n, _3 D6 d: y( _; @; E6 J9 T};' l2 r, L. F4 Z3 F) G
3 ^' X6 H5 F* t' ?
5 P% J$ j# X4 z2 N- X上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
. y; e1 U% o) ?% q9 M+ U9 ?6 b8 A% P* Q
HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
3 b" C( B/ U4 m, T/ c. ~$ b5 {+ P1 v* i9 @+ Z9 ^
void update_key_matrix(char row, char col, char onoff)) H8 ] F( ~9 w2 L7 k/ y; F
{
" k* @( \2 u. l& r8 X static uint16_t hid_report[4]={0,0,0,0};
0 }) }2 S* N2 [! |3 @ static char (*hid_keymap)[8]=hid_keymap_dvorak;! [6 G$ p3 H; S- B0 [6 s; }
, D3 s- g7 ~% O+ ?; L/ k
; W: y# w2 K' J- c& K& @( J unsigned char key=hid_keymap[row][col];5 ^0 H0 W1 z+ F! J2 l q% g) R
unsigned char *report =(unsigned char *)hid_report;
5 E' G9 N) l' B. C* W char i;: E& z1 Z$ f1 ?3 s6 p" X* H. F
, O+ f: D' H$ k3 i5 o8 j0 G( `* {4 @% W$ n
if(key==HK_MODE), t7 x% B5 D* y W
{
( L, S" ?0 z' V0 }$ ?) b if(!onoff): D. B2 }" q, c
{
: o) L x( }- r- @' _3 ?* n if(hid_keymap==hid_keymap_dvorak)
- k0 l4 L. G6 |' R! i {& l4 l0 I/ v$ K
hid_keymap=hid_keymap_qwerty;
5 J5 t- H; \0 R: |( I1 v GPIOB->BSRR = (1<<2);
9 _. K' P" }% o9 A% Y6 p, C! G2 z }' I$ a1 L4 ]6 J' L s+ E
else
0 O W; e& R4 [8 L6 a {
! {8 @, H. K4 Q5 m! N hid_keymap=hid_keymap_dvorak;, j- c- A: B3 P4 j' H1 R5 J4 ]: ?3 x
GPIOB->BRR = (1<<2);7 U- q2 A3 S/ t& Q) _* w
}
5 G8 y/ ]2 n E5 h4 M) u) ^8 d( x% o }
) m5 L( |. E0 F6 v: t7 k return;
8 O6 Q# [) o9 `5 s: V% g }
; T, j0 Z) r% o* t0 ?3 ~# Z
' E3 J9 C" l5 ^% r4 q) N, R. m
, s6 W. K5 R# |7 }8 r if(key>=0x80) // Alt, Ctrl, Shift9 [$ H& r: {( k" S
{
+ T2 W% h; Z2 X% @0 \: J uint8_t bitset = 1<<(key&7);
8 r/ F1 z9 [2 L$ Y! U1 {* u; x$ [ if(onoff) // non-zero is key up
& `4 x6 C' a3 o( M7 O report[0] &= (~bitset);- I8 W; Q8 j' Q: \: e% x) Z
else
0 a) G0 O8 g) [$ B# ` report[0] |= bitset;- C2 |' v+ A" w8 {) L
}
' T- H) o. e0 `5 ^ C( s else3 V! r. m$ R3 J q. m2 K
{+ m) H6 H( J& t
if(onoff) // non-zero is key up2 Q0 n6 `( I) K7 t
{: L, C6 L: u) R% G5 z% S
for(i=2;i<8;i++)
% m9 h! U; [2 }4 X8 |9 ]7 d2 P, o {" ~" Q( y/ ^0 R! Q1 Z
if(report==key)
. `( `6 t2 H0 D' i9 z4 W5 P! h {: {% V, |' f# q
report=0;
0 j/ Y* q7 j# t* I break;( L( N+ r% R2 [* }' ], b
}( D7 ^) Q" H+ y; H% b- P
}# i7 D. O. g; j. C
}, [4 \6 F& U" l" p: e* u7 g
else
! U! L1 I1 ^1 p5 a' y {
' Q& e- ^0 Y4 n6 ?7 l+ b- d for(i=2;i<8;i++)- T3 z! P3 h5 B( a6 t- \; p) I$ N
{
1 ?. }1 F) d; H: a7 { if(report==key): [9 x2 G# {+ {3 u$ W! n
break;3 Q7 ~6 W' e/ W# g$ i
if(report==0)* C7 p1 ~* p) Q3 \
{, G/ L" G6 W# s7 @; v& W
report=key;
4 P) m; T; Q5 B9 o4 g1 ~% Y break;
! w$ ^+ S5 k1 f; ]2 ] }9 B" Y; J' J( s' f) V. @
}. {$ g' T3 V' G5 ~. k7 j
}
6 t H* i, K. M& k2 z; a% p6 c }. [4 y: t& f% L' c/ Y4 G$ J: i g
for(i=0;i<4;i++)6 D6 `1 V4 n2 J+ K; t: D8 k, t
USB_PMA[192+i]=hid_report;/ J/ z1 ?; K/ _; z, Q* ^
USB_PMA[5]=8; //COUNT1_TX# ^; s) c3 |& Z
if(ep1_wait==0)% @6 j w# t+ q: S8 B! `! [% I) M1 Y: W
{
9 u* V! H6 N, F) [ USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;8 ]4 [0 M! O3 z+ E4 ?
ep1_wait=1;
+ M t' T) Q0 r; ^ G& E }% U/ f0 Q6 Z5 M! l8 r
}( `+ ~4 a' F, `& l
* t# ]% l! H4 K% w! @ h+ l3 t
! Q8 e( Z# w% p2 c" P% @" t2 p完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。) w0 a& O9 I& h, O; s' }( D. j
keyboard.zip
(8.7 KB, 下载次数: 6653)
2 m4 s9 R( R1 t/ b+ Z" j3 K& |, D2 F. v! q: ~ ^! A
( r8 |, J, h% H& i% X
9 ~+ T% r: V/ W+ X( e
4 F9 q9 v% H, C9 C! B1 V$ J
|
|