|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
+ u, K' {8 @6 ^
! T4 Y# J, J J- L# q9 Y5 _扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。) n3 v) [& M* i
/ H5 w4 [- r* l. h+ j# C
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:' U; l. q6 {3 |3 ]
1 K& }2 Y) l4 n7 D) D
6 x( v% h4 {* i: N& p$ D+ i2 Y/ Aconst char hid_keymap_qwerty[14][8]={
' y) J+ E9 ^+ e. }5 Y1 U% a/ j# } {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},; v* i9 f! J+ S" p8 I' V
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},/ U& Q% ~& ?. t% [" }1 U( Z% U; k/ }
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},
6 ^4 r, o) A( P {HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},4 t# o, w! i8 o( D4 x% E) X
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
/ g8 H; v! Y* W: O4 S: Q8 J {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},2 E# s* I" G+ }4 k- B# r8 ^
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},# ?7 x6 e; |( A ?, K, N
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
- s& q- D2 \% Z {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},8 w+ p8 B5 i5 _
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
4 A9 Y" L. P# d( Y {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},$ k# I0 d$ _1 i+ [+ S/ ?
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},( L& X, @) P9 K: v3 _" |
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
7 Z$ n! d4 `+ m! [, {9 y {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
7 X" p* M r4 f% r};
4 s/ }3 t- }( q, T+ i) K& {8 G% O3 l8 G& R% ]
- X0 Z& c: D* j$ O9 Q
const char hid_keymap_dvorak[14][8]={
7 _/ r+ K/ s. [ {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
0 x6 s7 @# P G7 Q2 o {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},2 c, C7 \" @2 J9 ^- `) r
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
& m; W) F! h3 W5 R {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},& F7 P9 S" N, Q5 m
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},- ?# h% f( L' W! v7 }. L
{HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},1 t3 G# i0 R: I: V y
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},
# a3 e5 |$ l. K- ^# e: ` {HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},. w7 A5 j1 X7 |( J- x+ T0 D
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},/ X; E- C: v8 _
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
6 @* [ l3 n8 v+ N% { {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},5 _+ `( C4 a/ p7 P6 Q. @4 Q$ U
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},2 `5 q) X) e1 `9 Y/ X) d" f
{HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
/ v8 w6 N6 v2 ^2 b% Z0 { z; } {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
, H- ~% \4 D9 y% U6 M0 U};
" @2 [( Y2 r3 h& S7 k
+ x: @& H- |) |
8 w0 d4 y6 D# E/ I上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
5 a* `# E2 B/ \" D& s. @0 f0 S6 V0 V3 U: P2 [
HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
9 b) l0 Z( }/ Y' a& ~. x7 z+ `% [7 W2 [* I- s' G" p) O' Z
void update_key_matrix(char row, char col, char onoff)
5 J, G2 ?8 a+ j- V6 C{" F, B: L% v _4 l8 T0 j
static uint16_t hid_report[4]={0,0,0,0};
! T! `, {+ R+ }. t2 c3 Y static char (*hid_keymap)[8]=hid_keymap_dvorak;
7 e( [' p/ ^6 Z# e5 d: J+ d: t) x [- u+ B% u6 g
& K8 m* M- k1 L# B+ k' m, o unsigned char key=hid_keymap[row][col];5 b6 T4 J$ x! ]
unsigned char *report =(unsigned char *)hid_report;
% C. ~6 P* k5 r1 J3 z# s) o char i;
) S* m0 i5 [$ U2 E1 w% P" Q: ?5 {; }; S: s2 f% b. a
3 b4 b0 `$ C0 W" ~7 a
if(key==HK_MODE)
) k" ~; q' O3 V6 U3 }5 V1 |* q {& y0 L+ C$ n, N' h
if(!onoff)% ~. h2 @9 c) g9 A* t
{
+ g3 R5 O5 e4 ~+ d9 q9 G if(hid_keymap==hid_keymap_dvorak)" {: | ]9 I% A5 a% K$ y: A
{3 U% B( W; }% P
hid_keymap=hid_keymap_qwerty;
4 X4 A/ z5 F2 ~& U. S GPIOB->BSRR = (1<<2);
0 p* g; ?" M5 u6 C/ k# x3 E+ G A }" A! C0 {) e7 Q0 t8 M& t! I
else$ W+ y {+ U6 }; m6 o
{
7 H, |3 D* A9 ~6 G9 v hid_keymap=hid_keymap_dvorak;
: M1 @8 ~' v, F% A K9 \ GPIOB->BRR = (1<<2);
# p: f7 E" o8 M; p( d, u }
9 h) e# p5 u- S- |% P }
7 S6 f3 Y" E% n return;
. ], q1 u! `( h/ ~6 v }
$ w+ V- ^) \/ p$ u/ S/ N5 M* P9 i( F4 {9 j# f
' S! {4 d( D% D+ _1 G5 {
if(key>=0x80) // Alt, Ctrl, Shift5 [% j% y, ]3 K2 z' z: n
{7 G. Q* f. x4 X8 s, k# h2 y3 d) e
uint8_t bitset = 1<<(key&7);
5 b* c# j7 o3 O2 j5 T. w if(onoff) // non-zero is key up
, q0 m5 g4 F) @7 y2 n5 }* J report[0] &= (~bitset);
( M* M. m- k: ~8 v else
* y9 Q+ ]! f. z: v* k3 c report[0] |= bitset;
: L" O# [& q. l8 `7 Y; C }0 u: U9 s* V4 Z& y% n
else
% X- i% i- K0 @2 @ e- N- O8 ` {
; u0 J9 _: u4 L! z. ?- F# Z if(onoff) // non-zero is key up
4 O& R+ I d( p( ^& A( Z( @4 m {! S# g0 a. _ ~
for(i=2;i<8;i++)) V! M8 H6 u& l. G( X- K
{) ?$ I1 N% R, k1 Y8 J' y- [" n
if(report==key)
# L5 k: T5 R/ N, _( E. N% T {
3 n0 j7 D2 l# P report=0;
A! Q7 T! Z7 T, A% M- I* g/ z! D break;. B) e. t' M& i6 H
}
6 d# x; U B! V" o" X! o }
' Q- S a9 ^. t, j, C% h }5 [/ i1 Q- D" u) e! z
else; j. ]( [1 H0 c. m$ X% \7 n
{
6 k, N2 \; t, p) Z$ `; B for(i=2;i<8;i++)( a" H. \* I, _1 ]$ p
{( M* H' f! g$ g3 U& ?4 z( y4 A
if(report==key). ]3 ^! }) x9 r3 n
break;
* s( B8 X) i" m' y# D* b" W, b if(report==0)
9 m: j. e! t. @ {. T' y3 F1 |3 U- ^' a" s$ Y* L* m5 }! u
report=key;
5 l9 p) \2 ~' q1 L6 K* J v break;
. H# m6 f7 C; M! E }
" ^3 N8 S8 F4 N5 o: z }
e% n* I% B U i }+ x& u( I% d6 J" e5 ^5 u
}
4 ~- o4 z" G& d8 l- q for(i=0;i<4;i++)
% o6 l7 ]- d" @# B USB_PMA[192+i]=hid_report;# M% \2 N! ], E; i, V
USB_PMA[5]=8; //COUNT1_TX p1 O/ P# \. w& [0 r
if(ep1_wait==0)+ D; ?# b& V, F
{
: Q8 w/ J: a. x( E6 P9 @) z+ W) a( Q USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
9 R0 I9 j4 C9 r* S, K$ g' X ep1_wait=1;
( f% D9 Z( C$ L/ n8 t* s+ R }
7 Z( W0 K: e7 P; {% `}
, ~1 I' q1 n' T- c4 H E4 K! \* x4 x F, b/ Y
+ k( D" n1 A* B( A2 F# Y% K# R1 o完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。) q2 e& x2 u2 d1 [' a N, b
keyboard.zip
(8.7 KB, 下载次数: 6064)
' j- g/ T. \8 a! q
, `* }" L. J; Q4 F: H& q9 Z) Q9 }
* U. h$ s0 z5 C$ P; x3 m3 r- V
% ^/ O1 M+ t* z& M1 p! D
|
|