|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
( o; _$ T+ ^/ w9 o: L% c
& i* t7 E0 T" v. }扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。- x2 }. G: d1 G$ E, n
. v, X* I" {9 y1 F* F- m: f* @
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:% K1 I2 l1 n! j+ Q9 T
4 w4 ], E% `6 `" K" p! B5 Y# f, G5 \/ `$ k D$ `0 w, N
const char hid_keymap_qwerty[14][8]={
3 I4 H1 D. [! B* M1 J+ A {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
3 u; C( @) s% o {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},4 h1 ^- l% |. v, B
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},- J7 V- C. [7 H9 n0 @
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},. x7 w' `" b6 T
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},) g/ v8 |% C0 D4 v
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3}," A/ O; S( d3 S7 E, {& K4 I- E" E
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
8 r* Q: G: w. N% {2 E* V {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},+ J6 o: }$ U% n$ j* a0 q) m+ K
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},0 K6 K2 p- \6 ]+ L, K2 [0 L& p
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
2 j. o# v. T+ y {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
& D" Z9 v) K; n- M& h {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
7 u7 a* n! A. I' p- Z {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
* f6 `# Q+ E+ F* N8 Q! Q) } {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}: v2 I' R) j r0 `( G$ `
};
; f0 {% {" y3 @' i6 X0 u4 _, ~- _; P; @4 N5 L0 G+ E
. X( s# B% b% G+ w& t1 e
const char hid_keymap_dvorak[14][8]={
, q2 X) m+ H6 ]+ U& l {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
3 [# h" ?/ d+ Q( k {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},, b* }& V h& F: C8 y
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
7 j7 j# Z x* x- L1 i4 @ {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
% T) o% `. v2 ], I) K* R {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
4 ]9 M9 c* b0 k7 D {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},, R; I( H( ]5 J6 u
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},: Z4 R v5 {, [# Z* f: }
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
# n4 ~! n8 X* X7 @* @- d6 D0 @- B {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
" S6 A* r8 ]& z8 @! ]1 e& e! r {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
; Q9 j2 Q3 w) }. L) G6 e! r {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},( U( l# q8 Y/ y! s: D
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
) y' e4 A/ z0 T+ X {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},. M9 |$ K4 \* p: b
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
# P6 [# c3 b4 `" J};
1 `& Z+ d$ d" `# A/ K# @( \4 r. H0 n
( r9 s5 Z* c, N5 C" Y
) W8 Z& @; p/ J' `) \上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。8 G* f6 q( y1 V, m9 ]+ F
# v& b0 L0 {6 G! ?0 p
HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:3 f1 ?1 M* X5 I! M- H4 w
- [9 Q/ o! y. Tvoid update_key_matrix(char row, char col, char onoff), ?* N: h) t+ `& R+ T
{
3 `5 N& V! K- t' V0 @3 q7 r static uint16_t hid_report[4]={0,0,0,0};' q. q; G& a# h- _& d
static char (*hid_keymap)[8]=hid_keymap_dvorak;
$ ]: K$ M; b" \% O R$ k, L" C: B1 x ]. f! J f$ b9 I
O/ V( v% T( B* I& N. @ unsigned char key=hid_keymap[row][col];
1 r) Y% j& V) {, u( \6 U# a: N' w unsigned char *report =(unsigned char *)hid_report;9 z- m# i1 Q; @5 F$ N
char i;
2 l" H5 u; s/ @* I! r9 J
: p# N$ t4 T% F7 j+ s& s
% ?3 x$ u' Q3 A: Y' F3 p( t' L if(key==HK_MODE)
+ p% b% z% U. C8 o+ c: n {
) f2 ?- {; \3 v3 @ if(!onoff)+ ?1 {0 Y7 L0 a. B7 J0 x8 }
{, |! i8 [) j8 R, P0 \
if(hid_keymap==hid_keymap_dvorak)
1 G+ |- O# \8 L. Y* q% z {" `, ~7 ]& E/ I* J
hid_keymap=hid_keymap_qwerty;6 u0 O9 p7 p, ~# l; |
GPIOB->BSRR = (1<<2);
9 W6 y+ H' J( j }. l' b) Z# \) A
else# ]4 n# n, g' s& F: M+ ~9 L- J6 _
{3 D$ M! _1 |4 s3 \ L3 W
hid_keymap=hid_keymap_dvorak;
. C9 D+ N8 S4 y# J! _ GPIOB->BRR = (1<<2);
! _4 W' F% D0 _& ]! \! O2 L4 N, B }
( Y5 U5 ?( J1 Y" H/ _" g# J }
5 A% y$ [: N' n8 H% K return;
# {) h8 |; s! w9 M }
; L- Z: o& }: s
7 ]* F8 h' ]8 p) a' N0 T! w/ T2 |' C K) x. b7 H
if(key>=0x80) // Alt, Ctrl, Shift
9 a* n$ ~% y( s { {3 V. K* d V8 m
uint8_t bitset = 1<<(key&7);
* W) a. e. J* [% O if(onoff) // non-zero is key up
E4 Z* m+ X9 Z+ T9 W& o7 K report[0] &= (~bitset);8 Z1 |/ Q( \8 ?# B$ C
else
! ^) J7 m8 e$ a7 Z! S$ l report[0] |= bitset;
7 G" G# K" n6 } }
3 d( q# M9 n7 Q( V( W. Y5 I7 `& i else
, z! k- W& H; n5 @6 V2 @8 I- @+ n {
" W) C: c$ D5 f) K+ U% M if(onoff) // non-zero is key up" {/ x* x2 H+ \* o
{
2 _1 B* @- e, q1 P; U8 w$ D for(i=2;i<8;i++)
7 X# p3 e. s& l% \ {
0 Y$ H5 q Q. F if(report==key). L3 i7 b9 l+ i; H# s( k* U
{
" U1 p& n8 `+ B6 Z report=0;3 G5 [3 n, f1 o/ q
break;% |/ K1 _- `) L! _% V, ~
}
: F4 o D; d& J# P" f# x }& v3 O+ u$ @9 P6 G4 t0 f% S
}* S I2 @4 R! G0 o" g- ^& ]
else
! }8 j1 G9 `. K7 s$ l {
+ H- D( M( Z6 i$ Z: ? \ for(i=2;i<8;i++)/ t, _5 V- o1 Z
{! V4 k3 _9 }' [9 N, v% y
if(report==key)$ e0 q( F z) t; ?% ~
break;
: c9 _3 O* A& @, B$ N if(report==0)8 x( |; R# [) X& e* ]; F" o* B
{
8 d, s z" t) x9 ?$ @- a1 R9 h report=key;4 V& q X! }0 }* L8 U2 |
break;. _! r& Y1 n! R* q# S+ |
}
: V) S' z3 y# f: K3 d4 ~" C3 o } T: z- X5 b8 G; _% y
}
3 w" v. R9 w; g6 O& ]' t }3 a4 O" ?$ o5 M% i7 S5 `
for(i=0;i<4;i++)
- ^) h4 n2 l# x/ q5 {8 G7 i: x! B3 P USB_PMA[192+i]=hid_report;7 E( b- `, d0 G( c8 V x( ^0 j/ @6 p
USB_PMA[5]=8; //COUNT1_TX
* J6 b( Y) B& r if(ep1_wait==0)$ t# n: r+ I R) o- T
{: Z( D% \; W" U! H4 `7 t
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
; ]$ w( r# n& `$ C4 s/ W ep1_wait=1;" m% J' c/ K, r& l" s2 w) O
}* G0 Q( g# H* }+ }9 E' D
}+ ^. k- X Y$ S! c: C8 o2 w% A
4 d. O- _" {* g" J2 t4 k. K
' Y1 `" x# u9 [8 d3 D9 n完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。* y* I- }" Q6 t: t: o
keyboard.zip
(8.7 KB, 下载次数: 6043)
7 r+ p# `! D5 `7 F7 m. R! S
7 G$ u! x8 r. x+ Y6 J* [# [ M
+ a$ r( }$ I* o
( J+ C! n1 W) b- C8 ^+ s$ _1 R0 [/ c4 ?! E& B$ [/ @: _
|
|