|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 " N j, I, H& x
8 l, |9 U( H3 }" `扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。. Y7 f+ L" J# l7 R. O
6 e9 F5 I2 Q- f0 @! ^4 H- D* o8 u要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:" L e* C4 j; d8 K7 D
A% l/ s+ v! ~; f' S% g) r
1 x8 [0 v: q/ }1 S i+ kconst char hid_keymap_qwerty[14][8]={
2 {) _" U8 u } ]2 \1 O" U6 e' c {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc}," L% P& h$ Z3 E5 M f4 `- ~ w
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
5 Y2 `1 K; s0 j7 L7 S5 l0 f6 k, O {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},$ l* q( b$ L+ v3 P" Y4 K
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},+ r; p0 u( L7 _# g
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
4 F. L/ H6 y) \0 V6 ^' f {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},, ]8 |* a$ I, [8 s0 O
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
# \: R4 y' y. d, g- A {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},0 e) e6 v, Y/ |% c1 G' |% S, M$ L
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},; y9 s4 _* Y% ?! a, |
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
4 H) u3 }) g. H {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
2 e% k- i' m$ ^; F, M2 C! w {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},/ ^6 E( ?( y F
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},; A9 o3 l; o, Y5 u. M0 E
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}( s+ }0 u: Q1 ?4 b3 M) r/ ~
};, a6 W! }) W0 k: _8 \
! u3 |! c0 l! w( W* w+ l4 }" s! o; w
, r `; f% n" v8 u) p+ d/ Xconst char hid_keymap_dvorak[14][8]={
- ]3 ~2 m" [$ G% X8 u {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},& ], G1 f% A* e$ G/ k( Y
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
$ h9 J- N6 U9 @! T0 o {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
- Z- m2 D" W. @" q, {: x {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
4 ^4 i% w: L' o P9 u {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
3 \6 b8 c4 K! s' h9 l4 f& r {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},' F/ b, k5 L$ o7 |' C& q7 S3 u4 N
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},
- \! t+ t3 j- w7 C9 P$ m5 G* s {HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
/ w6 }2 v/ z: `8 R3 ^ {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
# M! P( T7 O$ i3 D2 J {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},6 y3 N& d3 V0 [: d
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
' X% F1 T0 T! {) ` {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},; t5 @# v6 k. z/ Y7 }3 i: `6 p
{HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
Q ?: C- F5 Y* { {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
. m- M; O3 X9 p1 u% R};- q0 e, z% h! _& p J$ h
" L% v( Y/ Y% W: V8 t3 p* M' H$ Q: Q @9 G! B6 S( c
上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
. l8 ?+ @% H) n" I7 v7 A. n+ u6 T% `: Y
HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
: S2 Y- a, T" C5 @ H" F* {' g) F& R' `
void update_key_matrix(char row, char col, char onoff)- r/ L% f0 U) A
{
6 g" F2 O: O: Q7 U static uint16_t hid_report[4]={0,0,0,0};
8 [( W8 v* A: R1 f+ k. y. l4 Q static char (*hid_keymap)[8]=hid_keymap_dvorak;! m' X. T7 U/ C J8 u- q: d
6 F% X: D( V! t4 b
. z8 M$ M) @0 E unsigned char key=hid_keymap[row][col];
5 e( \7 _. _3 e+ ~+ @8 | unsigned char *report =(unsigned char *)hid_report;
" B" ^+ S# |; U8 J* ~1 e char i;4 a. x2 A$ d2 z3 M0 O# P
& W+ C. Q. C( j _" f/ q' T, n
: u* x7 q& G/ @9 l2 |+ z: k+ N if(key==HK_MODE)# o# h8 ~7 U ^( H
{
* x0 x: H" \8 p, m1 d if(!onoff)+ l# X3 U) k& s+ {7 J
{
& ?: _6 y& B) g: {) K: m5 J if(hid_keymap==hid_keymap_dvorak)* J' ~+ l# ^' n) m: f4 b9 ]: Q
{
& p( Q5 a6 e9 G( I1 I hid_keymap=hid_keymap_qwerty; v) p0 R+ x ~ I/ x, m' X
GPIOB->BSRR = (1<<2);- X) k% ^" @. U0 v' r2 L% Z$ d
}
& u$ S' B i: N8 p8 x% v else2 U. ]# Q5 w* i r9 I2 s
{2 a) o/ K8 o4 F, U/ Q
hid_keymap=hid_keymap_dvorak;
4 L1 H& n3 C0 Z. F" g# R GPIOB->BRR = (1<<2);
6 @/ d' C' s- G3 [ }* m C( Z0 r, s
}
" V3 U4 ~9 G* t return;% M/ t! ?5 Y9 {- ? f
}
) A2 L! ]( ~9 ^9 @5 V9 A$ C) o' ]* p
( F+ X% k; V6 t% m3 x if(key>=0x80) // Alt, Ctrl, Shift
) d7 Y2 J$ T3 H1 A4 `) L4 ^ {9 j: u7 V1 m6 X' {/ C% r8 ?4 N* s
uint8_t bitset = 1<<(key&7);6 G$ m( L9 V7 A3 }2 J" [
if(onoff) // non-zero is key up
# q5 _) I2 R, v report[0] &= (~bitset);" J7 @% C/ _8 _. g( q# u
else
! c! V0 \2 b6 Y, o report[0] |= bitset; c+ m5 G2 L3 x$ ~) }6 t
}1 \0 k: D& J {
else* ?/ x# t7 B: L2 \: ` v
{9 `* \; G' H; w1 _# z3 k
if(onoff) // non-zero is key up
$ r2 |6 u9 B; w. U' v {
9 t6 y. x" P9 i for(i=2;i<8;i++)( w/ {0 d4 h" f2 g" I, A2 J
{ t* N5 `: x& u. ^
if(report==key)% l) W2 B- {' b4 F
{
# E% k) A; F" K; o$ U, J report=0;
2 ?7 f0 m3 X; S) g; J' h break;
- P/ [1 P) o: B }# f8 F% n+ [' C* j
}
6 y% c0 A) C' ~( M, ? }- ~: j3 u- s9 v/ X# X" n3 u* L
else3 d' p5 q, T; O' c. x1 E* Z
{
0 N3 k& J. O* ^1 |# P/ R# f for(i=2;i<8;i++)$ q2 ~+ T, z+ K4 ` Y8 C
{
8 \0 s' h, S% V+ E if(report==key)4 A& C( ?8 t/ m. ]' ^6 {
break;2 N5 @; r: z; c( J
if(report==0)* ^- s8 ]3 g' k5 U2 A9 [
{7 ~& W* T$ i6 K+ i& T4 ^7 M) L
report=key;
# ~7 E% h. r% o! a) H break;9 V$ Y; n( i: B7 }$ R# B& b: u
}) p! Y1 h" n J4 @+ y% |' O
}$ Q7 q* q7 B1 V6 ]0 j2 S5 |
}
- u3 f/ H( ~6 a* ? }
6 Q1 u) F3 [3 I1 M1 N0 \# u, U for(i=0;i<4;i++)
+ b- i8 R+ z. H6 F$ m- j USB_PMA[192+i]=hid_report;
* D6 W9 c! k, K0 _9 J+ h9 U9 t USB_PMA[5]=8; //COUNT1_TX
' I4 w9 a& k. u8 u5 t! r! i) ? if(ep1_wait==0)
: b8 h( K- h' @0 Q3 P0 }3 n {2 Y3 j& ~/ T) p
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
' ^. m: ]* W: l# O' P" n+ W ep1_wait=1;
$ P8 C1 K5 e% v! P }
/ N ~& i! i9 r' ?3 a}. ?; g3 @9 t, c" O: e1 j& \
1 m- N9 p( ^6 x6 P( w/ R
. E# b& ^1 h: \ \完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。! o6 g: A" f2 C: `8 s
keyboard.zip
(8.7 KB, 下载次数: 6420)
: n/ V; g3 ^$ E# e1 d
$ g: |9 p: ?( \% [
y2 o* c" O( \: b# c4 N- E4 D- |- e. n$ u7 k* G
% j) Z0 F8 x n. H: E { |
|