当前位置:网站首页>如何把老式键盘转换成USB键盘并且自己编程?
如何把老式键盘转换成USB键盘并且自己编程?
2022-06-27 00:10:00 【arenascat】
什么是PS/2接口
PS/2是IBM所推出的用于PC的接口,连接器共有6个孔,圆形设计,在1990~2000左右时间的台式机键盘是PS/2接口的,尽管在1996年已经出现了USB接口,但是受限于芯片成本和设计方案,当时的许多机械键盘依然采用PS/2接口。
因为没有识别协议和描述符,所以键盘鼠标必须插到以颜色划分的特定接口才能工作。
PS/2接口和现在的USB接口具有许多共性,比如实际使用的线缆数是4根,5V供电,但是在传输形式上有区别,PS/2接口是一根时钟线和一根数据线,而USB数据传输是D- D+差分线。
和USB相比较,PS/2接口数据处理难度低,频率低,兼容性好,按下按键后,键盘会拉低CLK电平,传输12bit的DATA信号,而拉低这个动作同时会让主板芯片组发生一个中断信号触发中断处理,所以理论上反应会比USB更快。
如何自己编程解码
PS/2接口的数据读取属于比较简单的,但是在编程上依然会有一定难度,PS/2接口传输的是11bit数据,第12Bit一定为0。这里的难度主要在于按键判别并通过USB传输上。
模块可以选择Arduino Leonardo,在成本和编程难度上有比较好的平衡,多数时候我比较支持使用低代码(简单调用就可以实现复杂功能的代码)来创作和改装。
使用模组和专用芯片转换成USB
要在内部修改成USB,首要选的就是可以使用的芯片,我购置了一些WIT122UH用来测试,它的价格只有几块钱。
我在设计上考虑到多数时候是用于内置,所以这一个模块只配置了最少的元件。
然后我还设计了一个更复杂一点的,用上了一个紫色的PS/2母口座,型号为DS1093-01-PN60
此外还有一个增强设计增加了16Pin的Type-C接口,另外还有一个母座,如果要从焊接难度出发,可以把Type-C接口替换成4pin的Micro-USB接口。
模块设计上,考虑两种可能,一种是外置设计一种是内置设计
如果你要简化DIY流程可以直接使用这些常见的PS/2接口转USB,将它们拆开可以很好的压缩体积。
举一反三
因为PS/2信号容易模拟,很简单就可以使用8Bit的MCU生成,因此,如果制作键盘,那么使用PS/2转USB信号的芯片,就能够以一个相对于使用原生USB接口的芯片来说更低的多的成本制作出一把USB接口的键盘。
用编程来解决
我是用Leonardo和Arduino IDE来实现这种操作,拥有很大的自由度,应用库是PS2KeyAdvanced https://github.com/techpaul/PS2KeyAdvanced
对应的键盘是一把Cherry G84-4400,PS2接口
在使用上我用的是PS2KeyAdvanced库,和另一个PS2Keyboard库比较来说,这一个库可以支持点亮CAPS LOCK灯,而这个灯是需要控制器可以支持数据写入的。也就是往键盘写数据。
线路连接上,我把DATA连接在D2,CLK连接在D3。
关于各类函数的说明
keyboard.available()这一函数的作用很简单,就是在获取到数据的时候触发其他时候返回0,因此在loop中不断的去判断是否有返回值1。当然实际上数据是已经被缓冲存储的,因为一开始的时候设置了中断,中断函数中对键盘发送的数据进行处理。
按键值的查询
//sample以A为例:按下代码 释放代码
//一般: 41 8041
//CAPS LOCK下: 1041 9041
//SHIFT按住情况下: 4041 C041
//SHIFT按键:4106 8106
完整代码
#include "Keyboard.h"
#include <PS2KeyAdvanced.h>
//最新的,用于PS2转换到USB
//sample以A为例:按下代码 释放代码
//一般: 41 8041
//CAPS LOCK下: 1041 9041
//SHIFT按住情况下: 4041 C041
//SHIFT按键:4106 8106
/* Keyboard constants Change to suit your Arduino
define pins used for data and clock from keyboard */
#define DATAPIN 2
#define IRQPIN 3
#define UPPER 40
#define RELEASE_UPPER C0
#define SHIFTMODE 0x40
#define FUNCTION 0x80
uint16_t c;
PS2KeyAdvanced keyboard;
void setup( )
{
// Configure the keyboard library
keyboard.begin( DATAPIN, IRQPIN );
Serial.begin( 115200 );
Serial.println( "PS2 Advanced Key Simple Test:" );
Keyboard.begin();
}
void loop( )
{
if ( keyboard.available( ) )
{
// read the next key
c = keyboard.read( );
//For DEBUG
if ( c > 0 )
{
// DisValue(c);//DEBUG用的,获取c的具体值,状态符号和按键值
}
//ACTION
if ((c & 0xFF) > 0) //判断获取的按键值c有没有大于0
{
DisValue(c);
switch (c >> 8)
{
case 0x10://大写锁定下按下字母
UpperKey(c);
break;
case 0x90://大写锁定下释放字母
UpperKey_Release(c);
break;
case 0x40://SHIFT大写按下
UpperKey(c);
break;
case 0xC0://SHIFT大写释放
UpperKey_Release(c);
break;
case 0x11:
if (c == 0x111D)
{
Keyboard.press(KEY_TAB);
}
break;
case 0x91:
if (c == 0x911D)
{
Keyboard.release(KEY_TAB);
}
break;
case 0x00://一般按键按下
standardKey(c);
case 0x80://一般按键释放
standardKey_Release(c);
break;
case 0x01://功能按键
FuncKey(c);
break;
case 0x81://功能键和SHIFT键释放
Serial.println( "FUNC RELEASE" );
FuncKey_Release(c);
break;
case 0x41://SHIFT键按下
break;
break;
case 0x20://CTRL Press And
Keyboard.press(KEY_LEFT_CTRL);
standardKey(c);
break;
case 0xA0://CTRL Release
Keyboard.release(KEY_LEFT_CTRL);
standardKey_Release(c);
break;
case 0x21: //CTRL
Serial.println( "CTRL PRESS" );
Keyboard.press(KEY_LEFT_CTRL);
break;
case 0x9: //LEFT-ALT
Serial.println( "L-ALT PRESS" );
Keyboard.press(KEY_LEFT_ALT);
break;
case 0x5: //RIGHT-ALT
Serial.println( "R-ALT PRESS" );
Keyboard.press(KEY_RIGHT_ALT);
break;
default:
Serial.print( " Unknow Higher code: " );
Serial.println( c >> 8, HEX );
}
// Keyboard.press(c);
}
}
}
///
/*
Descript: For DEBUG
*///
void DisValue(unsigned int c)
{
Serial.print( "Value " );
Serial.print( c, HEX );
Serial.print( " - Status Bits " );
Serial.print( c >> 8, HEX );
Serial.print( " Code " );
Serial.println( c & 0xFF, HEX );
}
///
/*
Descript: abcde and so on,main key
*///
#define LEFT_WIN 0x008B//press
#define CAPELOCK 0x00FA//press
void standardKey(unsigned int c)
{
int key = c << 8;
Serial.print("Stand press :");
if(remap(c)!=0)
{
Keyboard.press(remap(c));
return;
}
if (((key >> 8) >= '@') && ((key >> 8) <= 'Z'))
{
Serial.write((key >> 8) + (97 - 65)); //输出小写字符
Keyboard.press(c + ' ');
}
else
{
Serial.write((key >> 8)); //输出其他的字符
Keyboard.press(c);
}
Serial.println("");
}
//return 0: not found
unsigned char remap(unsigned int c)
{
unsigned int key = c << 8;
unsigned char remap_char=0;
switch (key>>8)
{
case 0x3E:
remap_char = '/';
break;
case 0x3B:
remap_char = ',';
break;
case 0x3A: //按键[']
remap_char = 0x27;
break;
case 0x8B:
remap_char = KEY_LEFT_GUI;
break;
case 0x3D:
remap_char = '.';
break;
case 0xFA:
remap_char = KEY_CAPS_LOCK;
break;
default:
break;
}
return remap_char;
}
//CODE:0x 80??
void standardKey_Release(unsigned int c)
{
int key = c << 8;
Serial.print("Stand Release :");
if(remap(c)!=0)
{
Keyboard.release(remap(c));
return;
}
if (((key >> 8) >= 'A') && ((key >> 8) <= 'Z'))
{
Serial.write((key >> 8) + (97 - 65)); //输出小写字符
Keyboard.release(c + ' ');
}
else
{
Serial.write((key >> 8)); //输出其他的字符
Keyboard.release(c);
}
Serial.println("");
}
void UpperKey(unsigned int c)
{
int key = c << 8;
unsigned int chara;
Serial.print("Upper press :");
if (c == 0x403A) //["]
{
Keyboard.press(0x22);
return;
}
if ((key >> 8) >= '0' && (key >> 8) <= '9')
{
switch (key >> 8)
{
case '0':
chara = ')';
break;
case '1':
chara = '!';
break;
case '2':
chara = '@';
break;
case '3':
chara = '#';
break;
case '4':
chara = '$';
break;
case '5':
chara = '%';
break;
case '6':
chara = '^';
break;
case '7':
chara = '&';
break;
case '8':
chara = '*';
break;
case '9':
chara = '(';
break;
default:
break;
}
Serial.write(chara);
Serial.println("");
Keyboard.press(chara);
}
else
{
Serial.write(key >> 8);
Serial.println("");
Keyboard.press(key >> 8);
}
}
void UpperKey_Release(unsigned int c)
{
int key = c << 8;
Serial.print("Upper release :");
Serial.write(key >> 8);
if (c == 0xC03A) //["]
{
Keyboard.release(0x22);
return;
}
Serial.println("");
Keyboard.releaseAll();
}
void rep(String s)
{
Serial.print("Func press:");
Serial.println(s);
}
void FuncKey(unsigned int c)
{
int key = c << 8;
switch (key >> 8)
{case 0x1B :
rep("ESC");
Keyboard.press(KEY_ESC);
break;
case PS2_KEY_ENTER :
rep("ENTER");
Keyboard.press(0x28);
break;
case PS2_KEY_SPACE:
rep("SPACE");
Keyboard.press(0x20);
break;
case PS2_KEY_TAB :
rep("TAB");
Keyboard.press(KEY_TAB);
break;
case PS2_KEY_DELETE :
rep("DELETE");
Keyboard.press(KEY_DELETE);
break;
case PS2_KEY_INSERT :
Keyboard.press(KEY_INSERT);
rep("INSERT");
break;
case PS2_KEY_UP_ARROW :
rep("UP");
Keyboard.press(KEY_UP_ARROW);
break;
case PS2_KEY_DN_ARROW :
Keyboard.press(KEY_DOWN_ARROW );
rep("DOWN");
break;
case PS2_KEY_L_ARROW :
Keyboard.press(KEY_LEFT_ARROW );
rep("L_ARROW");
break;
case PS2_KEY_R_ARROW :
Keyboard.press(KEY_RIGHT_ARROW);
rep("R_ARROW");
break;
case PS2_KEY_PGDN :
Keyboard.press(KEY_PAGE_DOWN );
rep("PGDN");
break;
case PS2_KEY_PGUP :
Keyboard.press(KEY_PAGE_UP );
rep("PGUP");
break;
case PS2_KEY_END :
Keyboard.press(KEY_END );
rep("END");
break;
case PS2_KEY_HOME:
Keyboard.press(KEY_HOME );
rep("HOME");
break;
case PS2_KEY_SYSRQ :
Keyboard.press(PS2_KEY_SYSRQ);
rep("SYSRQ");
break;
case PS2_KEY_BACK:
Keyboard.press(PS2_KEY_BACK);
rep("BACK");
break;
case 0x04:
rep("PRINT SCREEN");
break;
case PS2_KEY_F1 :
rep("F1");
Keyboard.press(KEY_F1);
break;
case PS2_KEY_F2 :
rep("F2");
Keyboard.press(KEY_F2);
break;
case PS2_KEY_F3 :
rep("F3");
Keyboard.press(KEY_F3);
break;
case PS2_KEY_F4 :
rep("F4");
Keyboard.press(KEY_F4);
break;
case PS2_KEY_F5 :
rep("F5");
Keyboard.press(KEY_F5);
break;
case PS2_KEY_F6 :
rep("F6");
Keyboard.press(KEY_F6);
break;
case PS2_KEY_F7 :
rep("F7");
Keyboard.press(KEY_F7);
break;
case PS2_KEY_F8 :
rep("F8");
Keyboard.press(KEY_F8);
break;
case PS2_KEY_F9 :
rep("F9");
Keyboard.press(KEY_F9);
break;
case PS2_KEY_F10 :
rep("F10");
Keyboard.press(KEY_F10);
break;
case PS2_KEY_F11 :
rep("F11");
Keyboard.press(KEY_F11);
break;
case PS2_KEY_F12 :
rep("F12");
Keyboard.press(KEY_F12);
break;
case PS2_KEY_F13 :
rep("F13");
break;
case 0x1C:
Keyboard.press(KEY_BACKSPACE);
break;
default:
Serial.print("UNKNOW CODE:");
Serial.println(c, HEX);
}
}
void FuncKey_Release(unsigned int c)
{
// Keyboard.release(c);
Keyboard.releaseAll();
}
void KeyBoard_Press(unsigned int c)
{
Keyboard.press(c);
}
void KeyBoard_Release(unsigned int c)
{
Keyboard.release(c);
}
边栏推荐
- CPU的异常处理
- Batch generate folders based on file names
- 目前哪个证券公司炒股开户是最好最安全的?
- kubeadm创建kubernetes集群
- 自定义JSP[if,foreach,数据,select]标签
- 冲刺强基计划数学物理专题二
- Target tracking shooting? Target occlusion shooting? With 1.9 billion installed petal apps, what unique features attract users?
- Moher College - SQL injection vulnerability test (error reporting and blind note)
- Le principe le plus complet de formation à la précision hybride pour l'ensemble du réseau
- Oracle 数据库基本知识概念
猜你喜欢
技术干货|极速、极智、极简的昇思MindSpore Lite:助力华为Watch更加智能
简单快速的数网络(网络中的网络套娃)
In depth understanding of UDP in the transport layer and the use of UDP in sockets
Moher College - SQL injection vulnerability test (error reporting and blind note)
光谱共焦如何测量玻璃基板厚度
Amway! How to provide high-quality issue? That's what Xueba wrote!
当Transformer遇见偏微分方程求解
07 | workflow design: how to design a reasonable multi person development mode?
Technical dry goods | what is a big model? Oversized model? Foundation Model?
Outside the code: writing is the best way to force growth
随机推荐
1+1<2 ?! HESIC论文解读
冲刺强基计划数学物理专题二
Oracle database basics concepts
Deep learning method for solving mean field game theory problems
Kubeadm create kubernetes cluster
深度学习方法求解平均场博弈论问题
2022 Health Expo, Shandong health care exhibition, postpartum health and sleep health exhibition
How to open an account on the mobile phone? Is it safe to open an account online and speculate in stocks
【Mysql】时间字段默认设置为当前时间
Safe and cost-effective payment in Thailand
Sword finger offer 10- ii Frog jumping on steps
如何写好测试用例以及go单元测试工具testify简单介绍
JS library for number formatting
“message“:“Bad capabilities. Specify either app or appTopLevelWindow to create a session“
直播回顾 | 子芽&CCF TF:云原生场景下软件供应链风险治理技术浅谈
idea 热启动失效解决方案
复杂数据没头绪?
How do new investors open accounts online? Is it safe to open accounts online and speculate in stocks
kubernetes可视化界面dashboard
Interface test framework practice (I) | requests and interface request construction