怎么说呢,写码的还是很喜欢折腾自己的工具的。之前折腾过编辑器,折腾过配色,折腾过字体,当然也折腾过键盘。
起因
一开始折腾键盘是买现成的键盘,记得之前搞过 DasKeyboard,搞过 Code Keyboard,也搞过 Filco,但是没搞过贵的,HHKB之类的,毕竟觉得贵得没有道理……
后来转入了split keyboard赛道,一开始搞了些现成的,比如微软的那个键盘,以及Kinesis的(公司报销的……),然而感觉都不能满足要求,毕竟不是机械键盘,但是现成的分体机械键盘又太贵,比如啥moonlander……
再后来发现有kit可以买,也就是买别人提供的电路板,外壳,和一些零件,然后自己去买键和键帽,组装成一个键盘。那段时间好像正好是疫情期间,在家里时间很多,于是搞了若干个kit,手感还是不错的,还可以自己选要什么轴之类…… 价格也便宜…… 后来还在上面搞了点开发,例如加上一个OLED画点东西之类……
我大部分的kit都是keeb.io买的,毕竟价钱比较合理(一套也就一百左右,加上键和键帽也比其它成品便宜不少……),前前后后在他们家买了也有四五套了。
后来又转进到了low-profile键盘,毕竟公司后来又要求回去上班了,带一套标准键盘去太重(傻逼公司疫情之后都不给桌子了……),于是又去keeb.io搞了两套low-profile键盘。但是用了low-profile之后发现有个问题:这帮键盘不止矮,同时键之间也很紧密,按键的时候很容易碰到边上的,可能是因为我习惯了传统键盘的关系…… 我搞的第一套还是竖直键位,根本按不对……
这时候看见keeb.io出了预告说要搞MX-spacing的普通layout的low-profile kit,于是我就一直指望这货出…… 结果等了好久之后出了,但是这个价格贵得超乎常理,例如我之前搞过常规套装Sinc只要一百不到,这货出的Sinc LM (low-profile MX-spacing) kit居然要三百…… 要知道三百去买成品都可以买到无线low-profile split的了(NocFree &只要269),你这个还只是个有线kit,甚至都没有键和键帽…… 不知道到底在想啥。
这个时候想到之前袁叔已经搞过自制键盘了,虽然不是分体的,但是应该也不是很难。网上看了看,貌似的确不是很麻烦,于是就搞了一波…… 结果反正还行。
目标
搞之前其实大体上就有个目标了:
- 无线 – 既然keeb.io只有个有线键盘,自己搞一个至少应该比这个更强一点,而且无线去公司就不用插线了。
- 分体 – 人体工程学!感觉分体还是要稍微友好一点。
- RGB – R!G!B! 其实无线RGB没啥意义,毕竟你就塞个小电池,跑RGB分分钟没电 – 但是插USB的时候可以亮啊!(因为是分体其实要两边都插才行,所以其实没啥用,搞完发现一般不开……)
- low-profile – 标准键盘太大了,不好带。
- MX-spacing – 之前已经试过了,太挤的键位会影响打字准确度。
- 普通layout – 之前试过竖排layout,还是不习惯。而且我一直坚持能随时切换回普通键盘 – 毕竟你未必能一直带着自己键盘到处跑,到哪儿都能打字还是很重要的。
- 按键可插拔- 这个其实不是一定要,但是考虑到一开始做出来的肯定有问题,到时候没法拆的话就完蛋了。事实证明我要拆好多次……
然后其实搞之前我搜过很久,结果除了keeb.io还真没啥 —— 市面上的split low-profile kit基本上全都是竖排layout的 —— 看来普通layout还是不够“ergo”啊…… 可能这也是keeb.io为啥敢买那么贵的原因,毕竟独一份啊……
流程
其实网上的确已经有很成熟的自制键盘工具了,我主要是用Ergogen搞的,大体上跟着https://flatfootfox.com/ergogen-introduction/走一遍就行了。Ergogen说是某人一开始搞了个工具自己搞键盘,后来公开出来让大家都可以自己设计……
流程基本上那个导引都提到了:
设计
- 首先是设计键位。我反正要普通layout,所以找个普通键盘照着做就好了。但是,Ergogen是用来做“ergo”键盘的,所以默认是支持竖排layout的 —— 体现在每个键的位置是基于竖排下一个键的 —— 所以要搞普通layout还是挺hack的,有不少地方要手调。搞了一阵之后还是搞定了。大概是这个样子:

- 然后是设置footprint,也就是确定pcb上面放啥。所有的键都要放上去,除此之外还需要放微处理器,电池插座,重置按钮,开关,显示屏接口,RGB led,二极管,之类的。我基本上用到的东西库里面都有(我用的是ceoloide的fork,自带一堆元件,比原版的好用点;另外原版的PCB预览不能用,这个版本能用),唯一缺少的是Choc v1的卫星轴 —— 毕竟基本上“ergo”的键盘上面只有1u的键,最多有几个1.5u的,谁会搞出长条来 —— 于是又在网上一通折腾,后来找到FK提供的卫星轴的footprint,虽然是KiCad格式的,但是研究了一下弄成了可以在Ergogen里面用的。有了这个之后,终于可以把所有元件放在PCB上了。做完之后差不多是这样:

- 之后要把所有的元件连起来,这步倒是不咋难,毕竟Ergogen有比较标准的办法可以把键和二极管连接成键矩阵并且连在控制器上。唯一麻烦的是RGB led:Ergogen对这货的支持好像不太行,我试了试没啥比较好的自动把灯串起来的办法,于是只能手动指定每个灯上一个和下一个是哪个 —— 还好其实名字还挺有规律的 —— 把所有灯串起来,再把第一个灯的信号线接上控制器。差不多就是这样:

- 这时候就可以把生成的PCB扔进KiCad里面了,然后要进行布线 – 毕竟上一步只是指定了怎么连,没指定具体线路怎么走。在有RGB的情况下线超多,我找了自动布线,用的是Freerouting。虽然装起来挺麻烦的 —— 居然是基于java的 —— 然后用起来也有问题 —— 菜单都是框框,并且设置不生效 —— 但是好歹能帮着布线,基本上每次都能搞定绝大多数的网络,但是不知道为啥每次都会剩几条 —— 我之后手动补完的 —— 就很疑惑,感觉剩下的也很容易,不知道是不是卡到了啥阈值。布线需要注意的也就是供电线要粗一点,别的没啥。为了布线容易,我还把偶数行的RGB给转了180度,这样连起来比较顺…… 布完之后大概就是这样:

- 布线完成之后PCB其实就可以拿去生产了,我找的JLCPCB,毕竟这家最便宜,左右两边加运费也就四十块左右,比起其他家动辄上百还是强多了…… 虽然这个还是实验版本,但是5张起订,也就是说会有多出来4份没用的,除非我要直接做5个……


- 除了PCB之外,其实还有上面板和下面板。下面版其实也不是必须的,不过没有的话就是电路板直接露在外面,并不太适合携带,也不太像成品。当然也可以不做下面板而做个3D打印的壳,但是我并没有3D打印机…… 上面版基本是必须的,它提供两个作用:
- 最重要的是卡住卫星轴。没有上面板的话,卫星轴是完全没地方卡的。
- 其次是卡住键本身。其实如果键是焊死的话,焊点足够固定键了,但是因为我搞的是可插拔的,键是可以从插座上拔出来的,这样没有上面版的话会太松。其实我一开始并没有做上下面板,然后就觉得按键很容易掉下来…… 所以还是需要的。
- 因此,上面板需要给所有的键和卫星轴开孔。另外,需要空出来正面的元件(微处理器,电池插头,之类的)的位置,所以形状上要比PCB小一圈。设计上就是这样:

- Ergogen的强大之处在于所有的这些基本都是生成的,有啥要改的只要改改设计文件重新生成就好了,减少了浪费的重复劳动。我基本上就用了网页版,不过还是把配置弄下来传到了https://github.com/HenryHu/ergogen-configs
元件和制作
设计完成之后就可以订购各种需要的元器件了。其实定PCB的时候也可以让厂家直接把各种器件直接焊上去,但是我试了试,价格又直接破百…… 考虑到焊起来应该也不是很难,我就决定自己搞材料来焊接。
- 微处理器的选择:这次设计用的是现成的可插拔板子,毕竟这个比较简单,不需要了解怎样设计微处理器外围器件。常见的选择是nice!nano以及其山寨版,原版略贵(25$),山寨版5刀一个,不过据说山寨版有不少坑,但是有的版本还可以。
- 根据设计需要一堆特殊键帽,啥2.25u的空格,1.75u的回车之类的……
- 多数电子元器件都可以在aliexpress上便宜地弄到,Amazon上面都挺贵的。卫星轴和特殊键帽倒是很难搞,毕竟好像没多少人会在low-profile上面做非1u/1.5u的键帽……
- 电池其实typeractive上有便宜的,但是他们家其他东西都太不划算……
- Aliexpress上好多东西都要一次性买一堆,留着用来做下一个版本好了……
根据设计,需要如下材料:
| 器件 | 需要数量 | 购得 | 价格 | 来源 | 物流 |
| 二极管 (x84) | 84 | 100 | 1.6 | aliexpress | 8/5 -> 8/14 |
| 重置按钮 (x2) | 2 | 20 | 4.62 | aliexpress | 8/5 -> 8/14 |
| 开关 (x2) | 2 | 20 | 4.41 | aliexpress | 8/5 -> 8/14 |
| 电池插座 (x2) | 2 | 20 | 6.16 | aliexpress | 8/5 -> 8/14 |
| 按键插座 (x84) | 84 | 100 | 1.26 | aliexpress | 8/5 -> 8/14 |
| 山寨nice!nano | 2 | 2 | 11.55 | aliexpress | 8/5 -> 8/14 |
| 联排插座 | 48 | 200 | 8.46 | aliexpress | 8/5 -> 8/14 |
| 电池 (x2) | 2 | 2 | 16 | Amazon | 8/19 -> 8/21 |
| SK6812 MINI-E | 84 | 200 | 11 | Amazon | 8/3 -> 8/11 |
| PCB | 1 | 5 | 29 | JLCPCB | 8/3 -> 8/13 |
| Choc V1 卫星轴 | 3 | 4 | 4 | chosfox | 8/4 -> 8/11 |
| 螺丝和螺母 | 一堆 | 一堆 | 7 | Amazon | 8/18 -> 8/19 |
| 亚克力板 | 2 | 6 | 6 | Amazon | 8/16 -> 8/17 |
| 键 | 84 | / | / | 库存 | |
| 键帽 | 73 | / | / | 库存 | |
| 特殊键帽 | 11 | 16 | 13.2 | chosfox | 8/4 -> 8/11 |
总的来说成本并不算很高,而且好多都是可以做好几份的。
元器件来了之后焊上去就完了,不过我其实之前没焊过贴片元件,所以一开始还是很不熟练的……
- 一开始先给一边上锡会容易一些,之后就不需要一手焊锡一手烙铁了,可以空出手来用镊子固定元件。
- 按键插座一定要按平,否则很容易翘起来……
- 二极管实在是太小了,而且我烙铁头还粗,焊锡也粗,很容易焊锡给太多……
焊完之后可以用万用表测量是不是搞对了,不过我测了几个就懒了,转头决定刷完固件直接按键测。

至于上面板和下面板,其实主要就是一块挖了洞的板子。为了节约成本,我打算用亚克力+公司的激光雕刻机来刻出来正确的大小。在试了几次之后,好歹是弄出来基本能用的板子了,但是
- 装的时候才发现开孔太大,按键没法卡住…… 看来14mm+雕刻机的误差(毕竟激光雕刻会多烧掉一点)对按键还是太大了一点……
- 理论上卡住按键需要1.2mm的上面板,但是我只能买到1mm的亚克力。这么薄的亚克力非常软,在挖掉很多洞之后更是如此…… 感觉不是个好材料,可能还是直接用1.2mm PCB做比较好,虽然会贵一些。
全都焊完之后,放上卫星轴底座,就可以把上面板和下面板都组装上去了。我其实是之后才做这个步骤的,毕竟一开始很难确定是不是设计能正确工作,所以我一开始组装的时候并没有上面板,后来才把所有键都拆了装上去的 —— 因为键要装在上面板的上方 —— 这就体现出键可以插拔的好处了。
- 组装面板其实就是用螺丝固定到一起,但是正反面都需要空一点空间,我基本上就是用螺帽和垫圈空出来的地方。
- PCB上方用两个垫圈高度就差不多了。
- PCB下方用一个螺母高度差不多,但是如果按键插座没焊接平整,那么就会比螺母高…… 可以加个垫圈。
固件
固件上用的是无线键盘广泛采用的开源固件ZMK,基于Zephyr操作系统。这货主要支持无线键盘,也支持分体式(并且两边用无线通讯)。基础的固件配置其实挺容易的,只需要指定
- 键盘基于的是哪个微处理器。因为我是基于可插拔的控制器板子,所以我这个键盘算是个shield。
- 按键矩阵的配置,也就是行和列都接在哪些pin上面,其实照着Ergogen里写的抄就行。
- RGB led的信号线接在哪个pin上面。
- OLED的信号线接在哪些pin上面。
- 矩阵转换 – 基本上就是指定物理的某个行列映射到逻辑上的哪个按键
- 初看这个好像比较多余,但是其实还挺有用的,因为物理连接可能和逻辑不一致,比如为了省pin减小矩阵大小。例如我右边有一行有9个键,但是我矩阵只有8列 – 其中一个键其实物理上在下一行上,但是逻辑上是在这一行的。
- 按键映射 – 就是每个逻辑按键会输入哪个键,和QMK一样。
然后就可以编译固件刷上去了。我一开始搞混了GPIO的指定方法 – nice!nano基于nrf52840,它有一套自己的GPIO编号,但是因为这套微处理器板子一开始卖点是兼容pro-micro,所以也会标pro-micro对应位置的GPIO编号。我一开始把pro-micro那套打进配置文件里,然后就完全不work…… 其实那套也能用,zmk nice!nano支持里面其实有兼容层,不过考虑到我后面可能还要用nice!nano独有的pin,还是直接用它自己的GPIO编号了。
搞完固件之后发现若干个按键没焊好,还要回头返工。全弄完之后,基本的功能就有了,接下来就是更有趣的功能了。我把ZMK配置放到了https://github.com/HenryHu/zmk-config。
OLED屏幕
Fancy的键盘上当然都要有个显示屏,既可以显示实用信息(电池,蓝牙状态,等)也可以用来搞些有趣的功能(比如养猫……)。这个键盘设计的时候搞了两个显示屏位置,一个在控制器顶上,一个在下方。做出来之后,控制器已经很高了,于是决定用底下那个位置。ZMK配置显示屏本身并没有什么难度,只需要照着别人的例子在device tree overlay里面搞个i2c node,然后在底下挂个显示屏就行了。
- 一开始死活显示不出来正确的图形,只有一堆点,我还以为显示屏坏了…… 结果是因为没有指定色彩深度只有1位,参照了Corne键盘的配置,加了几个选项就好了。我是不知道为啥在用单色OLED的情况下这些不是自动指定的……
- nrf52840的I2C可以随便指定到(大部分的)pin上面,还是很方便的……
zmk默认支持在OLED上显示一些信息,例如电池之类,但是网上有其他人做的控件库,里面能显示更多信息。我找来了nice-oled,并在它基础上加了一些功能和优化:
- 本来nice-oled的效率不太行,每按一个键会卡一会。我看了眼貌似是因为这货用了LVGL库的transform,但是其实它只是需要旋转90度(因为OLED多数是竖着装的),自己随便手搓一个都比transform快很多……
- 实现了基于Oneko的小动画,可以在小屏幕上养猫,基本上就是个状态机……
- 其实还有不少可以优化的地方;nice-oled的思想是每次有变更就重绘整个屏幕,实现上当然简单,但是效率就不太行,毕竟很多时候只有一小块地方变化了。以后再说了……

RGB灯
Fancy的键盘当然也要能亮RGB,虽然没USB供电的时候真不敢让电池跑RGB……
RGB led是整个键盘设计中问题最大的部分。本来其实RGB灯并不太关键:大部分时间都是用电池,用电池根本就不会开RGB led —— 毕竟灯全开大概要50mA左右,电池就100mAh,也就是只能用俩小时 —— 基本上就是个可选内容,但是问题是最多的:
- 搞完之后再看资料才意识到,RGB led其实按理来说需要5v供电,但是nice!nano并没有5v输出,我是接在3.3v上的。幸好装完之后能亮。另外nice!nano那个3.3v未必能带动那么多灯…… 最后限制最高亮度了事……
- RGB led 基本上推荐是用SPI驱动 —— 虽然这些灯其实并不是SPI接口的,但是用SPI控制器可以产生灯可以理解的波形 —— 所以我一开始也是这么搞的。但是搞完之后死活不亮,我折腾了好几次,例如尝试换成GPIO驱动(结果没有给nrf52840的实现),以及修改各种参数(比如改拉低和拉高各持续多久之类),结果最后发现好像是SPI控制器有问题。nrf52840有4个SPI控制器,一般网上都推荐用第四个,因为其他的有点问题,于是一开始我也是用第四个(spi3),但是死活搞不起来。后来改成了第三个,立马就好使了…… 我也不知道是我这个山寨版本有点问题,还是恰好这个是坏的,还是别的啥……
- RGB本身其实并没有啥需要配置的,只需要指定是哪个pin,以及一串led有多长。虽然理论上要指定颜色顺序,但是反正都是sk6812,都是标准的.
- 折腾完之后装键帽的时候发现…… led放反了,或者说整个键都放反了。一般的键帽灯是在顶上的,但是我设计的键灯在底下,于是就面临两个问题:或者键帽倒装,或者光透不过来。反正我打字也不看键,当然是透光更重要…… 于是基本所有的键帽我都是倒过来装的。这个需要在下个版本改进……

电池
我最后折腾的是电池,毕竟没有电池也能用 —— 插着USB就行 —— 但是分体式键盘要插两边,还是有电池比较方便。而且当初折腾无线就是为了去公司不需要插线,所以电池还是要搞的。
Aliexpress上的电池不知道为啥都挺贵的,Amazon也是;typeractive上倒是便宜,但是居然电池不单卖。最后还是Amazon上搞了俩401230,正好挤在控制器底下。
搞完电池之后测了一下,没啥问题,能放电能充电。但是用了一会就发现问题了:这个电掉得特别快啊……
把万用表调到电流档手动串在电路上,我发现就算灯不开,整个键盘也要走22mA的电流。考虑到电池只有100mAh,这也只能用五个小时不到,完全不行…… 而且屏幕关掉的时候也有18mA,考虑到整个键盘能耗电的玩意也就剩RGB led了,我就怀疑它不亮也耗电……
搜了一下,果然说这些RGB led就算不开也会漏电,三十几个led漏十几二十毫安很正常…… 于是想着只要干掉供电就好了。然而问题在于,我灯和屏幕都接在3.3v上,虽然nice!nano有个pin能关3.3v,但是关了屏幕也会不亮……
于是第一个想法是只有屏幕亮着的时候开3.3v,屏幕不亮就关掉。这个事情倒是不难,毕竟zmk支持控制3.3v开关。但是,我试了之后,发现关掉3.3v没问题,但是再开的话屏幕不会亮,除非reset……
搜了搜发现是3.3v重新供电的时候屏幕需要重新初始化。这个其实是已知问题,zmk也时不时有点进展,但是一直还没修完…… 那个issue里面有些别人自己写的patch,基本上就是上电重新初始化oled(还需要初始化i2c)。我试了试之后,基本上还能用,还稍微改了点小问题……
这样弄完之后,开着屏幕还是电流不小,但是屏幕30s之后自动关闭,顺便切断3.3v供电,系统耗电会降到1.2mA,也还行。之后搞上了deep-sleep,过了指定时间自动进入深度睡眠,耗电可以降低到0.33mA,就可以坚持很久了……
这么搞之后试了试,感觉耗电还是太多,特别是键盘一直使用的情况 —— 毕竟这种情况下屏幕经常亮,led也就一直漏电……
于是就想着要搞个开关只是切掉led的供电,但是屏幕的还是留着。最好这个开关还是由一个pin控制的,这样要亮灯的时候可以自动供电。和Gemini聊了聊,说可以用P沟道MOSFET。实话说本科学的数电早忘光了…… 看了看相关资料,觉得还是挺靠谱的,就搞了个MOSFET(AO3401),插进3.3v和RGB led供电之间。
但是PCB已经做完了,这时候要改其实还是挺麻烦的。我拿刀切断了3.3v供电线 —— 幸好布线的时候只有一根 —— 然后刮出铜皮弄上了一个MOSFET,然后把栅极弄根漆包线连到了nice!nano的空出来的pin上面。
随后就是怎么控制的问题。Gemini在这方面非常不靠谱,它提供了若干个扯淡的方法,编译都过不去那种。最后我自己给zmk的underglow驱动加了supply-pins支持,开灯就把pin设置成1,关灯就设置成0,跑了跑之后改了几个bug,就没啥问题了。随后我就把原来那些奇怪的patch给车掉了,毕竟如果能直接切掉灯的供电,那也没必要切掉3.3v了,也不需要重新初始化屏幕了。
都折腾完之后,亮屏耗电大约4mA,关掉屏幕耗电大约0.6mA。之后又降低了屏幕亮度(OLED居然那么耗电,我把contrast从128调到了32),亮屏降低到了2.4mA,大大延长了电池寿命,现在基本上可以撑个几天了,当然最好能一周一冲。另外右侧基本上是不耗电的,idle的时候只有大概零点零几毫安,感觉一周没有任何问题……
总结
折腾到这里基本上告一段落,各种功能工作正常,电池寿命也能接受。接下来或许要搞个v2,毕竟
- 首先,按键都是反的…… v2肯定要正过来
- 控制RGB供电的mosfet当然要弄到pcb上去
- 可能应该搞个5v供电电路给RGB led…… 但是反正3.3v也能用,可能没啥必要
- 可以考虑支持128×64的更大的OLED屏幕,位置需要稍微调整一下
- 重置开关塞太里面了,装了下面板很难按到,应该移出来一点
- 螺丝孔离按键太近,有几个都没法装垫圈,需要移动一点位置
- 上面板还是订购PCB的时候一起定了吧,虽然会贵一点。或者研究看看能不能3D打印一个
- 可以考虑给控制器设计个挡板之类,现在只能靠贴纸把顶上封上,避免碰到啥东西短路
- 可能应该买个官方版nice!nano?虽然贵(25$),但听说耗电更低
- 这次感觉买choc v1的零件,特别是stabilizer,越来越难了…… 看来v2要用choc v2了……
其实v1的结果出乎意料得好,我本来都没有指望v1能用…… 按键方面没有任何问题,屏幕也没有问题,甚至卫星轴都没有问题,所有的问题基本都出在RGB上,可能还是因为多数人不搞RGB(虽然位置反了好像和这个没多少关系?) —— 毕竟无线+RGB本来就不合理 —— 所以RGB这方面默认设计有点问题。
感觉现在自己折腾自定义键盘并没有多少难度,如果不搞RGB的话照着教程直接做就差不多了,感兴趣的都可以试试看…… 毕竟有时候个人需求就是难以在现成kit里得到满足……
另外觉得如果是国内的话,迭代肯定比这个快很多:我光是等PCB寄过来就花了一个多礼拜,还要等材料寄过来,如果是在国内的话,估计可能两天就到了……
相关代码:
- Ergogen 配置:https://github.com/HenryHu/ergogen-configs
- zmk配置:https://github.com/HenryHu/zmk-config
- fork的zmk:https://github.com/HenryHu/zmk
- 加了led-strip supply-pins支持
- fork的nice-oled:https://github.com/HenryHu/zmk-nice-oled
- 加了responsive oneko widget
- 提升了效率,跑起来反应更快了
致谢:
- Ergogen,没有这个的话基本上整个项目无从谈起
- zmk,没有这个当然也没得搞
- ceoloide的ergogen元件库和ergogen实例,比标准元件库好用
- mctechnology17的zmk-nice-oled,屏幕控件库
- Ergogen Introduction,提供了很好的入门教学
- FK的Choc v1 footprint,提供了卫星轴的信息
- 若干其他人的zmk config,包括corne的,毕竟很多时候不看一眼都不知道还要设置这个……
