|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑
1 `4 n( ?- `1 H2 v* E% i
. \ L: p( c; [# y+ r扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
( F. w7 V$ R) n- ^1 ~. c
5 @7 D0 V! [8 Y, c' f; e1 O+ b7 G要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:6 E1 n; y7 d3 F
4 f" [3 A4 c7 W8 p- G, f' C
0 ~( C; S0 n5 K. p, }const char hid_keymap_qwerty[14][8]={
% W; C e; A: J {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
- ~+ I. @" u# X# @1 c) D2 {, H# |9 f {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},/ `( ?- F( u3 S+ Q6 F1 z+ b
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},' l$ @" F4 y8 H. _* ]
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5}," A0 ?5 m& d( s
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},
5 S* G# a. L6 ^2 l+ ~! i {HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3}, L) W7 f3 {1 ]- u& Z
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},
# Y) h k5 Y, O: j* o {HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},
4 e0 e* K |" j0 e9 p( Z! B {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
_8 i0 k2 }3 L* S7 u {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},( B" L. u8 W8 ]! ]1 {
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},1 a0 T6 k/ Y5 b, W4 }3 w( i
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},$ ^6 L6 {9 S" m% A0 X
{HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},
* E8 _* u* a0 v# R& L" r4 D: h$ O {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}
$ v! v; p) B' Q0 c};
' A, U; A' }$ v6 M* [ b) _+ ^
% P5 Y/ V7 i% f- W$ j7 D0 n. c0 h' K6 e7 X4 M
const char hid_keymap_dvorak[14][8]={" H' r2 E9 Q% ?3 m( V) ~
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},' F y3 `, L" Z9 E( _1 j/ E
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},: k2 f1 G1 `7 H
{HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},1 N. D2 U' q! r8 ]: N( y
{HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},
$ k1 N0 ?& P t) f* P3 k {HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
2 x/ [ q v! L/ v# g0 j7 z {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},
( o, l; q) E$ F+ S {HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},( U& z$ u, ?" j/ A& ^9 a: X/ O2 N
{HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},
, a. M7 R9 j- f. b0 J8 O4 w {HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},8 k" x$ M0 J: L V; E2 w0 X" W
{HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
- I/ Q/ L5 W X {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},
+ {* _/ Y, t3 x7 x {HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
5 ]' n5 e" |! \- w& K% Z {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},, U( ^0 `/ T; P6 F
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}5 Q; Q# L: l9 x' S' B! A/ e, L
};
/ K- x5 ]: ]& _
; _% r2 ] x+ D
2 K& A: X) Y0 K* A7 U上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。$ D% N+ g& \$ T2 I
. |/ N; t5 t" M9 k' m
HID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:2 g7 X+ n+ q+ }- J+ z
. R/ |; Z- |+ K& X1 a' a8 ~void update_key_matrix(char row, char col, char onoff)' z2 q+ p$ ~: @" D. E
{
1 f' W+ k1 h1 Y R' V8 X* P8 j) X static uint16_t hid_report[4]={0,0,0,0};
8 R5 M0 C; R+ C( U; I: K' f9 {: i static char (*hid_keymap)[8]=hid_keymap_dvorak;+ g* Z# p( n: Y; J/ f% L9 d4 a1 @
. ~7 m7 v% O/ o+ A
2 k' M8 \& n, b# w8 }* o# X+ e0 N unsigned char key=hid_keymap[row][col];
4 K, @; e/ J+ [4 F; V( W+ A unsigned char *report =(unsigned char *)hid_report;( z U' g9 I/ ^% @! a3 G
char i;
: Y) \% E1 B; E( K3 [! f( G3 |' V6 X$ M$ T; e& h/ s* i
. s V/ W5 Q W( O! e) \2 v if(key==HK_MODE)6 u) V3 ]0 R3 |2 d1 H) G$ P' ^& ]
{9 @6 d v- j& c' [( s2 T
if(!onoff)
' m' }4 o( A3 i; B9 e {
9 D3 y G% ^, i! b if(hid_keymap==hid_keymap_dvorak)7 v+ H( P3 A' }. B% i5 t& {
{, Q* C; K6 A/ B& c
hid_keymap=hid_keymap_qwerty;
! Y4 W, b/ k2 ?% y1 l GPIOB->BSRR = (1<<2);
" ^( X) w' ^& n' P7 ^, Y6 _# O; ~8 f }( @6 U0 o" H2 O5 b0 e8 c7 e
else
- |# m6 v6 y, N, g0 k5 `: b9 F {
+ r- S* K3 k, ?5 ]/ \9 [$ o+ f; y) U hid_keymap=hid_keymap_dvorak;
' p7 i1 d8 V8 |* L' w- d% ` GPIOB->BRR = (1<<2);
. h0 i. F9 K6 ?5 c3 Z! r }
, ~# Y. ], k8 M& {( V( z3 Y% a }" h, K0 D2 F _+ s9 l: Y
return;
+ H8 j8 k) U2 H }( ] n" Z4 k! c3 {1 C
0 ~, A- q) ^5 r2 e% p; s, Z! G% b! a( U3 y5 f2 L4 E z8 Y) [) N1 T
if(key>=0x80) // Alt, Ctrl, Shift
( m; g) c* U& ^+ W" Y) @( Q2 u& z {% K4 ^+ H7 D# x6 y+ `) z* C
uint8_t bitset = 1<<(key&7);7 D5 h8 X* m8 L1 t( F
if(onoff) // non-zero is key up
/ O# A1 p7 s; }" d N report[0] &= (~bitset);2 [' f2 ]3 Z( z* |
else
9 O' Y' I* @7 v' F6 k7 t0 v% Q report[0] |= bitset;
% R& y- v* l* C. v. l, R2 [ }
0 g4 v" h2 U7 W( t else! e9 |9 D+ E7 Q4 j5 ~) O1 D& Y
{6 a* {" V3 S+ ]
if(onoff) // non-zero is key up9 G" N4 h( }# P3 r) i U( h9 p
{
# l8 b4 U( e: W6 j for(i=2;i<8;i++)7 S0 N+ s$ ]9 a( q, r, E" q
{
! S# ?1 D3 N' f; \$ E( l. X0 X if(report==key)
+ x! j, w2 M" e& ^7 S {
; Y0 m8 P- V/ {- l4 k report=0;4 v, Q) \9 R! L* |' b, _
break;) w! v3 H% v" i6 d
}& c3 g& z* S% ]# M5 b; ?
}5 |$ L6 v5 K, X% o
}
# V3 H- h" Y! k) S else
8 F7 v+ g4 {# y" U: p8 O! U {, O* H' ^+ X, h' q' d# i+ L$ @
for(i=2;i<8;i++)
9 E7 W( w( p3 F% y {. d% o$ l! l6 _+ a- x" e
if(report==key)$ |5 E. ~; y. Y3 G( v1 D5 p
break;
0 F* b" ?. t. g if(report==0)
! G. }, N/ {/ r8 N) z0 I9 | {
1 h8 X7 @9 _3 f/ J3 L+ P. L; m report=key;
7 A- \, Y; y# B( t; P) b break;5 m' ]) W& J% U( M1 [
}
* l0 i- L9 j- y8 f9 A3 G; } }
* f# H* f7 w1 _2 e- X7 B+ L& ? }/ ?* H7 I$ C5 l5 a' P6 c8 e; M
}
t& T. ~- W) K6 r: I( | for(i=0;i<4;i++)
+ P% }0 ?( k- X4 k4 D- i USB_PMA[192+i]=hid_report;7 K2 V; }! P$ W' }% k- S4 H
USB_PMA[5]=8; //COUNT1_TX! m: R) F' m. n8 i# [
if(ep1_wait==0)
, P- h' W; v% U' }% Z {( ?; V% ~# f2 {; P# s
USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
( E4 l# s+ A1 f ep1_wait=1;% I7 Q2 j$ ]% {9 p
}6 m. `& g, F, |$ ^1 f& S, u) N
}% g2 _4 u( T" k w A4 v9 y7 I
! P! N* `; [6 W6 y4 J* f, u
# A. q7 L$ ?3 `% i完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。
3 s' o8 i+ B1 |1 e5 j
keyboard.zip
(8.7 KB, 下载次数: 6711)
9 W6 x% S/ J: q1 f1 D: A
9 \: b+ x# f! F: |
$ D$ N# a* K; G+ ?- @$ x
. ^3 A" A, [" |" V6 E8 D' z
! N8 \/ x# W8 G, ` |
|