|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
4 f# Z8 @0 v t5 Y2 f, d0 ]0 L" H' l1 ~* h& {/ F
扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。( P- h6 C5 e' F) d: B7 f* M
) q6 j, W- B4 |* n! K" Q" H- Q要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:
5 d9 T Y1 g! A, r# w3 u3 d$ {6 q3 K
& @- u# @" }0 i+ o) R& y! @1 `$ Y1 hconst char hid_keymap_qwerty[14][8]={
5 d d Y% a* W: y {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
% ?. r; Q8 \9 l8 q% ^) P {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},# ~: q. ^4 T% X% P5 i( Z0 q1 ]
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},# t5 ?: |# {2 [' W# c
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
8 D' C! S0 {2 V- z {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
! b1 H6 I& z8 Z% `4 f {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},
* C2 f3 A: ]! { {HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
% X Y# u* ^3 O' K+ j1 w: o1 c {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
( Y$ n0 ^$ k# [ k6 i& E) ~9 ]- J {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
; A6 }% H" n: z {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
8 `. [1 [3 \/ u {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
1 ~* ?4 P% S# `' j& S+ j% Q {HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
1 m% ~9 [* D- E {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},0 H- A* L( M ], O7 ]" G
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
& }7 N" S! r6 A- R" ]. G$ K& x};
) O T) y3 {. \. e% t: q8 F; i
! I( `& `) D% c4 f& T1 P8 R1 O8 y6 ~9 q2 g* B
const char hid_keymap_dvorak[14][8]={
+ X2 N* Q" M4 g" Y {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
# _/ M3 b* A, k; N {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},! s8 j# Y) h: N( w
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
+ c y5 @+ u& S8 U! s* U# s& |! r {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},5 l* P* t; A! q3 y9 B
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},) Z1 D9 { A! k
{HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
7 u2 ~+ Z7 M/ Z' G {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},3 ]9 k4 K0 ]- s% h* ^/ f
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
. v% D- ?' Z) ]5 F0 J% A% J* x P {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},; y& x1 i3 \# g- B4 F% h
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},7 B5 N! Z+ c& r& _
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},, A5 L( {9 A/ B
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
) h- @8 [8 a# C B, P {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
3 F6 }$ p3 M+ A: U {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
' e' e, A2 x/ ?' M/ R) R0 d};! @( z5 {# o: h: h$ Y, c+ E
' q9 c8 ~& }* x
' r- y G: l" j上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
% G1 [# n' `; [6 @" X6 B1 u
_/ _% n2 W* u, N" G- ~HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:3 a$ A, s3 T. k7 x' |
: r$ i% S* ?! V
void update_key_matrix(char row, char col, char onoff)
) [0 p) V1 E3 J7 t3 }; k{ o" ]' A& s) x d. _
static uint16_t hid_report[4]={0,0,0,0};
- v& J3 `" q( A5 N static char (*hid_keymap)[8]=hid_keymap_dvorak;* |. E# s+ K1 k0 q, \2 t
8 r6 }2 K! t$ R
* b: P( `5 s1 t; e( n! F) X unsigned char key=hid_keymap[row][col];: e( [' `# r9 A
unsigned char *report =(unsigned char *)hid_report;( U4 b8 e' `; U7 |7 X, I' `
char i;
7 y8 ?: w* F/ R2 s- K2 D1 r! |% Y! k1 W5 \( C( S; Y4 w
. t' n0 \9 Z. N2 W8 J if(key==HK_MODE)1 W' p8 f! m& z" Y) {9 J
{
& t2 _5 s/ k, N8 ?; p if(!onoff)
9 I/ x8 G$ a9 ^+ }# w! e% N {# ^% h4 i5 \" A
if(hid_keymap==hid_keymap_dvorak)
5 f, ]# W$ ~. _7 l" X% W* h- e8 o+ U {
: g- U) ?0 w7 E( N+ w b4 }1 I/ B hid_keymap=hid_keymap_qwerty;" P' M0 U4 M. y( ?! `+ K( X
GPIOB->BSRR = (1<<2);7 B8 F& r! m" b3 `+ V# {% X8 n+ \
}( |, E8 G! O3 j6 o
else
/ ?& G0 C5 ?5 {& E6 M7 b. Z3 X {
. a; v# N: L7 Q* | D0 [ hid_keymap=hid_keymap_dvorak;2 D9 A% ~# \1 h
GPIOB->BRR = (1<<2);7 i6 d6 o9 y+ ?1 E$ a
}
3 W% Z9 X/ H# t2 G- R }( i E) [2 Y$ I' m# \0 Y3 T
return;
# J2 n) h2 l- a+ U }# [( x9 v8 c; H
6 i* X0 d% f1 Y3 n
% S; d9 F) b1 K. G if(key>=0x80) // Alt, Ctrl, Shift- C) i z& h( h ?4 t6 k% ]
{
/ x/ z2 T% b; X$ ^% q- @, i( S uint8_t bitset = 1<<(key&7);2 @5 c; ?* F/ }
if(onoff) // non-zero is key up5 F% Y% x% I- F/ }- N' y5 z
report[0] &= (~bitset);) h& d# ^3 u1 U' A3 p' L. N- x
else
7 [1 m" w" c. h2 x* ] report[0] |= bitset;
7 {) e4 {! o- ^( w9 K$ X0 q- j }
% E$ @8 x* s" ]7 d1 C7 }6 y else
. Z& i* c$ b4 P( z0 `+ ?! q {
& S1 n9 G `6 m5 i if(onoff) // non-zero is key up
3 J/ }% s7 |. B0 n: w1 q {" w$ c8 C. J! H) I1 s
for(i=2;i<8;i++)( b0 K. W5 B# f( R; U
{, N( P# j: q S+ |, L: ]
if(report==key)8 {7 z" S9 S5 e5 b4 L
{4 d# M. ]( v" K0 q1 j* W+ G. ]
report=0;
) b1 j% x/ `- r( B$ O- N4 h break;+ E5 w5 O' w8 W. c) r
}
: b$ T3 Y* A; W& z# a( E M) T }6 n* {8 i( i% @
}0 Q/ e6 B$ Y6 e
else( \+ S. ?0 F+ [- j% U
{
+ @2 c i$ K1 Z" O4 o3 f# c/ { for(i=2;i<8;i++)
: G7 B, I$ l5 x {# k# L4 w+ \& }# @
if(report==key). I" J" ~$ w" ?
break;
& N9 y# }. L" {% W% X& @% S8 k if(report==0)
6 n6 h* s# h. P# _( X {/ |! m7 j3 R) ]% F$ g. q$ F
report=key;; I+ J$ H" ?% [& l. @( ] B, D. ^
break;
+ _+ ^/ E8 E) b: T4 V4 T) A* b. E }
& @: q! v, `5 F' i }7 Z% B1 u, p" i& B" L% `. Q
}7 d2 L: G& w+ H! e- O9 q
}) o" F2 v0 ], w3 ~% B$ S
for(i=0;i<4;i++)0 @" l( w! R+ J
USB_PMA[192+i]=hid_report;
9 E$ y u4 J! _8 T USB_PMA[5]=8; //COUNT1_TX
* [, i( E x( W0 K2 x9 P if(ep1_wait==0)2 o4 u( I2 v* T5 E# N+ L, l1 S
{
8 E1 K9 u1 ^" K4 k* p0 i2 B" m USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
2 c9 K0 P4 Y& F ep1_wait=1;# _+ E) ]9 e# S F9 z5 G
}2 R& l2 j1 E6 j5 A/ X
}; `4 j X+ e6 {) u
: u% H* x! B8 v$ w+ E5 x# D0 j/ W
1 d3 q1 J0 b% R7 M2 w完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。
) y$ i4 `9 T% t" o3 B- s: S
keyboard.zip
(8.7 KB, 下载次数: 6455)
( V$ B# I' t& }. b% \
: l. F( m/ w1 |0 F9 V
: G Q$ D: e/ D
3 `6 F' k6 h2 U7 E a3 l4 Z/ f. P, d0 \) m7 V" K
|
|