|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 3 e$ j9 B6 M5 u% J
1 Z2 \# Y5 h6 N ~扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
1 I+ H* b( R! I/ a; `9 Q: ?1 D- P- j" ^' Z' V$ u. X( G
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:
3 ^/ U0 }2 Y& ~+ {8 Z* r9 M/ w, D$ m3 a- ]$ s8 h% a
1 s ?! W# e! L; p; X% Gconst char hid_keymap_qwerty[14][8]={; b3 h, |- T: `) E4 v# I- r
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},) C9 y5 T; q7 z k( f
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
% x( D# N' R! L! G% y' \6 a. E {HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},& |. e$ i2 q; M2 Z9 X' ^/ A
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},
3 Y' n$ }; x# l$ A {HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},% d c& n% Y! r0 q
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3},
1 K! c1 m8 k5 O9 b" d8 b {HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},: a0 T1 ?2 Z1 d- M( v$ W0 T
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
6 J. Z& A7 Z, [6 w3 o/ s- } {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},; h: c+ h9 ?( h3 B# u9 t
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},+ p; R2 C5 c% Y" \' e
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},0 D+ X$ N7 X& t
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},3 [# z& A% e& V, }7 z5 [, ?0 a
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},7 R' @( d- c8 Y: \" \2 J* M
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}. |- x; r$ F9 j# \! j3 t
};
3 x: F! f: G% ^+ \ I& T \4 j: Z2 k: K2 ?1 R4 W& \1 w
2 [* h* i; j& k9 z; o1 h1 Q3 j
const char hid_keymap_dvorak[14][8]={
* v) W, o6 S6 R& Y# ?" N {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},
0 i, |; K% R( G* A3 A4 {) x" X {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
/ W- e' e1 `- Y6 J {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
9 `' G4 h h, D3 p0 b- }! y e {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
" V: s v" j' n" q5 D {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
5 P" f* N4 ?& k* Y {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
8 R3 U* Y6 h2 @ {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},. p1 U; S. A; s5 u
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},/ z8 M* B$ i1 R4 o/ @* K% D3 j6 f
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
, K+ d" |0 j ]/ D+ i4 X {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
' S6 h7 _( d' q4 p" Y! x0 j6 p {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},1 p! w' F2 R& S9 }% _9 G, h
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},2 X2 M7 g8 W& r' A; i. ?# I3 P: J
{HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
( k5 P) }, S: `* G {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}! [3 |. }, s4 C m
};4 ^& P7 {+ d/ d
* Z; _# `" X5 j/ X
6 d' R+ } ~0 P) H/ Y- m. [
上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。
7 f2 u- m d$ w) I6 P p/ L% c. s( L
& l' ~7 l0 O H8 yHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
8 G* P4 [2 F' S0 j9 i6 Z0 T( K0 [
! L8 |1 u4 J+ X6 y! C$ O9 I- Fvoid update_key_matrix(char row, char col, char onoff)
2 d1 q% K% a6 j, R; D{
1 E# }! i: _* {# K2 K( ` static uint16_t hid_report[4]={0,0,0,0};. e/ _$ k2 C3 I/ b* e
static char (*hid_keymap)[8]=hid_keymap_dvorak;/ O6 |1 C0 T9 q0 d6 X; R1 ]
' X& c5 b; G" ]) P; `
+ q" r! _! S# x$ Z# I3 _; H0 W unsigned char key=hid_keymap[row][col];: S! s, I" g: |
unsigned char *report =(unsigned char *)hid_report;
* l/ g$ n* Y: E5 J( S char i;
2 Y) ]1 q$ x' U4 [1 s( A1 G0 k+ s5 ?
% \1 m m2 h1 H @; H* y
9 h* o* \. q- B* x8 t3 t0 f if(key==HK_MODE)6 |9 A: ^0 S$ [& T- Q) {* R
{
4 O% K# b) M5 r0 {* ]8 Y if(!onoff)
* o9 L$ F- L5 R" N$ [& y {
+ b4 r4 H7 C8 P if(hid_keymap==hid_keymap_dvorak)
% x) w3 Q7 D9 E* V; f: ]: c {
$ y4 N" o; V3 e: }* L4 |3 \ hid_keymap=hid_keymap_qwerty;
2 P+ i+ v7 a% J. h1 W GPIOB->BSRR = (1<<2);
+ V4 \3 C' R/ P3 d# e5 b }
, d3 X5 D# A, T9 ]( a else
. p! }5 X& B: p1 E3 h {
# o5 X3 n5 }2 a$ \ hid_keymap=hid_keymap_dvorak;) q" A+ `9 ?3 m+ n' u. j( B# _
GPIOB->BRR = (1<<2);
" @2 J( w: g/ x3 e }
* [$ C6 W3 h( d) [ | }% Z Y- i4 W: g& a& c
return;
2 K0 ]/ U: }9 }2 G$ A; ] }
; V0 \. m; b, U" D& i- S: q; z. I" w. F! e* @
" a% X2 j+ F, s if(key>=0x80) // Alt, Ctrl, Shift
8 C( k* z0 S y) {" J; s- f {+ X* ~: w9 X# Y* z) }# l: }
uint8_t bitset = 1<<(key&7);. a- p" Q* d5 z& T" U
if(onoff) // non-zero is key up. T+ ^! \( d0 u9 P
report[0] &= (~bitset);1 o) P1 U; Q3 [1 t u
else
" [6 ?0 k) F9 O- S2 o report[0] |= bitset;# H* } p3 a0 C* T
}
3 K" ?/ z9 C5 q else
. F; d% m/ }0 @. w6 s {
( p3 Q/ Y' m% K if(onoff) // non-zero is key up6 n {/ t# F$ \
{
" l6 H/ R: |; S0 O& X+ t$ n \ for(i=2;i<8;i++)# o6 d6 a! J1 g; Y5 F' ?- _& \
{& H4 i# @( ^0 ]; M* s" Q9 A
if(report==key)
7 S1 P; K( c. n {
1 Y6 M) f- \1 C report=0;
+ H, _; U$ J0 O5 O8 Q" U break;! Q+ ^$ a9 u8 [
}8 A8 I4 x8 g) E7 X( \3 s
}3 @- W4 _* g9 J8 ~( u
}
: f8 S" [% u8 E5 p* f( H- W else' P5 z: L; \; f2 i
{# r( q# u; k& F2 \. j
for(i=2;i<8;i++)( m* A; b$ s* ~9 g6 L( I
{
, V$ O9 h/ a# F" g4 L8 ^8 I if(report==key)
6 e4 B# D; x+ d* o- E break;
( F" z8 A% b. x' O" V if(report==0)3 J* J+ G2 X$ P4 t- Z: m
{' o9 D U6 [! Z; F' h6 F
report=key;
) R+ o6 o& }* D4 {2 T [ break;3 U+ H; A6 q$ B
}
4 s/ \% n8 o6 u2 y4 K& V }
~/ \" o7 y- E% t }
8 a3 O/ z& L5 z3 m5 l: Z }
5 |1 s: T, [/ h: X7 @' X/ m for(i=0;i<4;i++)6 C2 J9 N. \6 b: q. P
USB_PMA[192+i]=hid_report;
/ ?) \" s# E5 u/ z R+ S# d/ P USB_PMA[5]=8; //COUNT1_TX
7 Z6 ]7 A3 @' J: q1 g if(ep1_wait==0), |# H. I, s! r& Z! z) \
{* r9 G- ]- n, C% n: ~& t+ `
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;5 X: ]% p, t8 A- O" j
ep1_wait=1;
& U( W, Q1 d x8 ^" S: k1 { }
; w9 j8 l4 z9 X7 u- z Z" V}
2 _* F$ M' v! o$ y4 [
- g0 T* j" b; U( ?7 n7 L% X- D: T+ G# ?
完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。$ e, \( w _/ y
keyboard.zip
(8.7 KB, 下载次数: 6370)
6 p' b% s7 ^! [, n' h
}7 u, y |8 `+ _4 T, k5 Y4 K: ~2 O2 N2 Z
- s2 f& \& V c4 G6 w e- N) A" [3 |4 O
|
|