|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
1 M2 E+ ^' @/ u3 n( w% t' A
/ G0 v0 x! N4 j- H/ [' j. q扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。/ v5 `2 ~' T4 ?( i2 L
, P& |0 M' K8 R* j: Q
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:
& s! ^/ H, c3 r6 J: ~
* V R( K3 ~7 `' N7 ]% o$ [/ z! j* R$ Y9 x$ N
const char hid_keymap_qwerty[14][8]={
" m4 k5 _4 Z% b* U$ V! [ e {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
4 U. ?7 z9 s! j9 _( M {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},& w0 o7 z; I* d# N7 y( j0 r' R- t
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},4 h2 y0 c: b) G- ]# E
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
# ^& w3 q' m+ A' g' ?/ o( c1 k$ m {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
7 r+ o N) G h5 e# Y {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},4 ]# r V5 w8 ~+ W. z
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},+ _6 p2 y T+ c) F- Z
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
' ], t7 e/ H4 \2 b' y b {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
1 K' y" V0 M0 |$ ]" t" r Q {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
$ o( `/ B' x" o$ s {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},& Y6 g- u' o8 B1 H* t$ b+ H! a
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},3 J% M/ ^: D S/ g6 B f) R
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},; N. s& z+ j3 j: M4 s
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
7 q# Z0 E% }$ G* Y# Z. [' R};
% v: d; x1 _! G- Y ~2 x- j! w% [; @: m: M0 _0 |' {! O4 w1 |# q
# h) q' w+ h% @5 J/ tconst char hid_keymap_dvorak[14][8]={/ Z2 z. D, k i4 k
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
$ Z; q5 z k2 i+ q v* | {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},/ m2 _3 W/ |8 f4 ]) v( O
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
: d! J" o a: ]: l {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
0 O7 @" {& l% A' s! v {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},( a& H" t" i* o6 h" R% k) O; _8 I. G
{HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
2 E, B) l( _2 g) j {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},6 i9 m R7 K7 h4 n
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
p. X6 C% U1 _; Y$ Z5 W {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
. H9 T9 h+ K0 h9 G6 f {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
, N* S! P+ p6 @- N$ V5 l {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
6 `3 [6 }' h) @7 C6 E$ | {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
) t7 D" Z$ U5 x" Z _) L {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},1 E2 m) |' b* K$ Q6 v
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
* B& ?9 ?% f" u% H, b ~0 a" h};+ v; }5 P) W0 P1 p9 e- |3 N& B& t
0 W3 b/ p0 S, M9 g( J3 Z
2 g( Q$ z( {0 S6 a: ~2 Z. V
上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。& v+ w' I. B( `/ @& n; A* U2 ], @3 B8 y
3 \. L3 K$ M1 I4 b7 XHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
9 c9 m" N$ S# O: |0 w: S; K' q# @
# U3 |* ?& R4 r9 N7 O. l1 b ]1 S" z$ gvoid update_key_matrix(char row, char col, char onoff)
/ T1 X' O; J$ d& L: {{- ?/ ?* f' }" i9 ?5 o& {2 Z
static uint16_t hid_report[4]={0,0,0,0};/ q+ `! M c& ^! x" ?
static char (*hid_keymap)[8]=hid_keymap_dvorak;
0 {8 H- N9 k3 P$ C- }2 ?4 |$ m: R$ _* ^
; B/ S/ V* d z9 \$ {, N. I unsigned char key=hid_keymap[row][col];8 e; h8 K6 V, L6 R
unsigned char *report =(unsigned char *)hid_report;! U j5 U+ r' v8 o' V- C
char i;
; c1 H; ^8 Z1 V6 E( f$ }4 C+ a# ^" h
2 u ^& F7 O# i5 a
if(key==HK_MODE)' e) D# b* n5 o- e/ E5 w
{: d0 ?* a/ Q% M6 _" P7 w
if(!onoff)
; o) H! |9 O" ?7 \3 R {" {1 `8 O" u7 s# i3 M
if(hid_keymap==hid_keymap_dvorak)% S6 a! h% T" D2 B/ }- Y$ @9 J5 K0 O
{% O( @' A! ?7 T. H2 C
hid_keymap=hid_keymap_qwerty;$ J2 T$ O, S: [
GPIOB->BSRR = (1<<2);
6 H% d+ ^+ @! [5 r5 y W. C }. {6 e( Y6 L; \# }: E9 m2 z- N2 r
else
& |* {& f& D$ P2 w: V. j! G0 H {
3 U3 z/ E) T% z4 b: U# P hid_keymap=hid_keymap_dvorak;
" l# |6 o1 k0 s$ r GPIOB->BRR = (1<<2);! k0 N/ C0 S0 n: q+ h x$ ~- t
}8 j+ f$ c- p5 }2 V/ ?4 {# B
}
+ a# X$ n$ f2 q. r% H* l return;3 A- Y% J$ e* u
}
1 Q6 `# e+ H: {; Z+ Z: f! A; l6 _
% b9 ]$ _6 o& z8 {/ R! W4 k+ a5 ^4 Y9 i' }
if(key>=0x80) // Alt, Ctrl, Shift
! o& K$ m2 i5 P# Z. m {8 ?, G1 t& A, Z( ~$ P' g# V
uint8_t bitset = 1<<(key&7);
" P. c" L) i& ^ if(onoff) // non-zero is key up
) L- a8 i* L2 ?8 Y' e4 ^ F! j( _0 W report[0] &= (~bitset);% ~( p; ~2 E+ Q8 g" q- F7 q
else
+ W o( i6 ?# L( A: v, ? report[0] |= bitset;
' S8 i" G2 W0 D' x" E }
. P4 U& E& X+ v: R( O, Q6 k- {8 p& [( J else6 C9 g+ Y; o# p$ i8 L0 }
{, H2 [0 j" e4 R7 P, D, }) X
if(onoff) // non-zero is key up$ e+ u4 y/ I2 D, B4 s- k
{
8 e- X9 g4 g; U; b' ] for(i=2;i<8;i++)1 M7 @& W9 U3 J2 a+ I8 x! h
{
' H8 b* L; o9 k$ d q, z3 i if(report==key)- c' b! N; s% Z) r ^& j( b! h4 t9 g
{+ J' g- Q$ G( d7 V+ \3 v
report=0;; j M4 y+ y% u0 S) B
break;0 g# V. A- W6 h( N+ }2 T8 k- @# g: ?
}9 x8 ]3 a! j7 H' @
}
u T' q7 y4 q! L- |5 J- F2 Z }
3 Q6 O6 X- O% u' T8 r) J8 M. J& _ else. i- z/ D' J: @7 p j+ V
{
! |/ z6 Z3 F. }% c* j for(i=2;i<8;i++)
3 N. n; v1 c3 a3 s, P. e {
. I! {! V4 `" O if(report==key)" [9 h% I, w1 Z G
break;, h9 S2 F8 \* h3 [7 h
if(report==0)1 m" t" \3 ]8 c) U3 D* H
{
6 J0 W6 X2 G! c report=key;% H# G& W9 s3 L
break;
% h6 x. l+ ~* V! ]$ R }0 I9 ]" e2 }) k5 f% m% d
}
4 ^9 \7 S5 Q, F! u }
@) e% T; |. j7 U$ r! z: r }8 b9 Y5 t2 y6 }6 O @
for(i=0;i<4;i++)
# d( u; I5 C) o6 v8 S USB_PMA[192+i]=hid_report;
$ H8 L7 W M4 V2 d6 D: X USB_PMA[5]=8; //COUNT1_TX
0 y% Q% n7 P& B1 M1 y" a! g if(ep1_wait==0)
7 z% t' }0 w" o {( M. Q7 L4 s( l) }, x
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
4 Y; G8 x1 b" S- ~, ~ ep1_wait=1;. U: A: z' f% k2 P% f
}
& p: r; F' D* s+ }- j}* G0 W# e7 V/ g- h
: R3 X3 D. w! G1 p: R/ ?2 j
8 G& ~4 p+ A# `# n6 `; ~完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。9 N9 {: a8 b n/ K) b. d5 Z5 e
keyboard.zip
(8.7 KB, 下载次数: 6305)
n" Q" z/ G1 R, j
6 {2 a8 r# P+ [2 D5 j
3 [# R, ^: f5 z% I6 h3 C9 k
3 T; x f+ T" q3 {" @
4 ?* D9 ^" w1 k" ?) L8 V
|
|