|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 $ h9 Z/ h) q. _! W
9 ^9 B0 i% W7 ~; r) H; j9 F# v扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。1 R; z% p& L: P, K2 _
* P7 b5 n" t. B要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:- M+ a6 E: p# S9 s {: w
0 {2 |, Q# Y( Y# F8 n9 B
% B# {3 ^ O0 J
const char hid_keymap_qwerty[14][8]={
) x* Z# y+ [- C( e {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
( | V3 N$ i4 d3 L2 D. Y4 n! \ {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},5 B3 }: }% H8 t6 n
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},( j* l& k- |) z+ l( C& C
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
& A* l# [. ]# X5 S5 u3 R {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},5 |8 q" ]* I& V+ T$ ]
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},
4 n( T. X0 q7 Q {HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},! I' w; T0 @" {! d
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
8 K/ i5 H" Z6 k% P {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},2 L- c; }* q: ?" Z- K
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},- ^% I2 q7 n1 x' E
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},' T4 |, m# ^/ }$ v, R7 n# ?0 s
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},0 J) p( ]. O) G& A. D7 M- ?) [4 N
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
( n, @1 M2 _1 p1 v/ F0 T {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
! j& [* R, M7 e) N2 ^# L};% L* c2 X9 U# u
- L: V: y* [* A! i& l0 V" J$ _3 p6 r6 e: ]1 g6 J# a8 S9 P
const char hid_keymap_dvorak[14][8]={
9 b% y8 L" Z: v; I {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
2 Q1 H# @5 `' c$ k+ F8 k {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
/ Z0 i# T) `) o. K# `, m/ G0 d1 ` {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},! p# z2 y) d8 V
{HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
# F7 u1 E2 m+ a# N, q6 @5 a( C {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
# _* `- E5 W- ?; s& K4 g# s {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
/ d4 ?- l" p! F {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},6 Y* R- W- ]+ c! r6 h1 @
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
1 k# n0 t) u- I, f3 I {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},8 R9 {) E3 O# Z% v' B
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},2 s0 \4 F1 u- A* `6 s* q
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},- b0 E6 r* N3 r, R0 Q5 R
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
: [) t' S K, I& Y, S {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},# [5 Z" m* T6 a7 G$ k
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
1 {, n$ A3 l- f& `' e; S/ r};% [4 J$ p3 ]) e! H" [* T
4 a7 c% R9 e% @/ H$ W# H- y. c2 C
, x1 s4 u- Y8 u$ M( x3 Q; {. a上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。0 `2 I- _" j2 u
( s4 z3 g; E7 AHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:. s+ w# w/ [) F I
: Z: a: ]4 M+ T0 O; H) X0 r6 M
void update_key_matrix(char row, char col, char onoff)
& P8 J+ f/ @0 f$ p9 S0 U) r4 E% p{
6 p0 w, _ {3 F6 B9 D static uint16_t hid_report[4]={0,0,0,0};
5 P, E. Z4 z' [. M) u static char (*hid_keymap)[8]=hid_keymap_dvorak;
1 m g. w. N) ~4 o1 F& K: t. z3 L: w+ R: g3 ^9 L! Y
) t9 l+ T8 ], m' y6 } unsigned char key=hid_keymap[row][col];6 q( A& r- @/ _. ^8 I
unsigned char *report =(unsigned char *)hid_report;
5 r0 _' x/ V+ e& a, y/ O8 o9 M) l char i;
- ^% J6 d0 }5 L1 P7 i
$ T8 |9 W$ h$ B4 ^% W& N
* d2 Q+ N, E% Y; Y4 E [( u3 R if(key==HK_MODE)* N$ ^, M3 w; L$ U
{
) U& v8 {1 e1 ^, N" N0 i9 H if(!onoff)
; c1 m4 ]7 F- V0 M {
& F7 X5 k; [5 `5 i if(hid_keymap==hid_keymap_dvorak); y/ g4 m& g7 J/ v! D( v
{6 `( q- S% [2 v0 f' H
hid_keymap=hid_keymap_qwerty;. i8 h! \* y F) |) O
GPIOB->BSRR = (1<<2);
( w- l9 q" |4 r( [# H. q" h4 M }3 s( j4 q6 ~' E" k5 }7 q
else
7 r) {4 h$ Z( Y! t {
+ Z/ _) J3 `* t1 b hid_keymap=hid_keymap_dvorak;
! O: l! C, `1 `9 C- \ GPIOB->BRR = (1<<2);- A/ e- T! w1 {5 \+ D4 G2 P
}7 c/ m* n2 Q, ^; ~) U- t$ y
}5 K3 f3 b/ ?2 C+ L! i
return;
" k* k+ D% [9 p9 K }
% o* c; r# Y( \" |/ ^) p+ J ^/ o& O4 l
9 I( M; ~' h1 y+ R$ j: u
if(key>=0x80) // Alt, Ctrl, Shift
) f* {7 v7 g" {$ } {2 [- Q. e6 U: V f7 ~8 n' q
uint8_t bitset = 1<<(key&7); h- L1 O# V8 N; f7 k- }6 i
if(onoff) // non-zero is key up; n$ B) u( [- M
report[0] &= (~bitset);
3 G# v x3 }# a- K( D0 Z) ~3 j; l else
- V/ R# N. @( F( l/ h; @/ m report[0] |= bitset;1 ~) B! n3 k" l) E$ M& K4 W b% w
}
3 h, h; s& C# b7 Z else
1 A* e4 p. v- V6 T5 n; s {
$ G. T" o1 ^4 N# f if(onoff) // non-zero is key up
" L5 A* ~7 N$ w {4 ?$ o4 Y1 M4 {
for(i=2;i<8;i++)
* X4 f# D2 n _: r3 W% j {$ c. {' A0 Q/ R# H
if(report==key)( n' T2 t% `1 f) f; G* r' x
{& I1 K; ?. }; d7 h2 J. c4 C- x2 r
report=0;
& @# k: f! f) c break;: e+ I( H! |2 k& Q
}
1 e1 N! R' f( [. l A( }1 b% e9 } }
4 k/ Q n1 L3 ]3 O }5 ]5 E5 C7 y+ @. n
else
! f% p9 p% P( ~6 y+ V% b {* B* d! P) O1 N- c4 X
for(i=2;i<8;i++)
0 y9 i! T% Y; @5 K I {# N, ] C# M: D2 M% P, D( o8 w$ B
if(report==key)4 @# j' f+ n" W9 s: H. m. C; f/ j
break;9 D |" ^! n+ ^! B9 o) K
if(report==0)6 A% q) o& _3 b+ ]# O2 j( `
{
. P6 H" w5 I A6 Q+ r0 M: D report=key;3 f" F, u+ R' }; O- b6 p* A8 t6 Z
break;! e" n l! r; O* b
}2 \; D0 X: T! s4 c' L) f7 w) V
}) Z o4 M$ S' J
}' A) Z4 l) L" Q& V7 B# q$ o
}
5 U4 j% [- o% E for(i=0;i<4;i++)
b7 b* y2 a4 p" T( E& C USB_PMA[192+i]=hid_report;2 B; |2 G& {: |9 x: C( z: C, Q
USB_PMA[5]=8; //COUNT1_TX
8 u7 l a4 e. F if(ep1_wait==0)
n. o2 \4 T3 v {
+ H8 q3 S' y1 \9 r( B0 ^- y. T; k6 d USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
. o8 H. c9 `/ M6 \ ep1_wait=1;
1 Y5 @ x& G$ J& I3 F6 D4 c }0 O" {5 u- t1 r! h9 E' u8 e
}, s" ^0 V2 f- b
; P! ~' P/ b* N. V, H' O! l
% u$ [+ i& D# Y6 o# Y8 V# X
完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。2 ^# b" x2 r' a# k5 k5 B
keyboard.zip
(8.7 KB, 下载次数: 6441)
9 F9 I' O6 m3 Q2 n
. S7 z) U8 V% C* v) D/ ?
t! a5 p8 J2 {# P8 ]8 z* y
3 z' _% V4 |- Z' S
3 i6 d' b2 c2 Z0 { |
|