数码之家

 找回密码
 立即注册
搜索
查看: 1030|回复: 45

[外设] 不飞线---优雅复活主控挂掉的机械键盘

[复制链接]
发表于 2024-2-18 09:17:38 | 显示全部楼层 |阅读模式

爱科技、爱创意、爱折腾、爱极致,我们都是技术控

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 飞向狙沙 于 2024-2-18 09:31 编辑

       18年得到一把主控挂掉的机械键盘,一开始打算拆轴,后来想修复,经历过stm32最小系统飞线修复,但是太丑,不想一把好看的键盘有一颗这么乱七八糟的芯,想美观不飞线要么就用原厂或引脚兼容单片机,这个搞不了,要么就用FPC做转接,但是以前的FPC打样价格太贵,都够买把全新键盘了,无解,就扔那吃灰了。
        最近看到立创FPC支持白嫖了,那就搞起来,想到手里还有STC送的STC32,决定支持下STC,使用STC32彻底重做,可以直接USB升级,不需要晶振,不需要LDO降压,就是这么妙。
功能需求:
  • 标准键盘全功能
  • 多媒体键盘全功能
  • Win键锁定
  • RGB背光(本次未实现,不是通用方案,懒得搞了)
  • 密码本(FN组合键或者特殊组合键直接输出密码,想了想不太安全,不实现了)
  • 1000回报率(可自定义,最高应该能到2000)
  • 30ms滤波(可自定义)

        本次DIY稍作修改即可支持修复所有的主控损坏键盘,实际上也支持全新DIY一把机械键盘。
image-20240217151814607.png

第一步:硬件测量
       换芯修复键盘实际上比重新DIY还麻烦,需要兼顾原来的设计,需要检测按键引脚连接定义,对于带RGB的键盘还要检测RGB链接定义,更加复杂。N年前的第一版方案是通过万用表一点一点测量,相当苦逼,测了很久才测完。这次做了FPC转接板,直接重写了个按键扫描程序,只需要测量NumLock等指示灯的定义,剩下的按键引脚直接程序扫描完成。
       清理焊盘,测量特殊引脚定义,主要指USB接口,三个指示灯连接,电源脚,这个键盘的RGB灯用的I2C接口的IC控制,所以需要测量I2C接口的连接,然后通过观察引脚的焊盘连接确定几个空连接的引脚(Pin2Pin,不筛选出空连接的引脚IO可能不够用),如下图。
image-20240217150613735.png image-20240217150841028.png
       确定了特殊引脚后就可以开始画PCB了,优先把特殊引脚连接好,其他引脚就近找最方便的引脚连接就行,后续按键连接通过程序扫描完成。画PCB可以使用小窍门,直接把键盘PCB的照片调整尺寸到实际大小然后通过立创eda的彩色丝印放置,方便原件定位。
       首次下载通过按下FPC上的P32按键试下进入下载模式,后续通过键盘上的组合键进入下载模式。拉出了txrx,用于调试。芯片位置4脚打孔,防止焊接时PCB焊接有错位导致的应力。
image-20240217152727418.png
      白嫖的FPC到手,这里有个需要注意的地方,金手指尽量不要直接到边,保留0.2mm空间,不然激光切割的时候会导致碳化发黑,我就踩了这个坑。
image-20240217153632661.png
       焊接完成,实际上只要焊TXRX两根线就行,或者通过USB口转接串口的话什么线都不用焊,看自己方便吧,我是拿公司折腾懒得带键盘所以先飞线了。
image-20240217154418237.png
       调试完成后上键盘,清空飞线,背面贴点双面胶固定,正面也用704固定了下,完美。
image-20240217154824277.png
第二步:按键定义扫描
       传统键盘按键连接都是以矩阵方式实现,机械键盘为了实现全键无冲或部分无冲可能会增加一个二极管,原理图如下:
image-20240217160951260.png
没有增加无冲二极管的直接把上图二极管短接,实际连接千千万,原理都是这一种,此处约定存在无冲二极管的,二极管正极连接的IO为列col,负极为行row,不存在无冲二极管时行列随意。
      整理键盘PCB连接时使用到的连接除指示灯、RGB类特殊功能外的所有IO,打开keyboard.c文件,把整理后的IO放到这两个数组,IO顺序暂时无所谓,两个数组的IO不要重复,即任意一部分IO放到rowPins里,剩下的放到colPins里,注意ROW_NUM和COL_NUM的宏定义要按照实际数量调整,不然可能会出现意想不到的意外。
  1. uint8_t rowPins[ROW_NUM]={GP11,GP47,GP14,GP21,GP22,GP23,GP42};
  2. uint8_t colPins[COL_NUM]={GP27,GP04,GP03,GP45,GP02,GP00,GP46};
复制代码

       打开common.h文件,去掉//#define ENABLE_KEY_DEFINE_SCAN前边的注释,编译下载后连接TTL,监视串口,按下键盘任意键,串口会打印扫描到的连接定义,如串口显示press P11--P22表示按下的按键连接着P11和P22两个脚,不存在无冲二极管,如显示press P11->P22表示存在无冲二极管,P11需要放到列数组,P22放到行数组。在表格中记录每个按键的行列指示,即可整理出引脚连接情况。
image-20240217161917622.png
第三步:引脚和键值调整
        按照整理出的引脚连接情况重新调整rowPins[ROW_NUM]和colPins[COL_NUM]数组里的引脚定义。同时按照表格里的按键调整keyMaps里的键值,同时检查FN键位置,调整common.h中FN对应的行列位置。
  1. //FN键位置
  2. #define FN_ROW_POS 8
  3. #define FN_COL_POS 2
复制代码

image-20240217161830103.png
       到此按键扫描工作完成。
第四步:多媒体键定义
       现在基本上所有的键盘都有多媒体键定义,如静音、音量调节、下一首等,通过FN组合键实现,看qmk等固件都是通过分层设计实现,对于这种全键盘懒得搞这么复杂了,直接单独检测了。
       打开keyboard.c文件,找到keyboardSend方法,在switch里case ID_KB_F1代表的就是FN+F1组合键,只要修改对应红框里的键值就能实现对应多媒体键。

image-20240217162521263.png
具体多媒体键的键值键keycode.h文件,如想在F1实现打开计算器只需要把上方红框里的键值ID_MK_MediaSelect替换为ID_MK_Calculator即可。
image-20240217162727277.png
       默认实现了WinLock功能,即win键锁定,防止打游戏之类的情况下误触发,按下Fn+WinL实现锁定,再按一次恢复正常,但是这个功能没做持久化,即本次锁定后如果电脑关机或者键盘重插,会自动恢复正常。
image-20240217163049800.png
实际上程序方面支持关机键等系统控制功能,但是这个功能基本上没人用,所以未作实现。
程序编译、下载
stc32的程序编译使用keil c521,下载工具ISP,具体安装操作看官方说明




155059015.jpg

打赏

参与人数 8家元 +229 收起 理由
nokia5320 + 15
亚历山大 + 24
hongo + 30 優秀文章
menwawork + 30 技术不错,可惜右上角品牌讨人厌。.
qrut + 30 謝謝分享
kkdkj + 30 謝謝分享
dulme + 10 原創內容
家睦 + 60

查看全部打赏

 楼主| 发表于 2024-2-18 09:19:39 | 显示全部楼层
本帖最后由 飞向狙沙 于 2024-2-18 09:27 编辑

原理梳理
       从键盘修复的角度来看实际上这么操作还是蛮复杂的,那么从设计一把全新键盘的角度再来重新梳理下整个流程。
按键检测
键盘的灵魂就是按键检测,精准的检测到一个按键按下,抬起,然后通过USB接口发送给电脑。玩过单片机的基本上都用过按键,最简单实现方式就是给按键一脚接上拉电阻,一脚接地(下拉电阻或ADC方案此处忽略),检测上拉脚的电平,高电平即为抬起,低电平即为按下。
OIP-C.HcZYcEAewTwhAByNa8aEpQAAAA.png

按键消抖               
       按键检测遇到的第一个问题就是抖动,明明只按下了一次,但是程序却检测到了很多次(具体原因见:按键的硬件消抖电路原理详解),消抖方法基本上都是通过软件解决,第一次检测到按键按下后一段时间内就不在检测按键是否抬起,等过了几十毫秒按键稳定后才开始检测按键是否抬起,检测到按键抬起后同样几十毫秒内就不再检测按键是否按下。以此消除抖动带来的误触。
v2-adc08d592fb6757657bfb6d7028ca6d4_b.jpg
      程序中对每个按键定义一个8byte的变量,用来记录按键是否按下和按下时常,以键盘1000回报率来说每ms检测一轮按键状态,状态没有变化则这个变量+1,最长可记录128ms
// 按键时常统计表,第八位用于记录按键状态,按下为1,抬起为0
// 低7位用于记录按键当前状态保持时常,最大值127
uint8_t keyPressCount[ROW_NUM][COL_NUM];
所以滤波时间可自定义,在common.h中#define KEYBOARD_FILTERING_COUNT 30,实际这里配置的是检测次数,回报率1000则1ms检测一次,配置为30即滤波时间为30ms,如果回报率设置为2000则0.5ms检测一次,滤波时间为15ms。

矩阵按键
       上边实现了一个按键的检测,但是这样每个脚绑定一个按键,usb键盘百八十个脚,单片机IO不够用,所以就引申出了矩阵键盘(具体扫描原理不做介绍,需要的自己检索下)
155059015.jpg
      但是矩阵键盘存在一个问题,就是存在鬼影问题,当多个按键同时按下时可能会导致误报,如上图1 2 5同时按下,程序会错误的检测到6也按下了(具体原因可参考动图解说键盘矩阵如何工作),为了解决鬼影问题就在电路中加入了无冲二极管,实现了全键盘无冲突。
      到此最基础的按键检测功能就实现了。
扫描程序
      程序中加了基础注解,这里第一个问题就是STC的IO是sbit的位寻址,没办法放到数组,所以只能自己重新定义个一下IO,结果就是导致IO设置或者获取状态时需要套好几层马甲,速度较位寻址慢了不少,好在键盘也对速度没太高要求。对FN做了特殊处理,只有当其他按键都抬起时在更新FN状态,防止按下FN+F2调小音量,但优先抬起FN再抬起F2这种有点憨憨的操作时误触发F2。
  1. void keyboardScan()
  2. {
  3.         uint8_t r, c, val;
  4.         for (r = 0; r < ROW_NUM; r++)
  5.         {
  6.                 // 行拉低
  7.                 GPIO_Reset(rowPins[r]);
  8.                 // 循环检查列
  9.                 for (c = 0; c < COL_NUM; c++)
  10.                 {
  11.                         // 检查是否超过滤波时间
  12.                         if ((keyPressCount[r][c] & 0x7f) < KEYBOARD_FILTERING_COUNT)
  13.                         {
  14.                                 // 未超时,只增加时间,不检测按键
  15.                                 keyPressCount[r][c]++;
  16.                         }
  17.                         else
  18.                         {
  19.                                 // 已超时,检测按键,如果和上次记录不一致则更新按键状态,并清零计时
  20.                                 // 按下为1 抬起为0
  21.                                 val = !GPIO_Get(colPins[c]) << 7;
  22.                                 if (val != (keyPressCount[r][c] & 0x80))
  23.                                 {
  24.                                         // logf("press v%d kp%X\r\n",val,keyPressCount[r][c]);
  25.                                         // 按键状态更新,滤波计时清零
  26.                                         keyPressCount[r][c] = val;
  27.                                         // 只有在正常按键全抬起时才更新FN状态
  28.                                         if (r == FN_ROW_POS && c == FN_COL_POS)
  29.                                         {
  30.                                                 if(isClear)
  31.                                                         pressFN = (val & 0x80) > 0 ? 1 : 0;
  32.                                         }
  33.                                         else
  34.                                         {
  35.                                                 isChange = 1;
  36.                                         }
  37.                                 }
  38.                         }
  39.                 }
  40.                 // 行重新拉高
  41.                 GPIO_Set(rowPins[r]);
  42.         }
  43.         // 按键扫描完成,按照按键组装报文数据
  44.         keyboardSend();
  45. }
复制代码


USB报文
       按键扫描已经完成,下一步就是把扫描到的键值发送到电脑,比如按键A的键值为0x04,则把这个键值发送到电脑,电脑就能识别到A按下,但是USB标准协议中键盘的报文为8字节,第一个字节8位用来存放左右ctrl、shift、alt、win8个键的状态,第二字节保留不用,剩余6字节存放6个键值,这也就导致不算ctrl几个功能键一次最多只能发送6个键值,按下7个键则第7个键无法发送,这也是以前一直说6键无冲的原因。
       既然这样那把着8个字节扩大不就好了,扩大到100个字节,不久可以把所有键值一次都发送完,实现全键无冲了,是个方案,但是数据量有点大,换个思路要是像ctrl那样一位表示一个按键而不是一个字节表示一个按键,那数据量不就可以直接缩减8倍,完美的方案(实际可能有老系统不支持,但是应该可以忽略不计)。实际方案:第一个字节存放ctrl功能键,第二个字节保留,后边13个字节存放13*8=104个键值。
       USB报文实在是太复杂了,几句话说不清,网上资料也很多,想研究的推荐看《圈圈教你玩USB》。
file://C:/Users/changwj/Desktop/lenovo-keyboard-mk300/README/images/image-20240217200645440.png?lastModify=1708219059

      遍历按键数组,检查按下的按键,通过偏移量计算赋值对应的buffer值,组装报文完成后发送到USB完成一轮键盘工作。
  
  1. for (r = 0; r < ROW_NUM; r++)
  2. {
  3.     for (c = 0; c < COL_NUM; c++)
  4.     {
  5.         if (keyPressCount[r][c] & 0x80)
  6.         {
  7.             keyBuffer[keyMaps[r][c] / 8] |= (1 << (keyMaps[r][c] % 8));
  8.         }
  9.     }
  10. }
复制代码

image-20240217200645440.png

打赏

参与人数 1家元 +20 收起 理由
eeerrr + 20 認真發帖

查看全部打赏

回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2024-2-18 09:19:53 | 显示全部楼层
本帖最后由 飞向狙沙 于 2024-2-18 09:29 编辑

结尾
这键盘---一言难尽,功能完全修复,但是,上次飞线修复就发现有一个轴臭了,这次修复发现能臭了1/5,近全新未用的凯华轴,2年臭一个,6年臭一堆,换轴吧这货RGB4脚灯拆起来也是费劲,修好继续吃灰吧。。。

看看对比效果
image-20240218090120858.png
灯效以前写的,懒得移植了,记得是单色、随机、彩虹、流光
image-20240218090430886.png

打赏

参与人数 1家元 +30 收起 理由
zsm小明 + 30 謝謝分享

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2024-2-18 14:24:12 | 显示全部楼层
这个飞线也很NB啊
回复 支持 反对

使用道具 举报

发表于 2024-2-18 15:05:01 | 显示全部楼层
卧槽!这个键盘我也有同款。
和大佬的区别是,我的坏了就丢了!
回复 支持 1 反对 0

使用道具 举报

发表于 2024-2-18 16:05:54 | 显示全部楼层
你这个是用插脚LED还是贴片LED?插脚LED拆都很麻烦
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-2-18 16:13:12 | 显示全部楼层
Python学徒 发表于 2024-2-18 15:05
卧槽!这个键盘我也有同款。
和大佬的区别是,我的坏了就丢了!

还是丢了省心,垃圾轴实在是没啥玩的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-2-18 16:14:56 | 显示全部楼层
jyobin 发表于 2024-2-18 16:05
你这个是用插脚LED还是贴片LED?插脚LED拆都很麻烦

4脚插件,加上轴体2脚一个键盘600多个焊点,想换轴太痛苦了,不如几十块钱再整把换轴键盘了
回复 支持 1 反对 0

使用道具 举报

发表于 2024-2-18 17:24:10 | 显示全部楼层
技术不 错,嘉立创的福利挺实 用
回复 支持 反对

使用道具 举报

发表于 2024-2-18 18:17:58 | 显示全部楼层
好复杂的工程
回复 支持 反对

使用道具 举报

发表于 2024-2-18 21:10:29 | 显示全部楼层
FPC打板不错!
回复 支持 反对

使用道具 举报

发表于 2024-2-19 00:10:13 | 显示全部楼层
飞线                           
回复 支持 反对

使用道具 举报

发表于 2024-2-19 00:13:30 | 显示全部楼层
这工程有点大啊腻害
回复 支持 反对

使用道具 举报

发表于 2024-2-19 07:45:52 | 显示全部楼层
这活学不来,买了个飞线的还没修好。
回复 支持 反对

使用道具 举报

发表于 2024-2-19 08:18:19 | 显示全部楼层
楼主技术很好,只是这个牌子.......................

我的富士通,用了十多年了,完全没问题。
6a737a5635da74b6fa1315354cca999.jpg 987c0f3d7e179b479d9b93162976157.jpg dd7bae552b1b1e718333d4479209d19.jpg
回复 支持 反对

使用道具 举报

发表于 2024-2-19 08:39:05 | 显示全部楼层
看到这些飞线~对比百多元还是能接受的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-2-19 08:55:11 | 显示全部楼层
qjt19810204 发表于 2024-2-19 07:45
这活学不来,买了个飞线的还没修好。

实际上比飞线更简单了,可以试下,都是现成的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-2-19 08:56:45 | 显示全部楼层
menwawork 发表于 2024-2-19 08:18
楼主技术很好,只是这个牌子.......................

我的富士通,用了十多年了,完全没问题。

可以,我现在用的网吧退下来的小丑鱼也用了六七年了
回复 支持 反对

使用道具 举报

发表于 2024-2-19 09:08:53 | 显示全部楼层
谢谢分享,祝楼主新年有钱有闲玩电子垃圾发帖
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-4-28 12:59 , Processed in 0.156001 second(s), 13 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

快速回复 返回顶部 返回列表