|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 8 U1 W0 T: R9 M4 w
2 ]6 o. l5 j+ n0 z0 s4 H
扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
% U8 d4 |$ l' i5 c7 `
, @( n2 |+ `3 k; n+ l' W要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:0 {$ [, x( t8 }3 {6 }9 a
* l5 z" V8 \# q, x- g
+ D7 ~3 e4 T% U# ]- rconst char hid_keymap_qwerty[14][8]={
& Y$ [4 H( G: ?& p @& H, c {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
: t5 o9 `3 z; P% ~ {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
. ?- ]5 {1 \7 B# [" b8 W {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},# a3 R/ w# t1 W% r0 B8 M* c
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
7 E+ y& |3 y; G, U {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},; h: W' y$ [" ^( w& R/ O
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},* Z) t3 X, D2 } {9 R
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
5 ?( m& y4 e; @* b" i {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},0 ` K5 v4 o1 z* b" `% l
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
, I3 k. B O. v7 } {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
& c: B: O5 b. P+ l, }( `' V {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
6 ~ y7 r6 n: |8 @7 D$ }( n {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
1 O' o4 m9 h9 | {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},- R# V! J+ r+ y& u
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}. r: z' c) Z# A. W; d, i
};7 m! [ r6 w. P1 Y; w/ q3 @2 S: @
( B* }# `2 V4 G: Z& M& k
1 Y0 x, Y# r+ i$ Qconst char hid_keymap_dvorak[14][8]={
+ c9 V' r+ _8 Z3 r {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
* G3 `$ K; x9 X2 Z2 M7 h {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
1 c. |5 v1 @( e {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6}," b) H5 j4 G2 U+ L1 Q
{HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},, I, o `0 g. u% \/ T# x4 }
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},1 ^9 \7 O7 _$ m
{HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},1 Q) n" \1 k( {6 r7 r' ]$ m6 [
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},6 K1 P. M5 C# ]; z7 _ m6 Q9 J' V
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},/ M5 U8 H- `0 s3 V
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},7 p0 Y+ C) w4 y1 z0 x
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
( R, A9 o6 b+ P% o R( U; r {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
) t [* i* v- A: n# I' l3 x2 y1 i {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
( Z- R- ]& P/ w. M) K' [ {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},% I% L1 n5 b3 [
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}' _6 r% ^' Y, ]$ ?
};
5 [' e8 `( M+ a3 [+ }6 B
' l! j/ [* o& n0 I; \
; T$ o8 d3 s/ M/ G7 y( D上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
4 k7 K' ~$ t2 ^7 O9 Y
6 E+ ^2 t" _6 g( ~9 NHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
: y. F+ U4 h* q0 |* a
' X8 x* n$ a, o; L# q- b4 hvoid update_key_matrix(char row, char col, char onoff)
8 u) z& g P% m( f8 t$ D# L' D{
+ d# d6 ?( Z, J+ g static uint16_t hid_report[4]={0,0,0,0};3 i) y! a# w' g4 H9 r# C
static char (*hid_keymap)[8]=hid_keymap_dvorak;
8 G6 N7 ?' J3 e+ ]- k- }
2 r# D( D! r9 F. y
( h$ v7 e4 ?, b& E; t( ~3 o; Z9 ^ unsigned char key=hid_keymap[row][col];6 ?+ h: I0 p$ a$ r- F
unsigned char *report =(unsigned char *)hid_report;
3 ]& i K" T/ Z5 |4 l char i;
) V& ^: K* [6 ?. h5 W
0 \' H: D6 \5 V- B {1 e0 ?7 q
4 \, U) b; B8 n if(key==HK_MODE)
% Y6 I; F* x, _# h; c b {
5 Q" l% s8 j$ N* h8 b, R8 N if(!onoff)
! G" g1 Z% Z7 Y {
, D$ k) g5 }8 H7 n j if(hid_keymap==hid_keymap_dvorak)
5 O: V. j' k7 ` {( c- H- r$ m3 }3 y+ t" g4 _8 s2 P" B
hid_keymap=hid_keymap_qwerty;* d7 d8 G* R z
GPIOB->BSRR = (1<<2);- b! f$ B% `" Z
}
( u# P# C% v$ D' e$ h: h else
4 Y, C5 w5 u( k {
+ S8 Y& d; v. n hid_keymap=hid_keymap_dvorak;
+ B9 l1 @9 ~- t GPIOB->BRR = (1<<2);
. U4 K" W! x4 V' k G* V }
2 Z) J/ \+ y0 U# I" z* Q }! c% ~4 r0 S6 u$ P9 _
return;# n5 S- {( g. m! \: l
}
4 x. C$ ]$ z6 \9 j' {7 ^4 t# ^1 ~! l: p6 @3 A
$ T1 E2 k2 S7 |: U: U3 L7 _! W
if(key>=0x80) // Alt, Ctrl, Shift- h5 m# K- ~) p3 }0 n% w1 n( {+ P
{
; I5 _) |, D1 K+ M uint8_t bitset = 1<<(key&7);
! J' D) b/ I# A4 K7 P6 X+ z if(onoff) // non-zero is key up3 M: C. m) v5 z/ `: }) Q! ?$ i g
report[0] &= (~bitset);! L1 Z6 }! }( `) F5 A
else
/ |2 c* i+ W$ [& x1 I5 j report[0] |= bitset;
8 {/ {6 e* ]5 E4 Q* {1 d7 ?: L }
- a( e; }" _% @+ D: p" O8 V7 ? else
+ u0 j4 T- M4 o) J( h4 {* Z5 n2 x {
! q- } G9 p: t+ n if(onoff) // non-zero is key up
/ _* k8 }# S1 ~7 m {
" R" u! i+ ?5 P( o9 s" L- L0 l for(i=2;i<8;i++)
8 ^ g) I1 v3 g8 |6 X3 `% Z {
7 x$ {! M& n; v% E) l if(report==key)# @5 t H! Z: z6 d u
{# x$ T7 j8 R$ g5 P! g9 b
report=0;
2 G. C' z. W; y4 b) o break;
1 ^! `% A: v" E% n: f* u" V7 b }" i9 E* e5 ]3 X1 i
}
: e, V h" T b/ ?. C }+ \' N: a' H$ L5 V! ?2 H
else9 ` v3 q$ Q8 |+ D
{
, i& M9 L1 o7 ]2 q& O' l. H for(i=2;i<8;i++)& k/ y& [/ c3 O$ G
{- \, W) c, J( @& q
if(report==key)7 Y- n. k, E6 i5 F' [% i/ h3 w
break;
0 e4 i# P8 ` z1 a. [* f5 w2 k if(report==0)
2 p3 I) f* X: K {0 _" \$ B$ u/ f, `* i# ?
report=key;2 @9 ~+ L$ G0 m8 V( ?0 B4 G8 i. u
break;
$ a. ?+ i& L- O/ w" M }3 W* `: ^8 O0 j8 \; G {/ Y
}, w* ?! U1 w& F* A6 j
}" i7 p; b" h) V9 y( b8 Q7 E7 D
}/ E" l' f: ]' [# A$ w4 E7 N& |- P
for(i=0;i<4;i++)7 |6 a1 a6 l2 k& E& l
USB_PMA[192+i]=hid_report;+ {* z5 q9 R5 W: ~5 A7 _2 r. h! J6 M
USB_PMA[5]=8; //COUNT1_TX. c" V3 D# n3 Y6 m! y, d5 P
if(ep1_wait==0)
( A' a1 _0 L- Y/ [/ k% s- O3 Q# ~3 @ {9 p' A$ {- ^( q' L# \! j; [
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
/ k1 x1 M x; y$ v H ep1_wait=1;
8 ^' Z( a) w1 H- N+ m8 [$ t }
1 {$ K5 w% d8 O( v; Y}) V, H& K* E( P
. D6 M N$ W8 j2 j% ?/ O# l- }/ N3 `" g5 X, W m( A0 k) p h
完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。
) Y. ?6 d& X( Y X, ]- l
keyboard.zip
(8.7 KB, 下载次数: 6011)
" j: @& W( N! F: B7 U5 N) C2 N6 n% k
$ C' Y2 d! l+ y; K4 [
* |+ A6 ]( b+ E0 x' e1 K; x$ N! Q, q# Q) K3 \/ _9 |$ L
- _$ N% Z+ v9 v) n/ E3 C |
|