|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 - R1 u# O4 s) `/ x, D) n$ Z
7 b V& E% G. A) P7 E7 I3 c扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
9 F' @9 s/ q2 P: L, D3 D( q3 A2 a7 B6 T
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:* _0 S* Y: {8 R: K
) Q8 t s8 B* A* ]8 I
- y0 l7 W* e" Z% p9 X- L" l
const char hid_keymap_qwerty[14][8]={: ]) n& l" d( Y9 ^& @, k1 x
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},, m2 k' f% X$ L6 _
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
3 E( u) ?9 m6 q* _( h' _ {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},9 v- X: x" |7 D0 s) o' g" ^- T
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
& H: n& U' A) [$ C# k/ W/ H) V {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
5 g5 O' D2 u9 t$ b/ a0 f. _ {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},7 D6 K6 E* J! ?' y
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
: v9 c+ E0 m4 C4 p" s) n6 `) |, G {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
' x3 X# f/ s( | {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot}, d5 t z2 _- i4 S
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},# B7 b% S2 b) G1 v
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},7 a4 k y7 p( z- @0 Z( g
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
; b! E$ n3 Q7 s1 Q$ l; A {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},0 O; k! O9 o5 t% m4 y
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
$ o5 K$ C2 G4 W; e, M3 j* P6 W};" s2 {) [% @. E) g
) o6 ]9 C ]' a8 X n z0 t2 D. ^
: ?/ e8 z( {+ F$ V
const char hid_keymap_dvorak[14][8]={
' c7 t' Z6 u5 A f: D {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},3 n; x9 s! T- p* V2 _
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
R* M) |* t1 N( L% R: e5 `& d; d) z {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
& U4 E6 k: s: c$ D" l. K1 [# [ {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5}, T. a8 @- i) ]: Q
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},# B, S0 ~$ |% ]# w: }
{HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},. Y. l3 x: P) Y# m. A' z9 j
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},) C% ~3 A0 l# d: y7 C! y
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
4 d! U `! P' ?; {* T$ r7 W {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},0 R% z" y5 j# H( W2 L' z' w
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
* T) h6 [( B) _9 |; _, j {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
l4 `5 d0 Y) V: W {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},) T2 Z% M* ~* T. W3 x, a) W
{HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7}, i$ P$ K; g- f$ ]0 A
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
3 v5 f# V' L4 v) d0 h0 S3 z3 i};
- a; R& D# N* c, p. i
( {3 q. ?% j* K+ `+ s& q
9 `- V4 c2 r/ z& f! }上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。) }- \2 ?3 o3 t5 ]8 G: a- K
! |6 P+ `: u1 h" g1 Q4 R
HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
; }7 m; T6 K" _% w
2 |9 R8 e$ M$ X: B3 [' R( M' Kvoid update_key_matrix(char row, char col, char onoff)
) f2 i, K% G2 |+ {, P( }# J# `" K{
/ M5 H, n! w9 T* H3 ?0 F static uint16_t hid_report[4]={0,0,0,0};
; j) e) J0 o( t* y2 h$ h static char (*hid_keymap)[8]=hid_keymap_dvorak;4 k- ? I+ v3 O3 U1 z* }, d& C
( v) R3 l, b0 t1 M6 F3 F; j) ?% o7 Z1 z3 A* N/ X6 ^; m
unsigned char key=hid_keymap[row][col];$ \! B# {+ |8 B" G6 ~
unsigned char *report =(unsigned char *)hid_report;
3 a- T' l" o* z, F* p z5 ?8 I char i;5 e( A( l3 D" A1 T- q6 V1 g. P
S1 J2 m6 x* M7 e
$ T$ e8 K9 T2 B3 E if(key==HK_MODE) `- u! v" {& Y/ G: B0 g
{
3 E U) x( a2 V* F0 g5 z$ I! ^ if(!onoff); `' T0 ]0 S( t3 C( Z
{
" h) E" e/ x6 `. P if(hid_keymap==hid_keymap_dvorak) u3 x! r9 Y3 L W* } }
{
6 b5 b5 L# I m0 |* h% ?$ X8 ?+ D. s hid_keymap=hid_keymap_qwerty;
, T$ E/ ^; D; T* v GPIOB->BSRR = (1<<2);
" _( @; e6 a4 C8 m- }- o& i }/ h" J. P) H z( K* A* J O
else0 G" n( F6 v9 \
{
4 ]+ r* U5 Y9 p hid_keymap=hid_keymap_dvorak;2 N7 L" y6 Y7 |* l% `
GPIOB->BRR = (1<<2);1 v9 g( j5 V; x* h5 v, E7 @% C
}
' v/ P5 g6 W' ^3 R* Z } J) N. _0 H* n3 S$ \
return;
/ b* b4 H3 F9 c, D/ P! H! M }8 N% @3 c% L. s# b- A& d
" V$ A9 v5 _( Y% G
" F S( g, ^+ J D if(key>=0x80) // Alt, Ctrl, Shift& K; d) W7 K2 x. c; v* x9 V& A
{* W+ F, V. z9 G! ~/ e
uint8_t bitset = 1<<(key&7);
9 [. q4 }+ \" f1 @: f if(onoff) // non-zero is key up6 s# g$ _! V8 n9 G
report[0] &= (~bitset);" H# _) s& B! J' S4 `
else
) [# ~) N' {; K) F report[0] |= bitset;- r- L3 j8 e& g; z8 k" d- I1 t
}
" C) |% h4 h& j8 o- F2 m+ w: g, N else! Y% R& N1 O' W5 Z4 E7 t! c
{
) @! q) |/ H& e g+ } if(onoff) // non-zero is key up) v$ v/ u2 X% d1 A6 C1 Z8 U
{
* B0 p& i$ w _& P! l for(i=2;i<8;i++)9 ~7 t; r; b- \3 D4 I% E9 T
{( _0 K9 F( {8 e/ G8 i- u
if(report==key)
; @2 ]9 s! B( E1 g {9 J* o9 p6 ~& F/ s6 }5 t7 H
report=0;
, U, a t# ~- f% W& D break;- X2 |! r3 M7 m0 w
}
% \; h" j9 J7 b% y# h4 _ }+ a: _1 d; K9 X
}/ N$ k+ q7 v, |$ ]8 Y! D H
else
1 c v: M( F, n {2 T1 Q7 Y7 o% q5 B0 V
for(i=2;i<8;i++)2 Q3 t, B" K$ r9 l( n
{
. A4 [/ v3 w+ q, \ if(report==key)6 R3 _" Z& J+ b2 m6 ^8 S% I" V
break;
# x8 @4 l' Y: h if(report==0)
7 Y# r+ C+ b8 g0 }. ^0 n {
0 y- `7 d+ a0 A report=key;
, D; \$ j+ m: I j break;
$ f2 {6 r/ n; Z( g$ q } f2 R$ p, m& y
}4 P2 I/ {. e& I
}
# f/ E. }0 S' \! i }
( v7 b6 i4 V8 i& `$ _3 t for(i=0;i<4;i++)0 s% q- p. l& _- ]* R
USB_PMA[192+i]=hid_report;
! c' Z ~+ w# u" n0 F" ~ USB_PMA[5]=8; //COUNT1_TX' i, `4 w# J$ O0 x
if(ep1_wait==0). B6 P. m$ p9 X5 P& f
{" l: W7 p1 q: B( X5 s" G
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;, I0 e% m5 D$ T( ^6 p- @' ?
ep1_wait=1;% _- a4 l; r% }& A1 |$ V
}5 {+ B5 a; Y" t: r# M5 C
}, W9 q: y& b+ \1 E
: |: X( c! H3 l! c% w' s
/ {) e/ J9 @3 t8 q完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。
9 N1 P k$ n. g! d4 Y
keyboard.zip
(8.7 KB, 下载次数: 6353)
( c7 @- m" ?' I0 G9 p- f7 s; O$ M% W3 x& n2 `: H' v$ b
! C3 m' g9 D& m1 ~6 W. z# d R. m+ n
% [9 t- G8 b1 t) n
0 ~0 O& \6 m7 ?/ _: f# Z5 V |
|