|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 - w) M/ H b, Y
( n4 p0 w$ D s) j+ H/ i9 W7 L扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
8 }+ W% Q( |6 ^+ D& y" i
D0 m6 p6 L t: d% X1 B" I; L/ f要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:
" J; w; E' o0 }/ I. P8 F2 A4 ^1 G* [; L, z" G0 k: r# c9 u* h6 e
3 b+ @; z/ h1 V4 F) Y' `+ qconst char hid_keymap_qwerty[14][8]={
5 w5 V L& ^) ` O1 ]3 A {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},% f' g1 d" h& t# {# f0 A) Y: n
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},( ~9 ^2 z$ {& c9 _3 {( x c
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},
+ h. J- C) b B) Z0 k B; Q {HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},; I, K7 M( {5 S5 H9 a
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},( C( q; [& |) L
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},; U) D7 l: j+ g. V7 @6 a' s
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},/ n% g1 E( F- M) O4 s
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},1 ^3 Z! G! m# _0 k& [
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},9 q e( Z0 ?/ q( w& c
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
: p/ L' }* D; r4 @& t+ i3 \ {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
* h4 ? o8 K+ Q* O {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
% f/ h O; l: ~! k7 h1 L {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
2 _2 S( g) {" z2 ?1 u/ y. r; W {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
9 O: s* `7 r6 f' F; \};( `! L5 T" [4 k; S8 }5 L
! |: ` m) f; I1 V
1 @8 g: B" a* j2 S6 A5 \& yconst char hid_keymap_dvorak[14][8]={
& b* _# U2 D1 d4 o8 D {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
" ?, P7 M: e! g {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
; d) |& O+ e5 n# Y; i$ u/ l {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},3 r9 n2 s3 d* N6 J& Z
{HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},! Y7 R' M7 i' w' D8 b5 g+ K/ Y
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
' w+ e4 `1 Z/ T {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
$ @. V: D& q! }) {# B3 f+ p {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},
, T" K F! }. g1 w$ P v" C/ Z2 k {HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
! d9 d) V5 U5 j) b. K, U {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},' v2 v2 `# O& r. E4 a% _
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
* o, q5 Q* R3 k1 M* ^; b0 n5 y# V, G {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
' C" Q6 ?" ^& c6 ?5 O8 W {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
; M& X- [- ]' O% _" ^ {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
9 L$ s6 V* G# M. i; X8 \& p1 ] {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
- a7 _3 `# j5 ]5 p! x& R1 Y& M( f3 S0 b};2 J- W7 n( }3 O! K: D- L& E4 a5 d+ D
) @- O4 b. m7 E4 a# y
% O0 B% Z% v# I% H' r4 d+ l上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。* \, E3 z- }$ O2 [' y+ m& @( J
, F% E% P- V6 B& M$ z CHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
% Y) F+ h& _! R% [9 Q( _' {, f' [+ C* O3 Y ? B
void update_key_matrix(char row, char col, char onoff)
( b! y3 B/ y$ Z' f# l: U8 [{1 |, y. L6 k9 H& J- V7 }9 m
static uint16_t hid_report[4]={0,0,0,0};7 \( X7 J8 `+ n- h" I
static char (*hid_keymap)[8]=hid_keymap_dvorak;. |9 N Z+ K4 H
) p+ @8 v2 z2 v) g9 x" H
; q7 {: B: h) T( o C2 \
unsigned char key=hid_keymap[row][col];, {/ r6 ^/ I- O
unsigned char *report =(unsigned char *)hid_report;" C- a1 U5 {- I( }0 w% J
char i;
& t( ]; C- y* X# j# q& h3 t7 ~( J
+ b' N+ W# o" X# @+ X7 M* X: q
4 n1 G: N- _+ v1 M if(key==HK_MODE)
* I1 Y2 w" M/ O+ C8 e {! k, q+ P% J7 \
if(!onoff)0 X8 X1 L7 R& k( m, @
{2 c2 ^! B; H2 v' d8 ?
if(hid_keymap==hid_keymap_dvorak)2 Q1 y( _9 \+ j% I0 l; g8 {
{+ M" q5 X9 X f# C+ P8 Z. m! p
hid_keymap=hid_keymap_qwerty;2 q9 H3 V9 x* I8 K1 }1 T
GPIOB->BSRR = (1<<2);" F. Q3 ]: z5 |2 M
}
2 Z! ]2 |; s$ |. b2 U+ c; m3 R: ^ else8 E5 k) Q/ J" N6 Y4 f
{
, F" ~6 A- L' w# ~6 a$ i3 v2 Y hid_keymap=hid_keymap_dvorak;
0 p7 `1 r, M4 G N& c+ j; y' k3 N GPIOB->BRR = (1<<2);+ i$ i, S& t4 P& b* k& l' B6 P
}
_: H( B( j- U! E' g }
# l* d/ E. X; Y return;
; {; ]$ O5 g4 r }% D5 U9 k$ _# j: {& J6 D
: ]7 c7 p2 g8 r, [ @7 z( m: T' s% i4 T {. q
if(key>=0x80) // Alt, Ctrl, Shift" c" e+ N, p. Z
{
- e: S/ o Z1 v uint8_t bitset = 1<<(key&7);
- _1 J5 I* K. e! q0 _- M/ \7 F if(onoff) // non-zero is key up
4 M* l9 b( g1 c' z" a report[0] &= (~bitset);. ~" f% @) x. L6 B$ n0 N# R
else
1 P. P' e; t* _3 T* U report[0] |= bitset;
+ d' l: W& U' s }2 Y$ ~: Q$ [' i4 ?
else5 t. ?+ l. g+ H6 @
{" G7 ~5 I. A4 h# Z! @: g
if(onoff) // non-zero is key up
0 ~1 U, |( w3 ^5 `8 g; v% D0 Y2 | {
) j* e% f% D, J; u" E for(i=2;i<8;i++)4 I _7 N$ Q o; k
{$ P5 i4 y7 ~ c5 s( s6 T
if(report==key)" T* u/ n( |8 `4 b# Q
{9 A2 E* F* O0 j: W
report=0;0 e# T6 j# V. N( X8 v, _/ P# }
break;
) i0 O4 l# p3 |$ {8 Z }; h; Y4 |& Y) \; v5 m4 F) l0 x
}
4 E1 ~7 {+ r9 t }7 a4 ]/ a+ c1 C2 J$ t
else, {! s( r( {1 S" c. a* t
{
4 k- _+ `/ G- _3 [) U for(i=2;i<8;i++)
5 T2 K0 c, Y+ W {' P! A& j- ]& P/ M' V2 t6 b( j$ J
if(report==key)
$ _+ z8 z5 M- \7 B6 { break;
1 V. c" q; \2 m, ~- L& w' _ if(report==0)
( f4 t( p3 A- V. B V/ L7 q( b y {8 @' k! M" ^) {% a
report=key;
$ h* R& q1 a4 l5 K: w break;
4 ^7 @( c1 D- R% y* K5 J }
- e* Y* f) ^. @3 t* q: |1 f) @0 v! a }
/ z+ w6 P3 x, t- {6 A6 w }% d1 i y+ c x1 B/ z8 n
}
& Q/ q0 y, A& p2 d$ b for(i=0;i<4;i++)
( }- [+ ^& x! P: [. q5 f USB_PMA[192+i]=hid_report;: X! Y f; G) f) G) L( [
USB_PMA[5]=8; //COUNT1_TX5 `9 m- B6 ]) y4 \& F# ]5 K @
if(ep1_wait==0). w8 o7 s: c, ]5 H/ w' U; h; h
{
* |# {* Z+ G/ s9 z USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
$ l2 r% a& w4 i9 E ep1_wait=1;" A& w7 s& |5 Y. b. Z
}: S4 F/ S$ e8 g
}5 @6 n. Y) B2 ?2 c; Y9 u
$ V* L, w) S& g) N( w. Q p
& q8 `) V- J9 d: C完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。( x1 g4 f1 f& T1 Z4 v
keyboard.zip
(8.7 KB, 下载次数: 6581)
' u4 `% f0 w1 d5 `9 B7 n( l
8 P( V- `! R J! s
& f* U7 z+ Y* ^, q) B- u# [, W, a0 O" R! w9 p% D8 v
3 S- a! \& ? n' u' ~
|
|