|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 : _6 F, s; P% X$ x( T
" n/ v# F) p$ O. ~
扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。6 z. L1 B! A5 T/ U! }& h9 }' L9 H
, x$ s/ c! d/ j+ `要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:9 L* Q; ?) O! C) Q, J5 _
8 Y' @8 j/ O$ l' |
& L* p# A) @& Lconst char hid_keymap_qwerty[14][8]={
/ U' {2 x" A ?% U# Y( P* Y {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},2 o2 S/ [& y/ z- J9 B# M
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},2 i+ w! w3 A! o. W8 k# q
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},
4 e" O$ M$ s4 F' a1 n {HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
v% U# N* J$ {# _& f3 P; h5 l7 @ {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},# q% V* x. |# o& M
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},4 I4 P) D# |# P d d/ d4 [
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
' X+ U( l! y; u0 R0 `2 f {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
3 B4 s3 B, y6 X* a2 u0 T {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
. `) U b& X# c; N7 a3 N {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
" X, ^6 q$ r3 t- l0 a5 P4 ^ _ {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},$ B9 `3 D9 X" x
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
0 |% q9 y) F; T/ V+ P7 n7 X# _ {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
* T) s( t/ A8 k) k; ~% K) ~ {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}$ m: e4 I! n" y! e5 L y$ C3 E
};! ^) h+ ?, B/ K9 E+ d7 _4 P( [. s
" X$ D+ S! A/ A. T7 V9 Q9 O+ ]
* ^& V9 n) ~! M2 i% X M+ |. Gconst char hid_keymap_dvorak[14][8]={+ k7 K" G9 G5 S- Z5 o$ Z
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc}," {/ V# l8 l0 H3 ]
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
/ S; M" U6 ]+ @2 {1 {. z4 U {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},3 K) e4 `0 J$ R9 S3 F$ C5 h2 `+ v5 |* Y3 ?
{HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
# @0 M! ]9 t8 B6 X' E {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},4 H( p3 r4 _+ l! V- N! t
{HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
9 K% g3 }/ J) v: n) d( I {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},( `- w+ j3 H& F. m
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
* R% M& m8 I% d+ Z* t7 ^6 [ {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
. v4 X8 M' R" M, U7 t" D8 t {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},) a) G$ v$ k/ ^6 [
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},+ F# N4 d/ h& i) g% t( y& r$ W
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
, z/ V0 F' d: O5 ~9 h' { {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7}, t; [0 O( v' o0 _8 Y+ ]5 a
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}& l6 |2 r# Z& C: }# a1 C: A
};' }7 [+ b* {7 @) C* Z0 Y
9 v6 h9 @8 j. i1 {, ~
5 W! p1 N, ~) o/ H. y
上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
2 b: l5 F, L3 l O u* v% M
+ N: d( m5 t, B4 C9 F8 P% S5 KHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
4 G% \# a: z3 S
3 a, r0 K$ o" \+ ^ v8 _% i Evoid update_key_matrix(char row, char col, char onoff)
[0 ~. I3 r' Y# e: I+ T" L5 `8 O{
* ~# e% d" v& Y8 f static uint16_t hid_report[4]={0,0,0,0};
! c% }3 C( h* `! V2 l% ^ static char (*hid_keymap)[8]=hid_keymap_dvorak;
! f8 W& G- ~; y4 H' \8 b4 q
. X: a& Y6 X/ C1 d" \2 g9 ?0 Z5 b1 T4 P- f- Q% m0 [
unsigned char key=hid_keymap[row][col];9 B9 y6 u! H' \
unsigned char *report =(unsigned char *)hid_report;+ u2 d6 i& |. K' E" j
char i;
\. p+ r1 c U: Q- q- ^9 e( U \: T: B! p
8 T, o3 F/ A9 S! J1 `: m
if(key==HK_MODE)
7 E; n3 w n! b- v7 j7 ?' t7 `8 N' L {
1 U5 U( n. N4 ?0 r3 r if(!onoff)
8 B+ r! G" n8 _% x5 D9 D: q. k. c( l {
# [1 ?7 A# l' g if(hid_keymap==hid_keymap_dvorak)
0 P$ v7 u( v! O; |9 I {: ]" N4 V W7 e/ s8 r3 p& A4 I5 J
hid_keymap=hid_keymap_qwerty;9 X8 O) G' a& u$ ~
GPIOB->BSRR = (1<<2);2 \+ i' y1 ` l2 E/ Z( B. S% m
}! u) `3 }; W% N3 D: A1 O
else6 \5 d$ H& d V0 V9 a: k d" E e
{! f% d8 L' m7 F, u/ |4 Q C
hid_keymap=hid_keymap_dvorak;
; d/ C% c+ D5 X; t GPIOB->BRR = (1<<2);
$ ~1 i8 h- \' c! \( U k }) o1 ^: n7 D4 M+ r: w5 u
}# e `1 ^/ u% V C6 q7 l. T# y
return;; @) f* S+ M$ k. @' X- {4 x
}
) t* X/ T/ c2 q* `* z* v: [) k7 a$ h$ H- }+ Z
7 V+ L3 [6 h/ L+ u3 Z5 h! K. m. o if(key>=0x80) // Alt, Ctrl, Shift b* J2 E& T+ n/ \4 @# K) q! U7 V" X
{3 Y8 P. j s) r) f
uint8_t bitset = 1<<(key&7);
$ m: Q) O1 i( V& `% _ if(onoff) // non-zero is key up" l$ S1 V* ~1 W! d, g( q6 }
report[0] &= (~bitset);+ |9 S3 s: ~( t8 y6 U2 a
else
- W* \7 T# h* s `5 X( _# R report[0] |= bitset;0 |- E) N4 s4 F g7 a
}( L+ w# F5 Y9 P; D1 ?! [5 T
else# x$ R) p) `! b n, p7 S7 n' R
{0 N& B* b% N; v& Q# J/ y* u
if(onoff) // non-zero is key up+ E6 C+ A2 n3 t1 P9 e, n7 Z
{
6 v) V, }& D' u for(i=2;i<8;i++)) V" ^) E5 D: Y$ O
{
$ A0 h- c. t4 Z9 Y! l& @ if(report==key)& V# x K8 A# z
{
3 } k: p2 @/ Y# l3 E report=0;
& o( b( x: F0 {$ ?3 I break;
' J8 k# a/ `- A2 B+ X' l }
+ q; a# ^+ V' C' q }
2 V# m6 L% X2 F1 C# b. A }( @* V! k3 s5 X" ~* C- K) d# V
else; P' m$ |3 D) H! U: x- a
{
0 P2 M3 A3 {( b4 M. ^# m, V for(i=2;i<8;i++)
! ` w2 _4 U* {% J* F {
/ X L7 y# U5 K if(report==key)
2 g$ {# w" T/ p6 E" j+ K( y break;% q& B d9 l) y
if(report==0)
6 k# i! ~! F: M* X( b; ?6 v. ] {8 b1 ]" i# ~: u4 P# f! x4 r0 Z
report=key;
0 s4 ]+ V/ B7 M$ c+ c4 ?# o6 `6 L# x* F break;7 ~- T' y0 K+ l' H5 l
}
# w- X* ~- _$ x4 o0 O. I }, A6 s3 z V" O' C8 b& k
}0 D7 @1 b- M$ X( e- h5 ^5 [
}& o3 y6 S% _2 Z5 t
for(i=0;i<4;i++)' b% W4 l8 y' t
USB_PMA[192+i]=hid_report;
. a- w) o& c0 f. \% u USB_PMA[5]=8; //COUNT1_TX
& i: V2 S4 m# {! x! W1 u7 f& _ if(ep1_wait==0)) B- l4 r! ?2 V3 j& i
{6 ?" L5 F% a, Y
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
. D: o1 O1 i) T! c8 i* M1 ?. W ep1_wait=1;: L/ n' b% E5 T% ]
}0 J! Q% h4 B7 a( ^* K
}- a6 s; e6 I& D; l- S, \% f! }7 r
8 I, ~# ]9 }8 x0 L. l
5 S- i* ^( n) [" |完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。
& v8 m+ ~) o2 E
keyboard.zip
(8.7 KB, 下载次数: 6483)
- w$ ], I% l2 B* t; r, Q, e! t+ q6 ^+ {; l! n
6 @) s* I/ v+ s: n/ ?
8 ~/ K1 O2 N5 w4 t8 j/ P* A% U, j# U8 N* Y' q# v
|
|