|
|
楼主 |
发表于 2016-9-21 21:01:28
|
显示全部楼层
本帖最后由 miaozhuang 于 2016-9-21 22:02 编辑 1 z4 H$ r$ m0 u l0 E& y
5 `0 ^* j7 M4 O4 i9 O
扫描的状态被Timer 6 ISR记录在 key_state[] 数组当中,上一次的状态保存为 prev_key_state[]. 这样在主程序中只要比较这两个数组,就知道是否键盘的状态有变化了。有变化(按下或者抬起)的时候,再调用 update_key_matrix() 函数去生成USB HID报告。
- P. X$ f/ z2 V& J, }# v* D, |& ]" P- O6 V1 E6 n0 { ]& Q+ v
要从键盘的扫描行、列坐标得到按键的编码(此处不是ASCII,也不是PS/2的键盘扫描码,而是USB HID定义的键盘Usage ID),需要用到查找表。我需要切换Dvorak和QWERTY两个布局,因此需要准备两个查找表:
2 O3 ^; M/ V0 j' ^6 t3 Z- h5 ?' z* q$ t' _ {1 j
/ X' w( n9 {' ` |
const char hid_keymap_qwerty[14][8]={
" T {9 L7 \: q1 g {HK_RShift, HK_NONE, HK_NONE, HK_A, HK_R, HK_7, HK_F9, HK_Esc},
6 ^* R# H# {9 J1 m! g {HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},3 K0 i9 _' L0 a( j$ Y+ y
{HK_Period, HK_V, HK_BSlash, HK_J, HK_P, HK_Q, HK_4, HK_F6},: f: _' B$ [- Z: M5 x0 m( j
{HK_Comma, HK_C, HK_Quote, HK_H, HK_O, HK_Equal, HK_3, HK_F5},) B0 s L9 N% P& \7 Q1 v% D! X0 Y
{HK_M, HK_X, HK_Colon, HK_G, HK_I, HK_Minus, HK_2, HK_F4},0 b1 w) V* ~6 t( R
{HK_LShift, HK_NONE, HK_Caps, HK_F, HK_U, HK_0, HK_1, HK_F3}, ?1 J; \2 E/ s! w6 K
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_D, HK_Y, HK_9, HK_BQuote, HK_F2},$ a ^# d7 s' a' G7 Z7 ]# ^
{HK_NONE, HK_RAlt, HK_LCtrl, HK_S, HK_T, HK_8, HK_Enter, HK_F1},8 f, J6 {0 N1 w4 q) u# e+ t" @: J
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
' B5 I8 V) s# l, I9 ?) ] {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},& a9 ^- H# @ J3 \. |$ Q
{HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},4 r3 ^+ h% E1 |+ G
{HK_Space, HK_N, HK_Z, HK_L, HK_RBr, HK_E, HK_6, HK_F8},
- t. F8 h' l5 O% v- I {HK_Slash, HK_B, HK_Delete, HK_K, HK_LBr, HK_W, HK_5, HK_F7},8 c& ~7 P" v- E: a: i; S
{HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}! ]7 Q! H j1 |3 m3 M: g. v
};/ H0 f+ ~% B4 x
3 `) p6 C& g( s) b" O9 X# K; v* Z# Y
const char hid_keymap_dvorak[14][8]={5 d7 P/ G: {1 A- x- P* D
{HK_RShift, HK_NONE, HK_NONE, HK_A, HK_P, HK_7, HK_F9, HK_Esc},. O" y1 }% b/ ]# R0 R. u6 {0 ~' d. ~
{HK_F12, HK_BS, HK_Up, HKR_Slash, HKR_Aster, HK_NONE, HKR_Enter, HK_NONE},
S9 L+ O3 {2 u( H3 M: J" D {HK_V, HK_K, HK_BSlash, HK_H, HK_L, HK_Quote, HK_4, HK_F6},
3 b% v$ j" n0 K9 M$ P {HK_W, HK_J, HK_Minus, HK_D, HK_R, HK_RBr, HK_3, HK_F5},4 P* r" ^ L# F% N+ ]
{HK_M, HK_Q, HK_S, HK_I, HK_C, HK_LBr, HK_2, HK_F4},
( B0 U: S2 D' {; `- M9 `2 @ {HK_LShift, HK_NONE, HK_Caps, HK_U, HK_G, HK_0, HK_1, HK_F3},& v1 m _- d: |: }% P+ p
{HK_Scroll, HK_LAlt, HK_RCtrl, HK_E, HK_F, HK_9, HK_BQuote, HK_F2},
& o; E% f. m) i: c6 s% g {HK_NONE, HK_RAlt, HK_LCtrl, HK_O, HK_Y, HK_8, HK_Enter, HK_F1},+ g4 O8 t4 {6 V! g1 x6 k
{HK_PgUp, HK_Home, HK_Insert, HKR_5, HKR_6, HKR_4, HK_F10, HKR_Dot},
1 |0 h* W; X o ~% u {HK_Right, HK_Down, HK_Left, HKR_Num, HKR_Plus, HK_NONE, HK_NONE, HK_NONE},
: `8 ?+ _! W/ H; d D {HK_PgDn, HK_End, HK_F11, HKR_9, HKR_Minus, HKR_8, HKR_7, HK_NONE},$ Y) Q8 G1 ~" [8 d9 g |
{HK_Space, HK_B, HK_Colon, HK_N, HK_Equal, HK_Period, HK_6, HK_F8},
/ R) U/ C/ ?8 n0 B/ k! |$ z {HK_Z, HK_X, HK_Delete, HK_T, HK_Slash, HK_Comma, HK_5, HK_F7},
- Y; p. m7 v) |. V. V. U {HK_Pause, HK_Tab, HK_PrtScr, HKR_2, HKR_3, HKR_1, HKR_0, HK_MODE}" ]0 y) g9 u) U; a, `" W. r6 {0 }( a5 Y
};" l- b6 ?7 H0 I2 @6 z2 r& ^$ D, r, d
2 X7 T9 m8 o, Z: w
7 T$ p+ P: M0 L* f: Q& ?+ K9 R
上面的宏定义另写在 translate.h 头文件中。HK_NONE是没有实际按键的位置,HK_MODE是我另外加的一个键,用来切换两个键盘布局。这个“一键切换”的键加装,可以用原来键盘上的AT/XT开关,也可以用我预留的User I/O,做到后来发现用键盘矩阵的空闲位置更方便。* e5 e3 p: Y: R. C3 ~( _$ b! T
( L E- N# _1 n8 m; zHID报告的8个字节,第一个是8个特殊键的状态(Shift, Alt, Ctrl, GUI),第二个保留,后6个每个非0值是一个按下的键的Usage ID. 产生HID报告的子程序:
- _$ z* l; Z, u( j. U! a6 H+ D; X; y' J% [
void update_key_matrix(char row, char col, char onoff)) c* H9 w2 R# w m3 W
{
9 {2 l9 ^* t9 ?8 P static uint16_t hid_report[4]={0,0,0,0};& s# V3 [5 f+ s! A$ [
static char (*hid_keymap)[8]=hid_keymap_dvorak;
t5 p! Q% ^- U& i2 l$ F) e- y4 X
3 M f* V: Y1 @# L
% z) d3 r$ z3 ^% w& `4 m% V& b unsigned char key=hid_keymap[row][col];2 \' v" {+ A7 F1 |/ A0 e5 Y' I. V/ |
unsigned char *report =(unsigned char *)hid_report; F8 K% k; y0 b
char i;. W. G) N" Y- q J |7 O
0 `" r% ^7 L: X7 u) A! ?9 k
, _3 o; X) `% ~* {2 B
if(key==HK_MODE)0 H6 v0 F& f6 F( U
{0 R7 a# k1 H! u- p3 t
if(!onoff), @$ ]3 I8 v: }+ C; e# f4 ]
{
4 B" g1 L# }9 K# K if(hid_keymap==hid_keymap_dvorak)9 J; O) V, f6 `/ K
{
- u7 ?8 \: \' b: K$ L4 v6 [8 P* c/ | j z hid_keymap=hid_keymap_qwerty;
7 y4 l, Z/ j9 l: @1 c: z GPIOB->BSRR = (1<<2);9 C" s( E, l/ T9 `. d
}" w9 |2 l' S7 y/ n. |) g
else: @/ g+ }/ l% A, Q2 ^: f
{
; h/ C. w0 L/ y. W hid_keymap=hid_keymap_dvorak;) z8 w. e) ?- O% d% o
GPIOB->BRR = (1<<2);
4 F: @' k1 U) @1 ` }# G8 W/ g) I5 l
}* m$ j H0 c& Z1 \: b6 m6 [
return;
7 P! ?: ?3 v3 o8 z. X }" f, J: \7 s( X" W! Z
* i2 ]+ ~3 B ~" {; P2 G# P
6 Q. s: @0 y7 [; M/ I8 `7 f0 z if(key>=0x80) // Alt, Ctrl, Shift; U5 d* S: o* e# f' I
{
& e. {0 P) b2 t& P1 T! s uint8_t bitset = 1<<(key&7);
% {+ B+ I5 a$ z% Y5 [& B if(onoff) // non-zero is key up- T& I: |( Y" l/ s$ a/ t$ ^- {1 c
report[0] &= (~bitset);) U4 J' D: Z7 @$ w4 H Y
else
" E+ v7 q; I' z$ B& l, K report[0] |= bitset;$ i+ `# K Z) i
}
( T% s0 S, B/ Q* v k# F6 W else
- P" B* C2 W/ F& `9 U2 Z4 C; D {
1 Y4 N* F$ z- z if(onoff) // non-zero is key up
* H6 w7 z( {$ S8 n# `' m G, c {) s# ~% R9 J* m! r1 ?' b
for(i=2;i<8;i++)* Z+ Q+ v' ?/ j; k3 f
{* H+ P) p8 @( b% z1 K( t/ E) w
if(report==key)9 I2 Y) r( n/ Q, F
{+ R$ e3 L8 @0 ~# y i+ Z8 I; z
report=0;. ]4 i2 F' _7 p3 E: A
break;
, X9 q- z! H7 f% m( g' n }' i* x+ q; j/ o2 K& e
}
5 u8 G, j3 }! E& `6 w6 Q }. l6 Z( w0 n) F* V: i& r- f# R! o
else
/ G; m7 `/ ~: x* s/ j {
$ |7 K6 _) ?* z) o" K for(i=2;i<8;i++)
. ^6 P8 s$ k) F4 _* X {* Z |: e* D6 ]! a: b
if(report==key)9 x$ K3 E1 q: G' n T$ O
break;
7 U; W: Q9 E0 q+ {! c if(report==0)1 ~) p5 v: o, d7 L6 Y. W& b( e& R
{
6 U8 K' V) B1 j" ? o) ]: t$ j; d8 O report=key;
4 _: l7 ` ]0 I5 g2 g break;
( b- V$ G7 u/ G" u; m }
0 W; I3 A" Q5 D' X; B! | }
: R- t' }2 A9 a }# l2 S1 D/ Z8 z4 k6 f: {
}
# @' A2 w# z) D1 Y8 k. A2 k: T for(i=0;i<4;i++)- M: j3 A% m6 _: N% c$ V9 o- ^) m( e
USB_PMA[192+i]=hid_report;8 S: b9 q) J+ y3 j8 E8 r! `2 X
USB_PMA[5]=8; //COUNT1_TX
! k; L! Y. a: m! L* H if(ep1_wait==0)) S- D. ^/ q( I! a# Q
{
" P) ~2 j% B! s. U USB->EP1R = USB_EP_TYPE_INTERRUPT|USB_EP_STAT_TX0|1;
, J8 M b# z, e ep1_wait=1;: ]% R/ L$ A* w& `& m- x' Q
}
) c0 |7 F* l, z0 v; b}
4 B9 m8 X1 A. \$ ?* u# m- p
! g$ U7 J8 B. {' W9 q( |: h, N
9 o6 K3 Z' d( p4 V$ I完整的程序在附件中。我这个程序没有使用任何USB的库函数,完全是从底层操作,这样对USB的工作细节可以了解得比较清楚,当然,也费了很多工夫啦。. S9 b: ~* A7 n0 E7 p# a \; |4 |
keyboard.zip
(8.7 KB, 下载次数: 6653)
9 j4 Y, }3 d4 ?: }3 i
0 z7 ?0 i% E9 _
2 A- r+ N3 Q6 x/ v: [4 T* a7 M- m! I' g2 F3 `% `
/ F; G8 s, a+ b- i P
|
|