|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 * O$ l' y5 R% o$ f8 {0 |
2 c5 \' B. z/ ]- _1 t: x扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
0 A2 b% G6 w+ `- j7 D% n6 s) e
1 ]4 p2 D( C% x要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:, f0 k8 E0 ~+ B, h9 a I& u
1 p C; F6 r4 ]6 K5 k3 k( c
' N0 @7 y5 n% [
const char hid_keymap_qwerty[14][8]={
$ t: ^2 G% k/ ]: }& { {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},' O. s' T' e' l5 W* Q
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
y3 O" i z: y4 }4 [ {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},. r6 ]# I/ Z% K. f0 m
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},( A v/ W9 t& c& T
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},& A; y- F/ h& l
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},
" c0 z0 }( O( S7 } {HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
9 P) J: q5 v, D {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},0 i/ A& @& f" _' n/ D' ^4 W- I' Y: g
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
2 L8 s" r- ]( ?& w: ]) L {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},& o2 e6 ~3 Z& R7 N! w
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
5 ^4 s) M/ u: k5 D/ _" C, X {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
" t" i( v1 b7 Y; F {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},% X% h" p+ w$ T+ U0 V9 I' p
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
. X5 ?" y0 @: X0 G# T. }- h};7 G) ^4 X' N. b4 U7 o; T
' ^" Q" i' _7 P4 d% y: U
2 `- ?* p9 d9 C+ K1 p0 }const char hid_keymap_dvorak[14][8]={! N: _: c7 U. d# Y! c
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
- o/ ]6 F+ C. P! ` {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
# @! @0 x7 n* m, F5 Q+ ~ {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
& a% V2 Q4 N N8 P6 \! _# p) } {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},, m2 e( b( e. e# Y5 R. m" r
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},6 j8 n( c0 R9 D4 u, `4 a0 Y0 f: d" g" p: `
{HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},' h: u3 w+ J5 j1 x; y* e: H3 v, h
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},
( K- V @0 M* P/ z) b9 ~ {HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1}, u1 d9 U \ p) `' p
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
8 O2 Q* ~5 L8 [. r9 [1 q/ k \# @ {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE}," o6 |' b" O! i0 n7 S' I
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
) r7 h1 B9 y8 ~# u% ` {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
; Q2 _7 Y$ K3 K" r5 N {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},' t8 ~$ @& u) D( y# H5 G+ S
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}: r+ M( W9 T; X; X
};2 }+ K* ~8 `. e3 C6 e
7 z8 t% r7 V6 Z* @. J) w; _( x2 E( E
& |, @1 I; g9 Q( ~# l. J上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。5 H1 H/ t5 X9 h
4 _+ R% {0 R3 D* R" H- HHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:5 e2 Y% Z0 L6 T/ a$ t8 n% p$ M
9 W( x/ a7 o- o* evoid update_key_matrix(char row, char col, char onoff)( F! @5 Y) J# c' D( N+ e! `
{
# g: n* o7 y' O static uint16_t hid_report[4]={0,0,0,0};
6 { {) x; q1 F: |+ K1 B static char (*hid_keymap)[8]=hid_keymap_dvorak;8 R/ U0 z3 b p& y! ~) T
6 o. o5 C0 w1 z7 q" g) K, J6 c! I4 i. p$ V5 L, m
unsigned char key=hid_keymap[row][col];
8 W9 e: K/ A9 k unsigned char *report =(unsigned char *)hid_report;% v- T/ t3 Q0 s" Z0 B
char i;! _( [# R( O& C) T
; R1 g2 A) c1 [; d2 p1 \
, T* O/ I$ R( W; |6 l, L% `9 U if(key==HK_MODE)
6 i4 }" c9 F6 X d {
( n e% V, z: L) ~7 L! Z if(!onoff). h8 h. P4 O, k4 y% b+ @7 k
{& a- s5 h3 u! C2 g. ? f- v
if(hid_keymap==hid_keymap_dvorak)
$ t0 w# c, d( g) i: \! J {. h3 t" q: ?( O/ [
hid_keymap=hid_keymap_qwerty;7 ]( Z1 x4 V+ Q# P
GPIOB->BSRR = (1<<2);, ?) q" p# m d) F6 ]6 s) e# |
}4 @& G' K9 g: f1 _4 x6 @
else
: G8 K! w0 H4 }% S {
" Y, @# X" y$ G* Q hid_keymap=hid_keymap_dvorak;' R( |% r- Z# C- |# l
GPIOB->BRR = (1<<2);
! N- b$ A9 c( U& r! u1 N }
! B6 M3 X6 X+ k8 y# H" v6 R- y" z, j }. C# e% x% Y& v. J) q9 p1 A
return;
1 u4 i& f# M% M6 n% |# e }
- P' Z2 g* t8 t6 a( `( r! Y( `2 d1 E% [
# R3 F: F) \7 ?% { if(key>=0x80) // Alt, Ctrl, Shift
, y$ I. ~4 A/ i/ i$ C# r* H {* d b- h! v$ |% |. o( p/ W6 m
uint8_t bitset = 1<<(key&7); b8 M% _! T! V9 A; q
if(onoff) // non-zero is key up
, w* s. J" k3 S* f; W2 M3 z- i report[0] &= (~bitset);
* h# k9 Q T, ? else+ W8 ]+ I( b% M$ `4 w
report[0] |= bitset;
+ W4 M+ q5 L, w- l }
6 q7 Y5 N$ B: x+ [ else# H; w4 c @! R+ h0 ]7 q
{
! U4 j! u, ]* ^ U9 x6 _$ C if(onoff) // non-zero is key up
2 [3 m% \6 H/ B( F {
6 i: E) m! L; Q. R0 ~9 [! r for(i=2;i<8;i++)) {' E6 w, C5 n8 K" H
{
; k5 s! F2 W" l. | R) [4 G if(report==key)
% J5 w+ x$ ~ I. [5 d {; a9 {/ a+ H1 w4 [7 y8 I& K! d
report=0;" q# R+ k% n& T) r' c3 a8 O4 C6 M
break;
# ?* G$ b" o3 p" i }
! }, |# P' o8 \( \1 n }2 h4 Q9 l8 Q8 ?1 l# P; o# `' y* L
}; o; `! h% Y; P0 |" F
else5 @, J$ t% I0 @" N1 Y
{. x1 _( a, n2 I& f2 W. T
for(i=2;i<8;i++)/ B9 X4 e. D1 [; R) s5 z+ D
{
; D" I3 j P; a, D if(report==key)
" `8 A! Y( D5 R( m" B0 e break;
5 A5 ^; O0 h* |: Q, R7 [" f if(report==0)1 D4 A. F; W& l) u
{$ E% `! j; U0 M( p
report=key;5 t2 v4 s% f1 I' N v
break;
' I+ t% F( g4 K$ q7 m }
8 R9 o9 i& `3 n X$ M8 l2 g1 X, t }
0 C0 F: @4 K) w9 C Y- ` }
" ]1 @" P& W9 C* g* u }4 _4 r! S+ {0 R- p; S
for(i=0;i<4;i++)
* b) |1 q1 B2 K; R1 t% Q/ B USB_PMA[192+i]=hid_report;5 a4 D* P% H8 L) Q& L I# g
USB_PMA[5]=8; //COUNT1_TX
. c0 s" g" D7 t. E if(ep1_wait==0)4 `0 Y& [) V* O a+ f0 j
{
4 `( j) c% a1 s9 N; W" @8 ] USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
" i3 l/ F ?- K S7 r+ u ep1_wait=1;! c5 ~! h/ s! {% U& S
}
$ R: t) k7 @" V# p+ I3 N) \}8 U! J" U7 u% C' w
0 [( b. T5 T" _" L8 x4 w
! V; X8 m9 G% o3 K( I完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。
7 f# a& `9 x" I# D0 {$ g$ ], g4 a
keyboard.zip
(8.7 KB, 下载次数: 6189)
' H8 X: w$ B8 |, x# L, r3 [8 g3 a3 @- p: `, U1 p0 U4 W
5 V# m! {( W% a5 [2 q% m. R
' G5 A4 y. @6 l+ b V% E6 \; Y: b) |9 }6 U( O
|
|