|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 3 I1 Z6 z& A7 M6 E
/ _. {; G" X; j& U/ m扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。/ J; W8 w8 ]2 m, F( Z. c7 I% r, ~) z
0 W( P8 T* W8 R6 p& k% s
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:8 P( H7 F* p1 `4 n9 |
: k2 i2 E9 G" ^9 q4 `$ o1 g# O, z' z3 h4 p) v4 R: j" I
const char hid_keymap_qwerty[14][8]={ q' O1 Z5 V, E* \
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},8 C# O+ j' s4 s+ |! j
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
5 T' N8 |; d" Z: J9 `' M {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},
: b6 p0 V% l+ k2 V# F {HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},- {" B0 ]* H E, B1 Y# r! @
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},- N& v% [: z+ Z* v h7 p7 I5 F: i
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},
3 P0 W! P& v/ \+ O% `! C3 r% f {HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
3 i: ~! |1 ~5 a' o% d% g( Z {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
( D& ^7 v0 P0 j+ X B. c3 c! } {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
. h" p! s4 Z1 r& k* g0 r8 `# [& K {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
' g/ G% C0 T8 o {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
( m2 U ]2 G8 S {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},- B" ]1 Z6 e% N
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
; e5 M6 }( S5 p$ K; z9 { {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}1 k" p% r: g9 x' R& r5 y9 c
};7 s4 K. c+ C U4 ~
, s! G! F# L' j8 s# \
2 v- W( K6 g7 S% h6 O; _: M2 A
const char hid_keymap_dvorak[14][8]={8 w: Z9 `/ l1 j5 s% [) ^4 Z
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},, u j% i* w1 x' h# F" U6 ~- w' t
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
4 r& r1 d! C1 e% g; t/ S. ` {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},' ?! v# E' Q0 t. n( I6 M! I
{HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},; N7 j( n0 N T; h1 b8 B; ]' E
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},8 x% D3 ]$ K b. I
{HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},6 V9 h3 Y8 a; }" ~
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},' A4 W% s3 {" ]2 E" a
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
4 E: \! | W+ X7 k2 ]" @: U/ m% Z {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
2 U4 F/ j M( p& k; i {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},6 J: A& R: z1 N5 c, |% b. A
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
3 q S2 [! W& P. L, ~ {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},& A" u) j8 K. J% {
{HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},) o7 @: E3 ?( t6 }
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
( A2 S: S& R1 w" ^$ X0 Y& C/ d};" c+ s. e- {' I6 n3 H- |. ?
7 }1 ?) w. b. ]! B$ q3 l; H- Z9 a8 l7 B: i& N3 U, u5 |% ?
上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
' i4 g" Y$ r! ^' q: r- A& b ?% n# t( A7 f
HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
% t4 C# R3 H# m9 c6 i: j! e( V; R0 d d- W( x) `: E4 F
void update_key_matrix(char row, char col, char onoff). B3 ^, O. H$ K* d% p: V
{7 Q, }: W* l. ~! L2 v1 V1 E
static uint16_t hid_report[4]={0,0,0,0};
- u0 t# }! K! ^) { static char (*hid_keymap)[8]=hid_keymap_dvorak;& Y, C2 R9 n5 M: Y9 B, b% P: t0 b
' f, Q @7 d1 s: _
, \: a/ e2 j9 ]$ C; z' Q
unsigned char key=hid_keymap[row][col];5 V4 Q. n+ a" ?4 B
unsigned char *report =(unsigned char *)hid_report;
" J; C4 V! o& _ char i;. \, Z( k2 T# O+ E+ L
y8 j' l; T+ x
3 ]1 B( q: G8 c- w# W; z if(key==HK_MODE)
& [9 y9 l: _4 F& y {' g7 E8 Q1 U9 S5 A: r
if(!onoff)# D/ V3 i, _- b5 l! B5 ?: s
{5 k. e% _0 h$ j/ T' f7 e
if(hid_keymap==hid_keymap_dvorak)! v5 j$ Z! q& ? [' |* h& ^
{
8 y) G/ W, W$ r! X hid_keymap=hid_keymap_qwerty;: L+ `% V2 K3 ~+ v
GPIOB->BSRR = (1<<2);' X0 \. |4 t# [7 B8 } b
}( M! Z/ u2 j8 Z( @" I
else1 `% X. m v6 H6 y+ n! R& j
{
' W2 I8 ? k$ Q hid_keymap=hid_keymap_dvorak;+ J# Q& [* K( Q( }. R( V
GPIOB->BRR = (1<<2);2 F+ o) j7 A2 Z
}% @3 `5 {& i* }3 ?! I$ A! F
}6 s2 `- X; a& ]
return;
5 W% m3 b' x7 j$ e: D1 J, K }
# c1 ^& x; P n7 a* I1 I7 d: Q, Q" B E- z0 J
* X: ^6 M# r" g# j
if(key>=0x80) // Alt, Ctrl, Shift+ S) X' G2 I( k) F
{) }8 R" M" u+ Q8 o: W/ G/ y: Z4 O
uint8_t bitset = 1<<(key&7);! o$ }! S0 N- V- B4 q2 g
if(onoff) // non-zero is key up
: Q) ]$ t& p; w ~7 ~ report[0] &= (~bitset);
?" J2 G, G# i: o else b4 U% L9 V* k( E
report[0] |= bitset;
[+ m& o, n U8 `& G }5 }3 M6 B9 f" {6 m d: m
else9 Z2 M, F/ B1 y, ?* A
{6 B- N, ^; d( R5 j7 q$ z- r
if(onoff) // non-zero is key up" ^9 u' f# d: `" }( W+ [7 V' Q
{* M+ ]/ }1 F9 F! x9 T1 A
for(i=2;i<8;i++)
# H/ _5 G; i1 M) I4 d1 i {7 A K8 e6 G; R q3 L3 [* A
if(report==key)9 a3 x! J5 I' j9 x* ~
{
3 o! K7 t" E" x+ s! S, V report=0;; q' d2 ?2 y% E- n( `# P
break;
8 o+ N7 y+ ~) e+ F' a* `& @" L }1 O9 S. }6 o5 H" c& N; e
}( p2 d' i' v: [& T B! n
}
) A) M+ J+ @# |3 @) S else
2 q( w/ Z$ m! _% p {5 s* l+ L; M9 K9 o. J
for(i=2;i<8;i++)) e! Y! H. m4 ]/ U
{# E2 t' F! N# D5 r. r
if(report==key)
% Z( z0 r1 O; K break;
0 s, v e1 z) h if(report==0)
" j& Z# n1 \- g" c0 }' J3 U5 g {
0 @" ?( B( o6 B/ C$ ] {% i report=key;
Q- S; M$ F/ _ d/ ?& |& s) @1 N break;+ E- i9 H6 M" v* l0 l5 w
}9 q$ [2 D2 B, b3 j: U8 s
}: T6 e& S! A6 Q& a* y% ~
}6 F+ T9 M( W" d
}
4 d4 {/ L+ ^7 ^# u! Y c" I4 N for(i=0;i<4;i++) l- R" |" R0 l- G/ f0 d$ e
USB_PMA[192+i]=hid_report;
9 c4 I/ f, k( [* S2 V+ f Z0 s USB_PMA[5]=8; //COUNT1_TX
9 J) {9 K, x6 G& m/ E* |5 G6 K if(ep1_wait==0)) t4 X# h- t# V; j; U; L# ]9 U; z
{
5 n! {0 I U2 Q1 O' W& a, E- }) L USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;. i% _: e- J4 y! n) [ D
ep1_wait=1;4 S$ E* V9 O& r2 I5 b
}6 l* Q: U1 b, A6 T! q( c
}
2 z' C) w9 A/ P+ |- o" o2 S( Y- X: W& d, ~ H$ P
! S4 E# C) t- E$ M) E& M* R/ C完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。( U" A; t+ t1 t: r% e% G+ u/ W. R
keyboard.zip
(8.7 KB, 下载次数: 6346)
- ?0 F6 L, y$ ^- b8 ?
+ g: \& a5 O, ]; c! C' b" A, O5 ^
) A9 [2 A! s2 Q- F8 M
9 }5 O1 | e) u/ } n1 z8 Y* U% U- w# {' v0 S) l. o$ h5 n* b
|
|