|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
: v+ b0 t/ ~6 B" B) ?/ `+ P5 b9 F& T
扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
5 A8 `" J9 i/ P) S |/ N {5 o5 T3 {' ]: O
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:
" U) x0 b4 y. ^
% K/ Q. n! f$ w% P J9 \" i1 I8 V5 z7 L( f6 Q" }/ z
const char hid_keymap_qwerty[14][8]={
: s0 J) R) m% [$ ` {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
/ q/ J* o- f7 V$ @( R+ W {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},$ q( R, Y3 U5 y8 m% f/ h
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},
% i( c- ?1 V- G- g {HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
; n" j7 }" J. X% I2 N+ T7 J {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
* G9 R1 m, V4 H! R, e+ a% s {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},, X% C4 Y7 v- S9 L9 ^
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},. U" b1 B9 ^; r5 X+ ]
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},: K) Z p( I v* c
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
' C6 [7 u# M, e; q" | P6 t {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
. @, F+ Z1 J% [, w1 x {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
& u& Y; i; ]1 P( b {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
1 n/ Z# D, { [' J5 g6 q7 ] {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},6 R- Z3 A# }& L# o. C
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
* N& j, B7 n) B& R};/ S6 u* n, A1 A# x1 A) J8 C i
7 O: z# _+ N7 a( B4 u
; p. V2 o0 ~1 _1 ]
const char hid_keymap_dvorak[14][8]={8 ]6 o5 K* L0 {+ H: q, m
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},! c. V, S: F# L/ n8 |
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},% v+ u8 \1 _3 ]# V* B! J
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},# F% }! L% ?) r! W+ `
{HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},/ g, U$ g5 O" {. N& x
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
/ k; F! ?& q/ X: @4 E& i {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},' W* w Y. f. I% [) O9 O
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},
. [) I- u& {0 i {HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
5 ^6 v0 |7 B+ u$ f) F {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
, e, U! U0 l/ B3 R: ~9 h/ A; ^: h {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},- m$ o/ `" X G. t) r3 L, b
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
3 X$ ?2 `: ], G {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},3 R0 J* p* g; i6 w5 V
{HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
3 w, J' s6 Q7 Y" V; P {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}' l) U/ M+ c+ ^, U& f, G
};/ O4 d/ h! q$ p: F4 {$ z# F
* e# d: b4 q7 e0 t8 f
( v; S$ G$ W I: T: o4 @# F( Y9 S
上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。( a( W$ w' Q' u! \ J) Y( R
5 d! r( Y& C9 {" A: ?' `
HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:2 C2 o+ I% h! K+ s
8 T6 c( }3 @3 U- z4 ]2 y1 rvoid update_key_matrix(char row, char col, char onoff)
: |0 m! L7 `( {{# M. r" Z# _1 x' U
static uint16_t hid_report[4]={0,0,0,0};8 h% l" E: K! ~: @
static char (*hid_keymap)[8]=hid_keymap_dvorak;' J6 t4 }$ M3 @( a9 ]( j" ^
. F9 z. o' n5 g0 e' x$ n7 c
' G3 S6 r, N( o; |! Z unsigned char key=hid_keymap[row][col];" \9 ~+ f; N9 _
unsigned char *report =(unsigned char *)hid_report;" [( C4 i: Z7 O: g! D O& U9 }
char i;
2 K3 T* L# l, q+ p Z
7 U. U X4 i3 V, t
+ d2 X3 `8 i. ^7 e2 X# @0 J if(key==HK_MODE)/ X. a/ v r6 L3 C8 t9 a
{
/ W- D/ M8 Y( a; @* n if(!onoff)1 V5 u# R9 Y8 o4 E
{% a, b/ q! R: @9 |6 O, [7 G) U9 T
if(hid_keymap==hid_keymap_dvorak)
: e/ R0 Z1 d* { {( t! h# k9 A7 {+ E
hid_keymap=hid_keymap_qwerty;
. t% H/ T1 _! d A. p) c& b GPIOB->BSRR = (1<<2);
% V+ z) Q; n. n. I7 | }2 a" H# q3 h' N7 q& W
else$ I$ H& ?0 h) U& d5 D
{& w B& ^( B: |, ~1 ~
hid_keymap=hid_keymap_dvorak;
. V# G- e; j" ?$ B! W GPIOB->BRR = (1<<2);
0 G+ c. T3 y; P' {5 N L" M }8 p' I% O4 Y% U
}$ t; Z# a! f' I" y- Z$ y' V! _
return; [ @. Z: l" A3 f$ U$ {
}
9 n1 N( g9 z* {4 x$ X
7 N* L& B' ^+ d4 z
3 M& G( ? @7 [. d5 v if(key>=0x80) // Alt, Ctrl, Shift
' s% ?& V5 G) @ {
3 K, d+ N. f% C, M8 M1 b$ P uint8_t bitset = 1<<(key&7);1 `' L8 O0 \1 x) ]5 F
if(onoff) // non-zero is key up
0 K# R- }& O; D. B, p report[0] &= (~bitset);
6 W( U/ Y* V+ C- ^ else. D# _# L* A/ \ t
report[0] |= bitset;
# H' g; a8 l; x }. B }9 G, |* O. S
else* u" \6 D7 J" k, F( w
{
) D: Q" h$ r4 x; L) W1 r0 X if(onoff) // non-zero is key up
9 l7 o) V, F# S1 _ {5 c3 b0 N: o/ H' v" u
for(i=2;i<8;i++)$ T5 Z2 R& V2 x
{- I2 d$ u; W/ B' i2 }) T
if(report==key)5 {2 U* O; x+ Z' i; i
{6 ? m1 d. U- I0 _7 c2 l
report=0;
/ U+ @, @3 V1 n: H* i- l break;
' _) ?4 p* d. D1 | }
/ U+ }: Z$ F+ d6 f% I. u }4 |9 s1 [" T3 E& e. ^% A
}
. Y9 ?" W" p8 d, t0 o9 O else( s7 S7 Z7 @5 b, t1 g) X
{3 ^& U/ Q7 \& E, g9 H! p
for(i=2;i<8;i++)# z' x% t) f5 P$ [" I0 S
{+ a5 X7 J' |- `4 ~8 n6 a6 ?9 @
if(report==key)
& Q7 v3 D0 p4 I. U( k" F0 |; B break;: ~6 H, A2 U! E2 ~+ _
if(report==0), Y& Q1 R* z4 c: t6 ~+ q
{
1 ?5 s- ?" q8 M report=key;
! n2 a! c0 N6 j g+ M break;: A2 |1 ?: ]2 I. r9 R, s- c
}
( R% m' f% Z: M) N. z" v6 Y }
' y9 C9 @7 K6 r! m; R! R }
& F3 E" C1 b4 j( T0 j+ j }
/ g+ m4 o1 X9 ^7 C, a4 T- E3 f for(i=0;i<4;i++)) J5 B0 C- _4 \0 J
USB_PMA[192+i]=hid_report;
& h' Y5 H7 |( L/ t$ p USB_PMA[5]=8; //COUNT1_TX; Y! A8 A0 x4 u
if(ep1_wait==0)* I% A( @+ V# j+ J# h
{
# Q) F R' L6 c9 v! ~2 }' H* L. J USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
- o3 t% S- _# Z ep1_wait=1;: ?3 e5 F( A* M
}1 I: P/ ~* S) h( x* \
}
V3 K- s0 `+ p3 r+ z& L- ?. I0 @
7 E; J( H. G, x+ P& U6 f
完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。' u7 Z% [8 ^ l; U0 f( N% d9 n
keyboard.zip
(8.7 KB, 下载次数: 6075)
2 U# m3 O9 Y8 ]8 g7 v
$ r7 W$ K% W; ~) k
5 z. B/ v# s- l6 ~8 [8 k9 U- K4 n6 K8 |3 W3 ]" H
b9 W% Q" R# P; ^/ ^0 K+ g
|
|