|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
" c6 M7 l; k. U2 C, X, N- g# L( Q
/ t+ r- g4 A6 S1 J扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。9 _7 F$ E$ ]) g N" \
3 {. j2 a5 i, \- H. ^
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:9 a- @% y! b6 O0 Q# E
( W. e' x3 K8 s7 p7 p0 M4 d
0 @! S1 I: O2 F2 _! s. gconst char hid_keymap_qwerty[14][8]={
* E: |) m# I$ V: S: E {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},, ?' P$ c; Z; W" z
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
/ t1 G3 d4 s- r, L7 j& H! ]2 ? {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6}, w4 k) _/ R) b, N
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
! E9 R8 ?& i z) O* X {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},! ^) Z5 t( W' m, z! `4 N* N: \6 W# f# ?
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},
# @' O6 V' o( N {HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
! v+ Y8 X6 H4 i M* x {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
: g; h4 ]7 x3 [6 Q {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
+ d: b7 X2 O) ^6 | {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},9 ]: h7 u3 l) |: y$ ^1 ~
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},) E+ _- s. w- ^) x1 F, S
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},4 p# D% ^% b( s) p& N. I
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
& ^1 w: X& L5 n. z1 b6 a2 \! b {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
. s9 Y k( r( v8 \% q};
$ d4 i! X' P3 h1 Y9 I
7 f: n t Z6 | e. {4 i) D8 Q, v9 k& n
const char hid_keymap_dvorak[14][8]={
" M; D8 l4 s- Y8 }0 R( v3 z, ` {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
8 c" j$ d/ Q3 c {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},8 N- T8 T1 h0 d3 E' G6 R, \
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},$ |+ X3 Y" H- B% u, o9 @" J! c
{HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5}, j6 S4 k9 ]' ?6 F, a
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
m0 g8 ~& g: ~, o: @; p {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
! d3 p% B( o- N* n {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},4 T) H" y9 X' {: B& C
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
) N! T% }; r' P" U6 m$ m3 h5 x {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
; S. x5 I: d5 B6 s" t5 Y) h {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},4 J, d! L6 k- [) R- \! O, i, O
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
) v6 w' x( g; F$ l( Q" r1 I {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},0 v- g/ ?% E7 `
{HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
2 z$ y g9 l" P m7 w% ~8 y {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
# B- J* z& C% N! R}; ?! M: \' d4 E& d) H
$ M/ r# Z5 V2 t1 Z( H# ]$ L" z$ N# k9 D
上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。1 m4 D8 c# h8 Z5 O( K* _
! m8 h; }# X8 W$ D9 t- J7 u
HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
' d" Q+ ?: \2 o! X( C9 U5 u7 p0 }7 E2 K
void update_key_matrix(char row, char col, char onoff)
7 o( @4 m2 k8 t% A{
0 j, T( e7 E! O' \( n. m static uint16_t hid_report[4]={0,0,0,0};4 A8 F/ t) K$ b1 _7 S9 x0 x' M+ k
static char (*hid_keymap)[8]=hid_keymap_dvorak;
; y4 P7 C- M+ K+ J, Y; M e5 m
3 W1 B( u% W! P5 J4 n( v/ Y+ e- I$ g
unsigned char key=hid_keymap[row][col];8 W, f2 s \% E% S+ L O* z# x
unsigned char *report =(unsigned char *)hid_report;
. o& b$ G! x9 R2 X2 L char i;. A( H5 s1 T2 `
8 {* j* |1 t+ D
5 `7 j- k' a% m3 _8 \7 D if(key==HK_MODE)+ K Q2 \2 Q7 W* E
{
$ R% S9 ^0 Y) d4 p3 z$ k if(!onoff)
# _$ L& _( N& c8 D& y$ u; m {/ H+ y6 g! g) P: g
if(hid_keymap==hid_keymap_dvorak)8 T4 V2 E0 O& ?6 p0 t
{. p1 L5 k1 ]6 {' U8 n' I
hid_keymap=hid_keymap_qwerty;, D, ^/ G$ e4 p* V
GPIOB->BSRR = (1<<2);5 N* T% ?" |+ @$ z. G" v: {( Y5 D+ p
}. `0 _ |' c2 }2 t% a4 n
else
5 b8 @; X: h3 i9 k0 q# V {. I# a) `2 R; @6 ^* O
hid_keymap=hid_keymap_dvorak;$ ^2 c5 I8 W U% a N& g% |
GPIOB->BRR = (1<<2);+ X4 f5 G( X% |6 ]
}
8 v6 R; F7 W% D6 { } w1 y) @4 x( D" C0 m2 f' n7 |
return;
# T. @% Y K3 C' P a: r }
5 }. D1 E8 u2 q3 I0 f8 f. L# k4 Z. q* q& D. _1 c
& F$ |) B m, ?7 t' p
if(key>=0x80) // Alt, Ctrl, Shift- `2 A+ v$ i1 O& |3 U! \) R
{
: h' B% s5 X- Z" }$ D uint8_t bitset = 1<<(key&7);
- X4 j/ t" M S! v if(onoff) // non-zero is key up
! J+ X9 V' L3 i# B, n/ V report[0] &= (~bitset);
: x/ R9 M/ H: k" g9 [: W0 u else8 [$ l | h! ]0 y+ n. }! y, w& ^$ V) i
report[0] |= bitset;( _/ T) N$ c9 ]( J
}
3 E- ]4 C* W% b D; u, V else
7 K& d8 \& P9 E {7 R8 D3 {1 T4 _
if(onoff) // non-zero is key up& ^3 C$ K- I( ~# K d0 B
{$ z% H$ ^( N- c9 Z7 `8 j
for(i=2;i<8;i++)1 k+ C: G" M) L- U
{
% W" ~8 a4 I! b( m* U if(report==key)" h; L2 Z8 t! z; A. I
{
6 l; J$ a4 p9 ]/ L9 h report=0;
( y, w% V* v% i0 \. c break;/ C- G$ ]( P) Q/ z4 h
}, Z3 i) x& n9 I3 J: a( y; F
}
0 v( z, V: p3 X4 b8 H7 h1 F6 U }
) e& A; T, j3 K. \/ ~ else8 }1 s9 {% t( [ u+ R( {" m+ r& U
{' X/ Q6 g. ~8 L0 s. W, w
for(i=2;i<8;i++)
* i' b4 L O/ _ {
1 k6 }. k' E6 _7 Z if(report==key)
' ~1 a, l- b' b- ?: ^1 R9 h break;: p1 L2 W; h5 x0 B
if(report==0)) Y% H, T+ p9 s, A6 Q
{
; r: `4 c5 v+ v7 _- _; [ report=key;
; N' D, p1 Z3 P* @5 b break;* o6 @8 q+ a5 L- f: k8 H3 a
} Z. ?) r3 m1 G4 z; G1 F8 Z
}
8 G( q4 c2 C7 t2 r9 s }$ J8 o6 f0 J2 Q' g; k, c
}$ }' K) ?, m$ [4 c
for(i=0;i<4;i++)
?$ [/ q1 n9 D; a& y X* t- N USB_PMA[192+i]=hid_report;- G: S. ?* e, {2 l* z! _( {
USB_PMA[5]=8; //COUNT1_TX; B* c' X9 [. K. @" i
if(ep1_wait==0)0 [' d$ E3 b% ]: q6 M9 {
{: Z( g0 o7 E0 L3 g
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
# d' r( Z0 E. V$ X! @4 j1 g ep1_wait=1;
) Z: \$ u0 Q: s( F% _6 W- @# u* L+ E8 \ }
9 x$ I; _3 g" U- i8 D4 J c7 u}
' @; c% A8 R" ]; v' s1 K s$ N$ b6 y0 ~, _/ ~" \
. e" p/ e% z( h. d完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。
: F4 t; w4 P( E- W" h2 V S
keyboard.zip
(8.7 KB, 下载次数: 6581)
4 `; M/ _8 h# t# B4 l' a* C/ z
6 ^8 G! a. \2 a/ e2 a2 L
" y. [! F$ W# V) L5 C+ Y5 _! a
1 O; q& `# Y) O" [
. K% s9 E2 V. H% I8 Z
|
|