|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
. I: }' X% r% U; i# a# t6 T. Z" c7 {
扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
* E5 O* W9 Y" y! A% {
+ P8 \+ w% S2 ~* Z0 ?要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:9 ^* B& \+ U, U8 y/ t- c4 m
% j. J6 A, @, \' U9 H
& H9 U: g6 T3 y7 p4 B, D5 R/ M7 [const char hid_keymap_qwerty[14][8]={6 G9 Y8 L+ \+ s# L. r1 ~
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},' H0 U: j- c7 u2 O0 i, g6 f
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
9 E' I* }' _; \7 @# I d {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},7 g9 I+ p# S& @
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
8 Y* d, [ C& b7 f% U7 a {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
. n& {0 Z9 c6 o {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},; e# q$ M7 A! |) ?7 ~8 ^ k- W$ E
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},: _( f9 J6 @( r% N0 |8 U0 c
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},7 D- [$ t' x0 b
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
! l: Q: F; h8 ~* X5 M6 d( R {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},0 N2 d. v, k" ]6 I! @$ ^1 k& s% ^) Z
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
, Z- K5 _, B2 v! a {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},. T0 r2 [% o1 Y5 P5 P
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},4 A0 G. N/ T- x, T$ i
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}1 q# V x$ Q4 U+ f1 ]
};( M: Q6 W. Q% s! n' ^
7 g3 Q3 v, e3 R7 ~$ ~- O7 r p# ?" {( C& Q8 N' x5 r
const char hid_keymap_dvorak[14][8]={, A7 E4 f: o! c& O
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
: i* O' [1 ~1 K7 S5 A9 b7 D7 R5 i- W {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
6 x* k. C1 C5 a- y5 w {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
: K8 s* W& r2 g( K* r {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},) H5 P0 u, Q& I, F
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
! q9 h; y7 U+ P {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
1 J/ z8 `; U0 d! P0 V0 J {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},- j" F0 E1 X9 |$ l" ~: h
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
( U1 q5 k; }- v; f2 x {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
$ j3 T- l# H9 Y# U {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},4 q l$ b V/ {" O) q; w. I9 a: \( C
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},3 k# M7 }0 O/ R/ l) m2 h' Q! x
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
3 \2 B0 S* {; W& u# t {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},- E1 k, [1 E: F. c5 ]' P! W
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}2 d5 `% K; v8 T p5 e
};
3 n d B0 I [
. H1 j) q* W6 N o8 b4 W0 e
2 H8 l) c& ~& R0 t上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
, @, a9 U) R: h7 A- X# r/ N0 u/ Z! q+ v
6 l4 d+ P0 {$ U1 X' J; `. }4 D6 dHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
+ ?; G% N* n& r5 ]6 }: Q8 D( @4 a
3 m' l, \5 ] q; v. A- ?4 Cvoid update_key_matrix(char row, char col, char onoff)
1 `$ W( L; ^/ P& J' L" x* s+ m2 a{
+ U) O" w0 Z. E' |5 i* I3 m6 F static uint16_t hid_report[4]={0,0,0,0};! S7 x0 \0 |4 i E) b
static char (*hid_keymap)[8]=hid_keymap_dvorak;4 ]/ Z: B6 Z# y, F0 w7 [/ w- f; I
" B2 `+ c! @, T! ^ W) e( Y5 I* J/ L* R0 L1 Q9 |. f
unsigned char key=hid_keymap[row][col];2 Y' F8 D* T" E4 ^2 ?) x, _5 C
unsigned char *report =(unsigned char *)hid_report;
9 M) h- I6 \' c8 U, \1 Q+ h! G char i;
' Y, N* X% L0 ^/ J) M% h
8 B! B- l2 @3 t$ O. v/ {5 z- E& @4 k4 u2 C& N
if(key==HK_MODE)
' E: Z1 l% H6 r {( F }5 p/ ^% G- {0 U
if(!onoff)
4 K7 B1 V2 h( m {
' j; H# f5 }# G3 w if(hid_keymap==hid_keymap_dvorak)# W# |/ A/ n$ n3 j& T' P# g* m
{& L& J3 E* ?3 a' ^; I
hid_keymap=hid_keymap_qwerty;
) c/ d! z$ ^$ L0 B& _! g+ A/ x GPIOB->BSRR = (1<<2);: L5 w" h, e( j
}
; S+ @; ?) V& h3 e- ?9 E% Z& z else
6 V( k P/ e- m- O {
& `' o( I B. l2 F hid_keymap=hid_keymap_dvorak;0 U. n& |1 }9 t- Y, b" C
GPIOB->BRR = (1<<2); I) K1 A+ w' f8 u9 e0 {8 u
}7 v( ^8 d; |# @( }7 U
}* ]4 A1 y/ I( A& G8 B# |7 m
return;( P# ~2 M- L2 d' J! g
}
$ N# t* l1 d1 b" ?8 H( ~
; u: a3 n0 R( k4 k" F
1 _& D5 B& a# _* T' S" ^0 ? if(key>=0x80) // Alt, Ctrl, Shift
3 @3 P- \# \6 \ {
. ~5 L( j, z3 \5 I uint8_t bitset = 1<<(key&7);: N w, A9 A6 {+ U
if(onoff) // non-zero is key up4 G, P& ^# b7 `) Z; D6 F
report[0] &= (~bitset);
7 k! F9 u1 a- K i' x" ~ else
+ b# N' r; ~2 T" q* C- U% [ report[0] |= bitset;
# Z3 N Q4 }& @8 B9 i& h }
3 }7 }, G( f9 _* J. r else
( c1 Q: l) ~2 j1 N {
0 j# s# e3 ~1 q6 g' c/ F if(onoff) // non-zero is key up( M" Y) {5 O- q# a6 `- \
{# |" Y3 I/ S1 @) {% S
for(i=2;i<8;i++)- I( q( o2 ^# @$ T, [# M! }5 [
{1 S% l. G$ }5 Z9 B( [% K
if(report==key)
" G4 D9 X/ F" s6 @9 z& A3 T) O {
. `% P+ i5 J& z+ T$ A report=0;% [" ^9 w- } c9 ]0 ], ~6 f$ h
break;
0 X4 b0 Q3 y) c* A7 I4 U# f } ]# U9 ?" ~9 F; T- e7 h# L
}- c T* t8 ` z( x T5 Y
}( N+ B3 \& r p' @8 J8 T
else
4 X0 A* R: W6 O6 i {: s4 B+ X" T! M1 _6 T
for(i=2;i<8;i++)2 j, {; ]4 b* x. [& I# J
{- v4 h j# {) ~; T3 T
if(report==key)0 U K2 e9 |/ U1 i
break;
% l7 s; t" G: v2 C' j) j" S g if(report==0)
7 n" m4 F2 I, {8 | {- G7 ?" `, @3 H% U" Z7 v) b+ l# l
report=key;
5 `, s3 Y$ P8 Q: F break;
* A; W. N8 T8 z }4 B# |& w# E: R$ _2 m+ }9 P e* u- P
}6 y& l& [8 x+ {+ V
}
0 I( v- n) u# V; |# n, Q* R( Q; U }0 R4 u& o7 _" H# t% ?
for(i=0;i<4;i++)
" F2 m1 H& b8 r1 ~) L USB_PMA[192+i]=hid_report;, U/ l$ n* u) Z4 ?# c5 j/ J( a
USB_PMA[5]=8; //COUNT1_TX" x U$ c' H: E( q) h
if(ep1_wait==0), [: p/ J* P [. K- C1 \
{
* Z% W1 n. a$ e7 r: T; _ USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
5 L! Y3 I0 L, V2 R ep1_wait=1;
/ M% l& s* i8 N }
4 w) m) |9 w9 V/ b& d& |}! a) _- z% O, s4 ^! g2 g! m
% `0 F" p" g, o1 P# n3 `+ R/ s. H e$ c( f& u; r% M) t
完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。
$ T, x7 \; _" e0 S8 r0 M8 u
keyboard.zip
(8.7 KB, 下载次数: 6380)
, h3 U" X# m7 _8 Q0 m
6 N8 F: p2 C; |" F. b$ Y4 C2 `2 h2 m0 F U0 ]
) t- W- W1 v; z7 s- T+ S! T+ `% ]$ a0 F5 x, R$ @
|
|