|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 $ d T# @; Z2 G5 }( l( d4 T0 ?
+ h( |4 `8 J% ~) z" U# @7 |
扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。 ]7 @9 n5 p! R8 I! e
; A) O$ ~* N4 f( y' Z" d4 |要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:
+ o$ ?# c b& @3 g
3 [5 \, Z* o7 ]3 R6 n$ e* j6 A1 [) L/ i1 A" ^
const char hid_keymap_qwerty[14][8]={! ?/ M! v) F8 E: F6 n
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},* ~' S1 ]; E7 c1 t. t- |
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},5 l0 T* a) S- E) i1 z2 h7 b7 Q+ j
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},( ]* y: Y" Y- ]: P
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
" j E7 c" ~% T3 i0 U$ W2 n B' P {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},3 }8 V6 T: b7 z* m
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},
8 w0 R7 o4 Q1 E. ` {HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},5 e- N& _+ c3 a7 s& _3 A" }
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
( `4 {/ v d e- U8 l {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},( G, y7 G/ ]0 F/ A
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
: D7 E0 u- w* A7 P) \ {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},( ^3 u* y T8 {3 e- h- h
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},# o; A% S0 X/ L- e( Z9 ?
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
' _( L1 W( F& l( P {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
9 X8 x9 X. A7 E! d w8 K! D* }' h: I};: n$ {3 @( Y6 d$ v; c. U J
" u, }* y" g# M" p; R
/ D9 r- E: Y! M4 h; k6 q
const char hid_keymap_dvorak[14][8]={8 H" H/ x1 L' A. K2 m4 a" y
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
1 ^ B, P/ r2 W1 b3 A+ T {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},' |% Z( J7 r+ z m
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
3 f: M- Q8 l% j/ V X {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
i. C% |; b# P {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
* `: ?9 x+ q8 a+ \, P {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},/ t, ^. R' K3 d* P: w- V
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},' c+ ~* n4 d/ H' }5 G3 F+ f
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
6 @; f: _' j: S5 D1 d {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},0 B" f' T# U7 Y
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},7 W- u1 y. _% \3 _: p$ S
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},5 I- n+ Q- [+ u6 }& |
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
6 J, d: x1 O8 J B' Z) v8 f {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
3 W& |( P* g0 p7 ^! z {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}& }4 y$ I) K& C. Y
};. @. F0 E O, e
* z9 t8 A$ M% q
2 U2 h C$ x; ]5 [1 i" _- U |上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
# M' b5 e- ^+ _$ W( y
# v. T3 g% p0 Y2 D1 Y0 rHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:# ]. w& z! M2 q# E, l0 ~
9 g. Q0 J p6 m R* M4 J
void update_key_matrix(char row, char col, char onoff)" i, F" N! y/ X: [5 s- E
{
' a7 z0 E! t% q7 J& b5 H6 X static uint16_t hid_report[4]={0,0,0,0};
6 [; ]8 r5 u% q4 | static char (*hid_keymap)[8]=hid_keymap_dvorak;
; B* @$ r" p0 }0 S. `6 \) ~" @
0 L6 m+ ^6 f9 t3 C! y
h& T* h4 e7 Y! Q unsigned char key=hid_keymap[row][col];' y8 K+ z" i( O; G
unsigned char *report =(unsigned char *)hid_report;
! M/ m/ C) |! D T$ w char i;2 O* k% D0 B, d/ R: W- ^+ u- I0 [
9 U! l) l3 _% I( a/ h2 w
/ H0 _, W& F) W" n if(key==HK_MODE)
2 a5 l+ A {. z& C4 E& V {; A" M" t2 Y' l; v( ]6 ^% @! g# f9 \
if(!onoff)
; H; `; \8 }" M8 f! j {( k' R% c7 ?6 j( Z; e- R( O# G
if(hid_keymap==hid_keymap_dvorak). @+ V: {/ I) D* b2 e" W
{
# _% b3 B3 s6 v hid_keymap=hid_keymap_qwerty;4 v7 _8 b. H/ Q# T- \1 M
GPIOB->BSRR = (1<<2);
: P+ K3 ]3 M. P }
' d& y, e# b6 r& K else
4 K) y: G- w/ K" h/ y- N {9 p! J n4 G0 v) N# m- ~ M
hid_keymap=hid_keymap_dvorak;: \$ D0 _$ g- n% O
GPIOB->BRR = (1<<2);; d6 Y4 X& K6 e
}) e# _# @' d+ s
}- Q" x4 P6 T2 S" @. D
return;3 ]; [5 K6 _: D2 S% L
}) ?6 d9 s$ i! E/ e' |% s j6 I* S
2 e4 b6 u) D' Z7 y* s8 L; ]+ X$ j8 H1 V" Z6 D' C# v: U9 ~# i
if(key>=0x80) // Alt, Ctrl, Shift
! W2 e- x1 E$ a( S! j" q$ b {6 `8 X+ _ P9 I" u
uint8_t bitset = 1<<(key&7);& D8 `- l+ W6 A l9 H4 t( ]9 Y
if(onoff) // non-zero is key up4 `* c7 p9 R% H+ c5 h* q
report[0] &= (~bitset);- {9 K% a E6 g2 y! l6 h: u* N, `% F
else
" R% k+ } Q% k: j/ f: T+ k$ t report[0] |= bitset;
+ Z+ _2 T% v c }
9 _$ x/ l P J; O: e1 D else/ `3 m# X& ~# Y$ g
{
& d8 |8 a6 K% T! J3 T if(onoff) // non-zero is key up
+ R! ?- @2 I0 I* f" b+ j9 U4 ~$ {" l {( s1 a. ]6 Q) A; m" g5 L; N
for(i=2;i<8;i++)( G7 R+ [0 g# R Q' [' P
{: x: Y7 _% x& q8 s% z
if(report==key)
( T7 A, o' ~) d! L5 K {
+ o# |1 R- U9 S1 q8 d# \% x0 j8 P report=0;+ m+ V. z! Y( ]
break;7 q+ T3 A/ v: O3 P: a- ]
}
% o! j, I$ r5 \% t }
& }) _: `! [' l5 G6 c# M7 T+ Y }, c3 n9 U) H5 F E0 u
else6 w( O M( Y2 N: H; V; ^- h& Q
{9 V! k, G- m7 i( m) [ I
for(i=2;i<8;i++)( x! D0 _4 n* R% q" G$ ^8 z# c
{
0 ^0 o! v$ N! l* D6 N+ [5 } if(report==key): U+ ^( n- _9 j
break;
9 }( j# ?0 S% E0 `- w if(report==0)
9 U6 [* Z. B* G {
; [+ o2 b0 E: l8 [+ U report=key;' ?& q& A2 c9 n! f
break;
- u0 q3 s6 v9 o2 F' F }
& S1 I" G1 O; P+ ^. K" m1 _ }- P( I9 B5 M: B7 p8 j4 I
}
* m8 C( e$ x) l3 v# x6 K }
( E/ h- h8 k3 G { for(i=0;i<4;i++)
: S" W9 M* B5 S( o( F& }+ o, ^ USB_PMA[192+i]=hid_report;
h3 g6 n. ~/ {0 N7 @! U, q, @* K USB_PMA[5]=8; //COUNT1_TX h9 \, ]- j8 H* N, }
if(ep1_wait==0)
. u, w( r5 n, J$ M" B {
4 S' i+ H; H+ B4 D USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
' ~" w( C* g7 X5 A2 x ep1_wait=1;
9 m/ u8 y/ {) r5 n2 M- b5 P }
2 Y0 V1 r: [# f+ g}! a9 @% z9 M# t4 F
. `' o7 D4 K- U1 j; R y) P# c& T
0 I1 c2 p5 r) G6 A) y; v
完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。8 s2 @ [$ T8 J; s6 v
keyboard.zip
(8.7 KB, 下载次数: 6617)
. y- n6 O* w1 E; N a5 Z4 L6 r. u
% L, o4 c! f8 W# R s3 [" N
2 D+ `$ I6 H6 b4 ]' E! q
% J6 ^' D' i/ Q0 G" \ K/ R4 N9 p6 w: ?, f
|
|