|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
0 P" [7 X/ v" ^0 x6 T
{& {5 m/ p! X9 \& O扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
0 m) T3 ~" Q- l$ H. V
8 b1 O; R8 V0 m5 A要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:
: [: z( ^' S3 g* Y
; V8 W* N; ]0 X; N1 K( L' N- \% E" O' h; T
const char hid_keymap_qwerty[14][8]={
( s& X+ Z4 u# F+ ?. ~9 ^: H {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
2 y3 i( g1 k+ r) f- {4 [1 T( Z. z {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
6 c: G4 z$ o- ]; \( l! F! H {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},2 Y/ K. W1 [+ s0 o( J4 T
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},. q: K* u, q1 B# b5 I' A
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
& Y4 Y2 N# _/ t" t% h5 f {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},/ S% v+ v- i% ?$ S
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
! V7 R0 q: P/ ]3 m7 g- l8 K' Y: U7 n {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},: ]) o3 m4 E) }# `6 I! ?9 h& N
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},, |/ M! z$ y$ }) z/ W9 K: k- A/ Q
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
( T0 Z" ]' l! S/ f% U' L {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
9 r) y# }- [: j* `2 y2 e& s {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
; }+ _6 s3 o; V- k" _& n {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
! w& f5 J/ K- Q/ W8 X0 J {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}4 n: s6 a) @7 _" y
};
* m! W7 x# f$ E F$ h' L; P/ w. s. k+ i" x; w0 {% O4 O6 H
0 _: x7 c4 v% L B' W {const char hid_keymap_dvorak[14][8]={
4 l$ x$ Z! ^0 \ P2 W0 ^& t$ K {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
5 e9 q1 l1 M3 L" i+ a' c {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
4 F# z4 j+ F$ c' \/ } {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
9 K" P p& {5 u( E {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},- c! s" Z0 g6 \6 u* |# e# R4 H2 \9 C
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
1 H# W4 w/ o1 X7 h" i( E; @ {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},8 w# W6 t/ A4 y4 y# X
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},
" L0 n: K t7 U d5 z5 g" G" R {HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},9 H( e5 Y9 P- o! L
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
# y2 ^$ h- T' e2 T0 O. V; L {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},7 T8 r: M( @* V0 e& U; c6 y$ I3 ]; r
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
1 h( N' a& [7 G% C7 ]0 G6 j- o {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
5 \, s9 O' t- L9 @ {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
5 t( @: w! }! x5 X" q$ w/ i4 ~8 h+ h {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}, S: H4 U- t e. e# l4 j
};' o! |0 o% ?/ d; X! Y, C p
- {5 ~7 }7 _6 A$ j# J' g
9 b* Y/ ^* s' P8 m2 D. a& `上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。" X1 h* O) `$ K) |+ Z5 {' A
) A1 s$ l6 {/ ?' J1 _7 e) A7 [HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
8 k; a- E( m2 h% ]: U. P9 k- O- F" D1 J W/ ?" q/ g' p8 S/ Y
void update_key_matrix(char row, char col, char onoff) p$ x; ^1 u0 |. F* K
{
3 m. N. w w# [! X/ D static uint16_t hid_report[4]={0,0,0,0};
3 s/ ]* S* h! M, _ static char (*hid_keymap)[8]=hid_keymap_dvorak;8 x' |' N$ f8 t/ }9 h/ }" w
$ }# D5 H) q" E! P3 O# |" C" D* N( K- @- ^: N, Y0 d0 k
unsigned char key=hid_keymap[row][col];
/ `8 v, `$ Z7 Q unsigned char *report =(unsigned char *)hid_report;
* f* Z( `" g" h char i;9 \ } H2 D! G2 I+ o) e
9 l: B+ k j; P6 ~8 ^) T3 z" y- ]3 B5 G
if(key==HK_MODE)
/ a# x& O& N) e/ z5 j9 e2 x7 _ {% I1 z! y7 N& n
if(!onoff)
0 z, @ \0 {0 }+ ^( C% f {
8 @. x: X, m$ ~3 |# u if(hid_keymap==hid_keymap_dvorak)/ K) g, T( W! N. Y+ @$ e
{0 M. N) F; Q- P$ J; m6 C1 \
hid_keymap=hid_keymap_qwerty;
$ Z/ q8 L/ [- }4 i0 w# O GPIOB->BSRR = (1<<2);
* N9 G' t! {9 Z) u! F2 j4 c* n }2 a+ Z# d% s* D& n1 Z4 P
else
. \) m% D, K4 F; ?6 m3 m+ ]. r {
2 D! j0 S1 S E( [4 V4 [% q hid_keymap=hid_keymap_dvorak;4 v7 Q' O6 {) i6 A0 u
GPIOB->BRR = (1<<2);8 {4 S/ v8 w! q
}1 U* A8 P" m4 @8 F9 f2 C
}2 M4 ^2 [4 M& T3 O
return;
: L: l* @# [% w }' Q: |- e2 W; _: }0 M/ _
% @2 `: C- O# j$ @
9 I0 X2 p2 h- a: R4 {3 ` if(key>=0x80) // Alt, Ctrl, Shift
2 Q3 ~$ l, G5 K8 Y- {3 ^2 f- k% n {: R' ?1 j3 F5 }, x& D! n0 N# d
uint8_t bitset = 1<<(key&7);
( A9 b- e- h* ?5 j) @" s if(onoff) // non-zero is key up
8 o. a/ T/ p' }2 C9 R% R# d, {; o3 Q report[0] &= (~bitset);
8 U+ q0 e0 M3 {- ]2 g else* } N, {# F9 s# o* `. K! Y
report[0] |= bitset;
: A- W0 F9 H4 t. y1 U0 S }
' ], b7 W# @' g else; K/ v+ M. `- l; P+ b \4 b# b7 B
{+ B; j: c/ D$ A
if(onoff) // non-zero is key up9 W/ U* x7 j$ V, j) w+ P8 y0 T
{( `1 N3 J# J" x' ]/ r
for(i=2;i<8;i++)5 W! y1 v3 N% |7 V' k0 j) a
{9 ^( K! j2 V0 N+ a
if(report==key)
1 e: u) F1 L& ^8 H6 g0 e+ J {
! |' q3 o. [( ?# v report=0;" W, p1 P$ x$ |! o2 E
break;
' Y5 n* G0 v# ^4 E3 ?! d$ J4 f) B }" c; v% p6 O% ?; h5 _
}( e" R1 M; w5 M6 W7 J
} ~( i) i8 a& S: Z' j7 f
else
3 S: J9 G! ^$ Z {- y% k: W+ x2 S' W+ m9 _0 A
for(i=2;i<8;i++)2 ?+ P) m3 z2 y6 n8 W* D0 [
{
) X* x; x/ e. }9 g if(report==key)) @" Z8 A( d; ]
break;
/ i* P/ Z4 v T& N if(report==0)6 g' m* n3 z! [4 t+ G
{, Z. ?$ _9 K S
report=key;& E, ~4 a3 b5 E/ j/ f
break;
9 I& [8 w4 G# Z1 J, p6 G. B. P }
3 u# X9 n# Q$ D; Y9 H- k2 e3 m# N }% D0 G) K* i3 X' c
}
2 D/ r R( i) C5 X }
; n) r/ W$ j9 `2 N0 u$ G for(i=0;i<4;i++)
n' U4 H( i/ Q0 { USB_PMA[192+i]=hid_report;2 a7 r8 L0 m( {
USB_PMA[5]=8; //COUNT1_TX/ P4 R3 Y; Y9 Z; ~9 J: c1 T
if(ep1_wait==0)
6 d" K+ I& S0 t {" T; f" `' r+ U
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;1 Y V% U8 |; b
ep1_wait=1;
3 Y0 A4 O1 `3 |: _ }; e) T, s3 f8 ^# N# H
}6 D) V( I6 Q7 D
" [- _* h, s. q4 [1 k- v( h
, D S4 e/ q. k完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。
/ h* ]" u/ v0 B- @2 O
keyboard.zip
(8.7 KB, 下载次数: 6454)
" R" I: E2 N; ^7 _
/ o0 L8 c% W: P" _. h
# G) `4 |* S; N m
4 B0 ]! I1 Q6 _% r4 q
3 U# [. |, F) {. u
|
|