首页 » 智能科技 » 电子工程师都怎么改装键盘?

电子工程师都怎么改装键盘?

东易日盛家居装饰集团股份通讯 2025-03-15 0

扫一扫用手机浏览

文章目录 [+]

功能不足丰富?自己焊一块板子。
利用不足方便?自己加一个物理外挂。
有线键盘太麻烦?自己改装成无线的。
EEwolrd论坛的工程师们就自己动手,把小小一块键盘改装得五花八门。

键盘侠闭幕者之自动反击键盘

电子工程师都怎么改装键盘? 电子工程师都怎么改装键盘? 智能科技

作者:彭丙浩 原帖地址:http://www.eeworld.com.cn/avLy9WD

电子工程师都怎么改装键盘? 电子工程师都怎么改装键盘? 智能科技
(图片来自网络侵删)

我比较喜好上网,网络天下是个没有硝烟的江湖,行走江湖,必须有件趁手的兵器,传统的机器键盘火力已经无法知足时期须要,于是我造了这个自动反击键盘,MCU+继电器+键盘电路板 ;当然最节约本钱的方案是搞个ST带USB接口的MCU芯片,直接输入字符,我对USB协议不太熟,于是就弄个成品键盘直接拿来用。
当前这个姥爷方案大略易用,效果还不错。

机器视觉打造全自动老板键智能键盘

作者:eew_dy9f48 原帖地址:http://www.eeworld.com.cn/afXzvHO

一、作品简介

自带键盘的树莓派Pi400,实在可以看作一块强大的智能键盘,作为电脑的赞助;按照项目内容层层递进,首先,先配置树莓派p400,让它作为一块普通电脑键盘;接下来,我想考试测验结合一些人工智能实现键盘命令的自动实行,比如全自动老板键,通过ESP32-CAM作为树莓派的网络摄像头,这样可以分开连线限定,可以支配在任何地方。
然后一旦识别到老板人脸,就自动发送Alt+Tab等老板键,瞬间切换至事情界面。
除此之外,由于在上述任务中我们已经实现了树莓派HID键盘的配置,因此我们还可以利用它来作为游戏助手,实现键盘宏,按一个按键打出一整套combo。
由于宏是内建在键盘中的,在pc端并没有任何干系进程,以是不会被游戏剖断为利用赞助工具。
这就可以实现很多功能上的延申,大家可以自行玩耍。

二、系统框图

功能模块一共三部分:

Pi400 HID键盘功能实现;Pi400 键盘动作的捕捉与独占;人脸识别在Pi400上的实现。

三、各部分功能解释

首先,先先容下项目中包含的硬件设计。

这个项目包括了无线网络摄像头的制作。
虽然网上有现成的ESP32CAM模块售卖,且价格非常便宜。
但是由于做工良莠不齐,导致常常翻车。
而且,ESP32性能较弱,且不支持USB,如果未来想做一些其他的开拓也可能会力不从心。
因此,趁这个项目的机会,我打算直接制作一块ESP32S2 CAM开拓板出来。

这个摄像头开拓板实在我后面还重新绘制了第二个版本,增加了tf卡槽,同时修复了飞线的问题,并由于板子面积有限将所有封装换成了0402。
但由于新版的板子打样回来焊接难度有点大,还一贯迟迟没有动手,因此先利用老版本的板子完成项目。

接下来说说软件方面,我们详细先容一下每一个功能模块的实现方法。

1. Pi400 HID 键盘功能的实现。

在github上有一个zero_hid的库,可以实现利用树莓派zero仿照hid键盘。
但这个库有一些问题,直策应用在组合键上会出很多的问题,因此我参考这个项目,重写了一下这个库。

首先科普一下HID协议,HID键盘协议是一种基于报文的协议,通过在USB总线上进行通信。
当用户按下键盘上的按键时,键盘将天生一个HID报文,并将其发送到打算机。
打算机收到报文后,根据报文的内容来仿照相应的键盘操作,例如在文本编辑器中输入字符或实行特定的功能。

HID键盘报文包含多个字段,个中最主要的是按键码(Keycode)。
按键码表示按下的键的唯一标识符,例如“A”键的按键码是0x04。
除了按键码外,报文还可以包含其他信息,如润色键(如Shift、Ctrl和Alt键)的状态和组合键的状态。

因此,在合成报文前,我们先要知道我们想输入的按键哪些是润色键,而哪些是按键,他们要分开进行处理。

在进入代码部分前,我们须要先安装一下驱动。
首先先新建一个文件,命名为isticktoit_usb,添加可实行权限,并填入以下内容:

···#!/bin/bashcd /sys/kernel/config/usb_gadget/mkdir -p isticktoitcd isticktoitecho 0x1d6b > idVendor # Linux Foundationecho 0x0104 > idProduct # Multifunction Composite Gadgetecho 0x0100 > bcdDevice # v1.0.0echo 0x0200 > bcdUSB # USB2mkdir -p strings/0x409echo "fedcba9876543210" > strings/0x409/serialnumberecho "Tobias Girstmair" > strings/0x409/manufacturerecho "iSticktoit.net USB Device" > strings/0x409/productmkdir -p configs/c.1/strings/0x409echo "Config 1: ECM network" > configs/c.1/strings/0x409/configurationecho 250 > configs/c.1/MaxPower# Add functions heremkdir -p functions/hid.usb0echo 1 > functions/hid.usb0/protocolecho 1 > functions/hid.usb0/subclassecho 8 > functions/hid.usb0/report_lengthecho -ne \\x05\\x01\\x09\\x06\\xa1\\x01\\x05\\x07\\x19\\xe0\\x29\\xe7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02\\x95\\x01\\x75\\x08\\x81\\x03\\x95\\x05\\x75\\x01\\x05\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03\\x91\\x03\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xc0 > functions/hid.usb0/report_descln -s functions/hid.usb0 configs/c.1/# End functionsls /sys/class/udc > UDC···

接着运行以下命令,完成驱动配置:

···#!/bin/bashecho "" | sudo tee -a /boot/config.***echo "# BEGIN HID Keyboard Simulation" | sudo tee -a /boot/config.***echo "dtoverlay=dwc2" | sudo tee -a /boot/config.***echo "# END HID Keyboard Simulation" | sudo tee -a /boot/config.***echo "" | sudo tee -a /etc/modulesecho "# BEGIN HID Keyboard Simulation" | sudo tee -a /etc/modulesecho "dwc2" | sudo tee -a /etc/modulesecho "libcomposite" | sudo tee -a /etc/modulesecho "# END HID Keyboard Simulation" | sudo tee -a /etc/modules# Move to before exit 0echo "" | sudo tee -a /etc/rc.localecho "# BEGIN HID Keyboard Simulation" | sudo tee -a /etc/rc.localecho "sudo ./isticktoit_usb" | sudo tee -a /etc/rc.localecho "# END HID Keyboard Simulation" | sudo tee -a /etc/rc.local···

完成后,往后每次重启完成,只须要运行一下isticktoit_usb即可。

处理报文部分的代码如下:

···from typing import Listfrom .hid import hidwritefrom .hid.keycodes import KeyCodesfrom time import sleepimport jsonimport pkgutilimport osimport pathlibclass Keyboard:def __init__(self, dev='/dev/hidg0') -> None:self.dev = devself.set_layout()self.control_pressed = []self.key_pressed = []def list_layout(self):keymaps_dir = pathlib.Path(__file__).parent.absolute() / 'keymaps'keymaps = os.listdir(keymaps_dir)files = [f for f in keymaps if f.endswith('.json')]for count, fname in enumerate(files, 1):with open(keymaps_dir / fname , encoding='UTF-8') as f:content = json.load(f)name, desc = content['Name'], content['Description']print(f'{count}. {name}: {desc}')def set_layout(self, language='US'):self.layout = json.loads( pkgutil.get_data(__name__, f"keymaps/{language}.json").decode() )def gen_list(self, keys = []):_control_pressed = []_key_pressed = []for key in keys:if key[:3] == "MOD":_control_pressed.append(KeyCodes[key])else:_key_pressed.append(KeyCodes[key])return _control_pressed, _key_presseddef gen_buf(self):self.buf = [sum(self.control_pressed),0] + self.key_pressedself.buf += [0] (8 - len(self.buf)) # fill to lenth 8########################################################################### For userdef press(self, keys = [], additive=False, hold=False):_control_pressed, _key_pressed = self.gen_list(keys)if not additive:self.control_pressed = []self.key_pressed = []self.control_pressed.extend(_control_pressed)self.control_pressed = list(set(self.control_pressed)) # remove repeated itemsself.key_pressed.extend(_key_pressed)self.key_pressed = list(set(self.key_pressed))[:6] # remove repeated items and cut until 6 itemsself.gen_buf()hidwrite.write_to_hid_interface(self.dev, self.buf)if not hold:self.release(keys)def release(self, keys = []):_control_pressed, _key_pressed = self.gen_list(keys)try:self.control_pressed = list(set(self.control_pressed) - set(_control_pressed))except:passtry:self.key_pressed = list(set(self.key_pressed) - set(_key_pressed))except:passself.gen_buf()hidwrite.write_to_hid_interface(self.dev, self.buf)def release_all(self):self.control_pressed = []self.key_pressed = []self.gen_buf()hidwrite.write_to_hid_interface(self.dev, self.buf)def text(self, string, delay=0):for c in string:key_map = self.layout['Mapping'][c]key_map = key_map[0]mods = key_map['Modifiers']keys = key_map['Keys']self.press(mods + keys)sleep(delay)···

上面这段代码把想要输出的按键分为control(润色按键)和key(普通按键)两块,再组合形成报文列表。
利用的逻辑是输入当前想要按下的按键状态,然后程序发送对应的报文。

测试一下:

···import osimport zero_hidif os.geteuid() != 0:raise ImportError('You must be root to use this library on linux.')k = zero_hid.Keyboard()k.press(["KEY_H"], additive=False, hold=False)k.press(["KEY_E"], additive=False, hold=False)k.press(["KEY_L"], additive=False, hold=False)k.press(["KEY_L"], additive=False, hold=False)k.press(["KEY_O"], additive=False, hold=False)···

press方法中填入的是一个list,表示当前按下的所有按键。
详细的键值列表在zero_hid/keymaps/US.json中。

如果电脑成功打印,表示功能正常。

2. Pi400 键盘动作的捕捉与独占。

一样平常在python中捕获键盘动作,大家利用的都是keyboard库,大略好用。
但keyboard库有个致命的问题,便是无法独占键盘。
这在我们当前的运用中是无法接管的。
试想一下,当我们想发送ctrl+alt+del时,一旦按下,树莓派和电脑都进入了安全模式。
你无法预期在键盘上的操作会在树莓派系统中整出什么幺蛾子。
因此,我们须要在捕捉键盘动作的同时,对键盘资源进行独占,以此避免按键被其他的进程捕获。
在这里我们利用evdev库来实现。

···import osimport evdevif os.geteuid() != 0:raise ImportError('You must be root to use this library on linux.')dev = evdev.InputDevice('/dev/input/event0')dev.grab() # grab 是为了独占,担保此设备不会被别的进程捕获for event in dev.read_loop():key = evdev.categorize(event)if isinstance(key, evdev.KeyEvent) and key.keystate != 2:print(key.keycode)···

按下按键,我们就可以看到对应的键值被打印在终端里。

接下来只须要把抓取到的键值组合成列表,发送到我们上一步实现的hid中即可。

细心的同学可能会意识到,evdev抓取到的的键值如果和hid的键值不匹配怎么办?这里我们就须要人工进行匹配,创建一个文件,将他们逐一对应起来。

在项目文件夹下创建一个codemap.csv文件,写入以下对应:

···KEY_LEFTCTRL,MOD_LEFT_CONTROLKEY_RIGHTCTRL,MOD_RIGHT_CONTROLKEY_LEFTALT,MOD_LEFT_ALTKEY_RIGHTALT,MOD_RIGHT_ALTKEY_LEFTSHIFT,MOD_LEFT_SHIFTKEY_RIGHTSHIFT,MOD_RIGHT_SHIFT,KEY_LEFTMETA,MOD_LEFT_GUI,,KEY_ESC,KEY_ESCKEY_TAB,KEY_TABKEY_CAPSLOCK,KEY_CAPSLOCK,KEY_NUMLOCK,KEY_NUMLOCKKEY_SYSRQ,KEY_SYSRQKEY_DELETE,KEY_DELETEKEY_INSERT,KEY_INSERTKEY_BACKSPACE,KEY_BACKSPACEKEY_ENTER,KEY_ENTER,KEY_SPACE,KEY_SPACE,KEY_UP,KEY_UPKEY_DOWN,KEY_DOWNKEY_LEFT,KEY_LEFTKEY_RIGHT,KEY_RIGHT,KEY_PAGEUP,KEY_PAGEUPKEY_PAGEDOWN,KEY_PAGEDOWNKEY_HOME,KEY_HOMEKEY_END,KEY_END,KEY_F1,KEY_F1KEY_F2,KEY_F2KEY_F3,KEY_F3KEY_F4,KEY_F4KEY_F5,KEY_F5KEY_F6,KEY_F6KEY_F7,KEY_F7KEY_F8,KEY_F8KEY_F9,KEY_F9KEY_F10,KEY_F10KEY_F11,KEY_F11KEY_F12,KEY_F12,KEY_GRAVE,KEY_GRAVEKEY_1,KEY_1KEY_2,KEY_2KEY_3,KEY_3KEY_4,KEY_4KEY_5,KEY_5KEY_6,KEY_6KEY_7,KEY_7KEY_8,KEY_8KEY_9,KEY_9KEY_0,KEY_0KEY_MINUS,KEY_MINUSKEY_EQUAL,KEY_EQUAL,KEY_Q,KEY_QKEY_W,KEY_WKEY_E,KEY_EKEY_R,KEY_RKEY_T,KEY_TKEY_Y,KEY_YKEY_U,KEY_UKEY_I,KEY_IKEY_O,KEY_OKEY_P,KEY_PKEY_A,KEY_AKEY_S,KEY_SKEY_D,KEY_DKEY_F,KEY_FKEY_G,KEY_GKEY_H,KEY_HKEY_J,KEY_JKEY_K,KEY_KKEY_L,KEY_LKEY_Z,KEY_ZKEY_X,KEY_XKEY_C,KEY_CKEY_V,KEY_VKEY_B,KEY_BKEY_N,KEY_NKEY_M,KEY_M,KEY_LEFTBRACE,KEY_LEFTBRACEKEY_RIGHTBRACE,KEY_RIGHTBRACEKEY_BACKSLASH,KEY_BACKSLASHKEY_SEMICOLON,KEY_SEMICOLONKEY_APOSTROPHE,KEY_APOSTROPHEKEY_COMMA,KEY_COMMAKEY_DOT,KEY_DOTKEY_SLASH,KEY_SLASH,KEY_KP0,KEY_KP0KEY_KP1,KEY_KP1KEY_KP2,KEY_KP2KEY_KP3,KEY_KP3KEY_KP4,KEY_KP4KEY_KP5,KEY_KP5KEY_KP6,KEY_KP6KEY_KP7,KEY_KP7KEY_KP8,KEY_KP8KEY_KP9,KEY_KP9KEY_KPASTERISK,KEY_KPASTERISKKEY_KPMINUS,KEY_KPMINUSKEY_KPPLUS,KEY_KPPLUSKEY_KPDOT,KEY_KPDOTKEY_KPSLASH,KEY_KPSLASH···

接着在代码中,我们只须要打开该文件,转换为字典,删除空缺项,即可制作好对应的字典。
每次捕捉到按键后,利用字典翻译一下即可。

···with open('./codemap.csv', 'r') as file:reader = csv.reader(file)codemap = {rows[0]:rows[1] for rows in reader}del codemap[""]···

3. 人脸识别在Pi400上的实现。

实现人脸识别我们利用的工具是ultralytics。
Ultralytics安装非常大略,只须要pip install ultralytics即可。
唯一须要把稳的是我们须要改换一下pytorch的版本,否则会涌现Segmentation fault

···pip uninstall torch torchvisionpip install torch==2.0.1 torchvision==0.15.2 torchaudio==2.0.2···

完成安装后,我们要利用stream的方法,从网络推流中获取到***流。
***流来源是我们一开始制作的ESP32 S2 CAM开拓板。
开拓板上烧录的是arduino ide上的官方CameraWebServer例程。
除了常规的选择对应开拓板并修正wifi信息外,我们还须要自定义一下开拓板引脚。
假设我们这里选择#define CAMERA_MODEL_ESP32S2_CAM_BOARD,那么我们要把camera_pins.h中的对应部分改成:

···#elif defined(CAMERA_MODEL_ESP32S2_CAM_BOARD)#define PWDN_GPIO_NUM -1#define RESET_GPIO_NUM -1#define XCLK_GPIO_NUM 2#define SIOD_GPIO_NUM 42#define SIOC_GPIO_NUM 41#define Y9_GPIO_NUM 1#define Y8_GPIO_NUM 3#define Y7_GPIO_NUM 4#define Y6_GPIO_NUM 6#define Y5_GPIO_NUM 8#define Y4_GPIO_NUM 14#define Y3_GPIO_NUM 9#define Y2_GPIO_NUM 7#define VSYNC_GPIO_NUM 16#define HREF_GPIO_NUM 15#define PCLK_GPIO_NUM 5#define LED_GPIO_NUM 45···

按照下图所示配置进行烧录即可。

Pi400这边的代码比较大略,ultralytics已经被设计的非常易于利用。

···from ultralytics import YOLOimport requestsimport timeurl = "http://192.168.8.171"model = YOLO("yolov8n.pt")requests.get(url+"/control?var=framesize&val=" + str(8))results = model.predict(url+":81/stream", stream=True, show=True, conf = 0.5)for result in results:for box in result.boxes:class_id = result.names[box.cls[0].item()]cords = box.xyxy[0].tolist()cords = [round(x) for x in cords]conf = round(box.conf[0].item(), 2)print("Object type:", class_id)print("Coordinates:", cords)print("Probability:", conf)print("---")···

如果所安装的树莓派系统是桌面版本,我们在桌面版本上运行以上程序,就可以看到画面。
如果是仅有terminal的系统,terminal中也会有相应信息打印。

末了我们只须要整合上述功能,就可以实现带有全自动老板键的智能键盘。

完全主程序代码如下:

···import zero_hidimport evdevimport csvimport signalimport osimport threadingif os.geteuid() != 0:raise ImportError('You must be root to use this library on linux.')k = zero_hid.Keyboard()# dev = evdev.InputDevice('/dev/input/by-id/usb-_Raspberry_Pi_Internal_Keyboard-event-kbd')dev = evdev.InputDevice('/dev/input/event0')dev.grab() # grab 是为了独占,担保此设备不会被别的进程捕获with open('./codemap.csv', 'r') as file:reader = csv.reader(file)codemap = {rows[0]:rows[1] for rows in reader}del codemap[""]curr_pressed = []def key_input(key):global curr_pressedif isinstance(key, evdev.KeyEvent) and key.keystate != 2:if key.keystate == 1:curr_pressed.append(key.keycode)if key.keystate == 0:curr_pressed.remove(key.keycode)print("\r" + "CODE: " + key.keycode + " ;STAT: " + str(key.keystate) + " "40, end="")keys = [codemap[i] for i in curr_pressed]k.press(keys, additive=False, hold=True)def handler(signal, frame):k.release_all()dev.ungrab()dev.close()exit()signal.signal(signal.SIGTSTP, handler) # Ctrl+Zsignal.signal(signal.SIGINT, handler) # Ctrl+Cdef thread1():for event in dev.read_loop():try:key_input(evdev.categorize(event))except Exception as error:print(error)t1 = threading.Thread(target=thread1, daemon=True)t1.start()from ultralytics import YOLOimport requestsurl = "http://192.168.8.171"model = YOLO("yolov8n.pt")requests.get(url+"/control?var=framesize&val=" + str(8))results = model.predict(url+":81/stream", stream=True, show=True, conf = 0.5)delay = 1count = 0mode = 0pre_mode = 0for result in results:try:for box in result.boxes:class_id = result.names[box.cls[0].item()]cords = box.xyxy[0].tolist()cords = [round(x) for x in cords]conf = round(box.conf[0].item(), 2)print("Object type:", class_id)print("Coordinates:", cords)print("Probability:", conf)print("---")if class_id == "person":mode = 1count = 0if mode != pre_mode:pre_mode = modek.press(["MOD_LEFT_ALT","KEY_TAB"], additive=False, hold=False)print("triggered!!!")count += 1if count > delay:mode = 0pre_mode = modeexcept Exception as error:print(error)···

罗技K260键盘套装改锂电池供电及加事情指示

作者:dcexpert 原帖地址:http://www.eeworld.com.cn/a0Guf54

看得手边的罗技K260无线键盘,就想改造一下。

K260利用了两个AAA电池供电,虽说K260省电已经做的很不错,但是为了环保,以及避免电池没电时找不到电池改换,还有电池漏液造成的堕落,就想改成锂电池供电。

键盘很随意马虎拆开,取下反面的十多颗螺丝,用撬棒轻微用力把外壳的卡扣松开,就可以轻松把后盖取下

拆开后可以看到按键部分分三层,一层是按键部分,其余两层分别是按键的行列电路。
这也是薄膜键盘的标准构造。

主控芯片利用了 nordic 的 nrf31504,这是nordic公司的一颗集成增强8051内核的2.4G无线收发器,带有16K ROM和512字节RAM。
在nordic的网站上已经搜索不到这个芯片,估计已经停产了。

比较有趣的是天线部分,居然把长度标上去了。

系统原来利用2节AAA电池供电,电压范围是2-3.2V,而主芯片 nrf31504的电源范围是 1.9-3.6V。
利用锂电池供电(电压范围是3.3-4.2V),最大略办法便是加一个二极管,将电源降落0.6V,这样电源范围便是2.7-3.6V,可以知足电压哀求。
但是这样改造觉得短缺了一点意见意义性,就想能不能换一种办法,增加一个LED根据电流指示事情状态,既能反响出事情状态,看起来也更有科技感。
用万用表实测键盘的待机电流约35uA,发射时电流约5mA。
电流可以通过电流传感器(如TI的INA180)转换为电压,但是春节期间无法打样,PCB打样焊接周期也较长,又不想连续等待,就想还有没有其它办法。
考虑到键盘的功耗很低,如果把LED串联到电源中,也是可以知足功耗哀求,但是电压就不足了,这时就须要提高供电的电压才行。
一颗赤色LED导通压降约1.5V,黄色和普通绿色LED约1.8V,蓝色白色LED的压降较高,约2.3-2.7V。
这样算下来,利用5V旁边供电在串联一个黄色LED正得当,这样的话利用移动电源或TWS耳机充电盒的主板,就可以实现充电管理和升压两个功能,既大略又能知足哀求。

虽然键盘看起来很大,但是内部空间实在比较小。
经由翻箱倒柜找了一圈,终于在箱底找出几个得当的元件。

电池,用了两种电池,并联以提高容量。
一个140mAH,另一个200mAH。

这个圆柱形电池不知道大家认识不

拆开后是这样的。

移动电源主板,这个还是几年前社区网友老杨供应的。
把USB座拆掉后,恰好可以放在键盘的空隙中。

紧张元件的布局

由于键盘是不透明的,为了让指示灯露出来,用电动螺丝刀和钻头,在适当的位置钻孔。
充电指示灯处用1.8mm钻头,事情指示灯用3mm的LED,利用2.8mm的钻头。
充电指示灯的空用热熔胶堵住,防止进灰进水,同时也能透光。

插入LED,并用胶水固定。

再焊接各部分导线

用透明胶带固定电源板和导线

末了测试一下充电和键盘功能,没有问题就可以将后盖装回去。
下面是改装后的效果:

充电指示灯效果。

待机时指示灯状态,每秒唤醒10次旁边。

按下键盘,指示灯状态,可以看到按键后不会立即休眠。

CIY64机器键盘锂电池充电改装

作者:IC爬虫 原帖地址:http://www.eeworld.com.cn/a00SefD

CIY64 这款客制化键盘我有两把,利用快两年了,几个月就要换电池,这些废弃的电池没地方回收真是有点污染环境,而且有时碰到没有备用电池的情形非常抓狂,两节南孚7号电池也要6块钱,以是早就有把键盘改成充电的想法。
本来想利用无线充电的方案,但是这把键盘的脚撑是不可调节的,而且高低有限,充电时不好放在无线充电器上。
又不想给这把键盘的外壳开孔,以是做个能在7号电池仓放下的充电板,1000mah的锂电池估计可以用非常的久,须要用的时候拉出来充实在也没啥问题。

方案:利用ME4054作为充电IC,这款IC最大可以800ma的电流给锂电池充电,但是发热比较大,我不须要快速给锂电池充电,而且避免电路板过热,可以利用这颗芯片的外部配置电阻就充电电流限定在300mA,这个时候芯片温度还可以接管。
这款键盘利用的是两节7号电池供电,为了避免锂电池的电压过高破坏键盘的原有的电路,加了一颗PAM2305AABADJ DC-DC降压芯片,将共给键盘掌握板的电压限定到2.6V旁边。

电路:

安装:

充电电流,这张图是我将充电配置为100ma,有点慢,后面改成了300MA,给1000mah的电池充电,从3.7v充满,耗时一个半小时:

CH582有线键盘转蓝牙键盘

作者:pomin 原帖地址:http://www.eeworld.com.cn/a5WjDaT

结合USB-HOST和蓝牙HID键盘的例程制作了一个有线键盘转蓝牙键盘的设备,代码如下:

/// 头文件包含 /#include "CONFIG.h"#include "HAL.h"#include "hiddev.h"#include "hidkbd.h"/ GLOBAL TYPEDEFS /__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4];__attribute__((aligned(4))) uint8_t RxBuffer[MAX_PACKET_SIZE]; // IN, must even address__attribute__((aligned(4))) uint8_t TxBuffer[MAX_PACKET_SIZE]; // OUT, must even addressextern uint8_t need_send;#if(defined(BLE_MAC)) && (BLE_MAC == TRUE)const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02};#endif/ @fn Main_Circulation [url=home.php?mod=space&uid=159083]@brief[/url] 主循环 [url=home.php?mod=space&uid=784970]@return[/url] none /__HIGH_CODEvoid Main_Circulation(){ TMOS_SystemProcess();}/ @fn main @brief 主函数 @return none /int main(void){ uint8_t i, s, k, len, endp; uint16_t loc;#if(defined(DCDC_ENABLE)) && (DCDC_ENABLE == TRUE) PWR_DCDCCfg(ENABLE);#endif SetSysClock(CLK_SOURCE_PLL_60MHz);#if(defined(HAL_SLEEP)) && (HAL_SLEEP == TRUE) GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU); GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);#endif / 开启电压监控 / PowerMonitor(ENABLE, HALevel_2V1);#ifdef DEBUG GPIOA_SetBits(bTXD1); GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU); GPIOA_ModeCfg(bTXD1, GPIO_ModeOut_PP_5mA); UART1_DefInit();#endif PRINT("%s\n", VER_LIB); CH58X_BLEInit(); HAL_Init(); GAPRole_PeripheralInit(); HidDev_Init(); HidEmu_Init(); PRINT("Start @ChipID=%02X\n", R8_CHIP_ID); pU2HOST_RX_RAM_Addr = RxBuffer; pU2HOST_TX_RAM_Addr = TxBuffer; USB2_HostInit(); PRINT("Wait Device In\n"); while(1) { Main_Circulation(); s = ERR_SUCCESS; if(R8_USB2_INT_FG & RB_UIF_DETECT) { // 如果有USB主机检测中断则处理 R8_USB2_INT_FG = RB_UIF_DETECT; s = AnalyzeRootU2Hub(); if(s == ERR_USB_CONNECT) FoundNewU2Dev = 1; } if(FoundNewU2Dev || s == ERR_USB_CONNECT) { // 有新的USB设备插入 FoundNewU2Dev = 0; mDelaymS(200); // 由于USB设备刚插入尚未稳定,故等待USB设备数百毫秒,肃清插拔抖动 s = InitRootU2Device(); // 初始化USB设备 if(s != ERR_SUCCESS) { PRINT("EnumAllRootDev err = %02X\n", (uint16_t)s); } } / 如果下端连接的是HUB,则先列举HUB / s = EnumAllU2HubPort(); // 列举所有ROOT-HUB端口下外部HUB后的二级USB设备 if(s != ERR_SUCCESS) { // 可能是HUB断开了 PRINT("EnumAllHubPort err = %02X\n", (uint16_t)s); } / 如果设备是键盘 / loc = U2SearchTypeDevice(DEV_TYPE_KEYBOARD); // 在ROOT-HUB以及外部HUB各端口上搜索指定类型的设备所在的端口号 if(loc != 0xFFFF) { // 找到了,如果有两个KeyBoard如何处理? i = (uint8_t)(loc >> 8); len = (uint8_t)loc; SelectU2HubPort(len); // 选择操作指定的ROOT-HUB端口,设置当前USB速率以及被操作设备的USB地址 endp = len ? DevOnU2HubPort[len - 1].GpVar[0] : ThisUsb2Dev.GpVar[0]; // 中断端点的地址,位7用于同步标志位 if(endp & USB_ENDP_ADDR_MASK) { // 端点有效 s = USB2HostTransact(USB_PID_IN << 4 | endp & 0x7F, endp & 0x80 ? RB_UH_R_TOG | RB_UH_T_TOG : 0, 0); // 传输事务,获取数据,NAK不重试 if(s == ERR_SUCCESS) { endp ^= 0x80; // 同步标志翻转 if(len) DevOnU2HubPort[len - 1].GpVar[0] = endp; // 保存同步标志位 else ThisUsb2Dev.GpVar[0] = endp; len = R8_USB2_RX_LEN; // 吸收到的数据长度 if(len) { U2SETorOFFNumLock(RxBuffer); PRINT("keyboard data: "); for(i = 0; i < len; i++) { PRINT("x%02X ", (uint16_t)(RxBuffer[i])); } PRINT("\n"); need_send = 1; } } else if(s != (USB_PID_NAK | ERR_USB_TRANSFER)) { PRINT("keyboard error %02x\n", (uint16_t)s); // 可能是断开了 } } else { PRINT("keyboard no interrupt endpoint\n"); } SetUsb2Speed(1); // 默认为全速 } }}/ endfile @ main /

设置need_send全局变量作为标志位,对付蓝牙HID线程修正如下:

if(events & START_REPORT_EVT) { if (need_send) { HidDev_Report(HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT, HID_KEYBOARD_IN_RPT_LEN, RxBuffer); need_send = 0; } tmos_start_task(hidEmuTaskId, START_REPORT_EVT, 1); return (events ^ START_REPORT_EVT); }

将HID线程的周期改为1ms来提高蓝牙键盘的速率。

实物:

(工程文件可至原帖内***)

扫描二维码,与作者互换老机器键盘改造USB,QWERTY/Dvorak一键切换

作者:cruelfox 原帖地址:http://www.eeworld.com.cn/aWvjfbD

这个DIY项目的想法已经有良久了,如今终于达到了的设计的初衷。
要表示“任性”的特点,先先容背景吧。

在看这个帖子的诸位一定都在用打算机键盘吧。
键盘上的数字键是1到9从左至右排列,或者是右小键盘区那样三个一排有序排列,反正规律很明显。
但是字母键却不是A,B,C...到Z这么按字母序有规律地排下来的。
我刚打仗电脑(实在还是学习机)的时候,没在意这个问题,以为是要盲打嘛,反正对两手的手指头来说,按字母序排列并没有什么好处。
于是用多了这些排列也就记住了,从来不管它为什么要这样。
实在,PC的键盘键位排布上是延用了打字机的键盘,这是设备演化过程中很自然的一个延续。
打字机的历史就要早很多了,我没有亲见过打字机长什么样,而且,咱们汉字是铅字打上去的,和英文打字机办法完备不同。

上面这个照片(来自wikipedia),是"Sholes and Glidden Type-Writer.",第一个得到成功的商用打字机(1873)。
请把稳它的键盘字母键排列。

为什么得到这样一个字母排列?在当时的确经由了多次的优化改进,由于打字机是机器的动作,要只管即便避免连续的击键引起冲突。
结果是由于商业上的成功,QWERTY这个布局也随着被越来越多的制造商接管采取。
在非英语措辞的键盘上,个别键位可能不同,属大同小异了。
最早的IBM PC键盘:

其实在电传动打字机问世之后,打字键盘的键位布局就可以自由了。
但是QWERTY的盛行没有被改变——习气的力量是强大的。
虽然是大众所接管,QWERTY也有被人诟病的地方,比如说旁边手分配不平衡,在英语里面单独用左手能打出来的单词远比单独用右手的多。
那么,除了QWERTY还能用啥?在ANSI标准里面还有其余一个键盘布局,叫做DVORAK.

Dvorak(德沃夏克)布局,因此其发明人之一: August Dvorak 的姓命名的。
在20世纪30年代,Dvorak 和 Dealey 在他们多年的研究事情根本上发明了Dvorak布局,目标是减少打字出错几率、提高速率和减少手的疲倦。
最始创造的布局是这个样子:

Dvorak布局的最明显特色是让利用频率最高的键安排在中间的一排(Home row),这样手指不用移动就触得到。
当然还有旁边手均衡的设计等等。
只管不是所有人都赞许Dvorak布局能够比QWERTY布局提高键盘输入的效率,最快打字速率的记录的确是在Dvorak键盘上创造的。

我是常常要写代码的人,对键盘哀求比较高,一定要顺手。
从1998年拥有电脑开始,第一块键盘用了5年,实在是塑料构造磨损严重了才换了。
第二块键盘用了大概也有5年,第三块是淘宝买到的和第二块同样的。
除了手感,我对键盘还有个挑剔是要大回车键(老键盘惯出来的)。
到了用上条记本电脑,键盘考题只能忍忍了。
我末了买的一块Benq的”轻指飞扬"绝版键盘由于是USB,作为条记本键盘替补一贯保留到现在。

到2012年下半年,我在淘宝创造了有“机器键盘”这东东,认识了Cherry MX轴。
然后到2013年农历年后,我花一百多一点买了一块老旧的国产青轴机器键盘,虽然很迂腐状态也差了,敲了一下子我就创造:这便是我要的手感啊,一比起来用了多年的薄膜键盘切实其实太委曲手指了。
我后来花了更多的钱买了新的轴(便是机器键盘的开关)来改换修复,使之成为上班工浸染。

机器键盘用着爽,后来我创造手指别扭的地方了,跟QWERTY键盘布局有关系。
理解了Dvorak布局之后,我下定决心,换用Dvorak. 这个过程很漫长,大约是一年往后才抛开了QWERTY根深蒂固的影响。
到如今两年多,我也没有肯定我的输入速率是否达到自己曾经QWERTY时候最快的水平,不过可以肯定的是换了Dvorak,手指头是舒畅了。
借个图解释两种布局的差别:

从QWERTY换到Dvorak,除了决心以及过程中的痛楚外,还有额外的本钱。
一是操作系统的支持,虽然DOS, Windows, Linux都支持Dvorak,但须要加载keymap,或者设置键盘布局,且每台机器,每个用的系统都要改。
在Windows上,Dvorak和默认的En-US是平级的,但中文输入法只能用En-US也便是压根儿没考虑Dvorak. 于是我将en_us.dll直接更换掉了,但也不是完美的办理,比如Sogou拼音会从更底层调用读键盘,还是没法用(于是我一贯用智能ABC咯)。
二是用别人电脑的时候,比如同事要请帮忙,又不能SSH过去,我就只好盯着键盘来“一指禅”了;以及电脑安装系统的时候,应急启动时候,类似的困难。
三是我的电脑夫人也就没法用,同样的道理。
四是虽然内部变成Dvorak,键盘上印的还是QWERTY那样的,必须盲打,必须双手干活,不能一只手拿着食品啦。
这时候我多希望它还是QWERTY,可以用用一指禅。

综上,在操作系统软件层次上修正键盘布局来利用Dvorak,问题还是多多。
那么我在键盘上面改,硬件直接搞定好了。
附带的好处是可以随时切换键盘布局,键盘也可以共享给夫人用。
国产老机器键盘里面主控是8049 MCU,虽然不能对它编程,我换掉它还是可以的。
于是就有了这次的“任性"DIY。

先是改造的工具,主角: 这已经是拆解出机器键盘中的PCB板+钢板,并且拆掉了全部的键轴之后的样子。
这块键盘买来时的成色相称差,很脏,惟有键帽还不错,但原来的轴已进灰,状态差。

轴全部拆下来之后才能将钢板和PCB分离,不然是被卡住的。
原来键盘里面的灰比照片上还多得多。
把稳到这块DIP40的芯片,便是键盘的主控。

特写,80C49

LED部分,利用了一片D触发器锁存指示灯状态。

暴力毁坏,将80C49拆掉。

拆掉原来的键盘主控,我用什么顶替呢?没有引脚全兼容的单片机了,而且我要制作USB键盘,以是……STM32F072,做块一样大小的PCB. 由于紧张是利用原有的键盘扫描矩阵,有些引脚是不须要连的。

焊好元件后的板子,准备更换80C49。

用剪下的电阻腿作连接吧,对好位把引脚都焊上。
STM32F0的SWD接口务必要留出来***程序的。

这是在软件开拓当中调试的场景。
USB线须要飞线,由于原来的键盘PCB上就没有USB。

开始安装钢板,主键区焊上全新的Cherry MX茶轴(2.5 RMB一颗)。
F区暂且空着,由于利用频率不高,换新轴就显得摧残浪费蹂躏了,等下再把部分旧轴洗濯一下装回去。

我设计的MCU PCB要在键盘PCB和钢板之间。
除了SWD的引脚,把UART飞线出来供调试的时时之需。

主键区键帽就位。

编辑键区也安装好,确认这里更换后不会有冲突。
调试用的线和针脚往后是要拆掉的。

末了的组装,USB线,以及切换键盘布局的附加按钮。
部分键轴还没有装,低优先级的。

DIY过程直播完了,下面说硬件的设计。
80C49是块MCU,貌似也就在PS/2键盘上面用。
搜到其datasheet对引脚的定义:

实在最关心的还是键盘矩阵怎么接的,这个我就靠人肉了,在的PCB背面寻着每条扫描行或列线找,记录在草稿纸上。
终极整理出来的结果是这样的:(最上边和最右边铅笔写的数字是引脚编号)

扫描矩阵是8x14的,最多可以支持112个按键,实际上只有101个键,空出了一些。
对照上面那个引脚定义,可以把用到的I/O口确定了。
除了电源引脚,剩下还有几个引脚利用到:PS/2的CLK和DATA占用2个,状态指示LED的电路占用1个,AT/XT开关利用了一个。
我用STM32F072C8,有48个引脚刚好是够的,富余的I/O就飞线引出了。

这是我设计的电路图:

PCB Layout:

不从80C49引脚上走的旗子暗记包括: SWD接口,USB D+/D-,USART TX/RX,额外两个可用I/O。

软件上的事情比硬件多得多。
由于想改造成USB键盘,不得不把USB HID的实现轻微看懂一下。
PS/2模式硬件上也是保留的,暂时我还没去写软件。

总结一下,USB HID键盘须要利用两种HID报告:一是从设备到主机的,按键状态的报告,8字节;二是主机到设备的,指示灯状态的报告,1字节。
第一个报告我利用EP1(Endpoint 1, 端点1)来发送,中断传输;第二个报告就利用默认的EP0,掌握传输。
USB的描述符,可以从现有的USB键盘上修正而来。
(完全代码和工程文件见原帖)

标签:

相关文章

淮安市公共交通领域银联移动支付上线

自9月10日起,银联移动支付产品在淮安市公共交通领域全面上线,产品覆盖淮安市县(区 ,覆盖公交车、有轨电车、出租车、市县(区 城际...

智能科技 2025-04-04 阅读0 评论0