鍵盤DIY——RK61改裝成HHKB鍵位

背景

前段時間入手了一把HHKB,感覺鍵位設(shè)計真的不錯,尤其是方向鍵和Home、End,可以在手指不離開打字鍵位的同時輕松按到,讓手完全留在主鍵盤區(qū)。但生活也有幾點不那么完美的:

  1. 用慣了之后,再用原來的鍵盤真的超級難受,一個是Ctrl,另一個是backspace,老是按錯。
  2. 用背包來回帶很麻煩,進(jìn)公司要查包,坐地鐵要安檢。
  3. 手感……是個玄學(xué),但是用了一段HHKB之后再用我的茶軸IKBC,感覺IKBC手感真的好,可能我更喜歡機械鍵盤那種更干脆的手感。

有了HHKB之后,打算把一直吃灰的RK61賣掉,感覺再也不需要它了。但是不小心把它外殼摔裂破相了,估計價格要大打折扣了。于是我想,干脆把RK61改成HHKB的鍵位,來解決上面的問題吧!

軟硬件環(huán)境介紹

電腦:聯(lián)想G410筆記本
操作系統(tǒng):Debian 9/Linux Mint
調(diào)試工具:JLink V9仿真器
軟件開發(fā)環(huán)境:STM32CubeIDE
開發(fā)板:YL-8開發(fā)板
電路板軟件:KiCAD
3D模型制作:Blender/FreeCAD

關(guān)于RK61

RK61是我的第一把60%鍵盤,這把鍵盤有點坑,F(xiàn)n的功能很有限,沒有辦法按出Home、End等鍵,用起來很不方便,買了之后用了一周就吃灰了。看官網(wǎng)現(xiàn)在的版本好像支持更多的組合鍵了,但是老鍵盤并不提供固件升級。

先拆開它看看。主要有兩個芯片

主板圖
  1. SH68F83
    這個芯片是一個支持USB協(xié)議的單片機,有線模式時的USB協(xié)議應(yīng)該是這個芯片實現(xiàn)的。
  2. BCM20730模塊
    基于博通的BCM20730芯片,這個芯片主要是為無線游戲控制器、鍵盤、3D眼鏡等設(shè)計的。其中鍵盤相關(guān)功能我們可以重點關(guān)注一下。它支持最多8×20的硬件矩陣掃描,用來做鍵盤還是很方便的。

一開始考慮的是把藍(lán)牙模塊的軟件換掉,硬件不動。但是這個模塊的資料很少,沒找到足夠的開發(fā)資料,冒然開搞后面卡殼失敗風(fēng)險太大。最終選擇了比較穩(wěn)妥的方案:直接把主控?fù)Q掉。這樣我們只要搞懂按鍵的電路就可以了。同時我對無線的需求不大,決定先搞成一個USB有線鍵盤算了。

雖然沒有使用這個藍(lán)牙模塊,但是對它的研究還是很有用的。從BCM20730的數(shù)據(jù)手冊上我們了解到,硬件矩陣鍵盤掃描使用的引腳是固定的。

  • P0-P7 row0-row7 (KSI0-KSI7)
  • P8-P27 column0-column19 (KSO0-KSO19)

有了這個信息,再看看藍(lán)牙模塊上這些引腳都是接出來的,我們就能通過藍(lán)牙模塊的引腳,比較方便地確定鍵盤的矩陣電路。

藍(lán)牙模塊引腳圖

RK61一共61個鍵,有了前面的藍(lán)牙模塊對應(yīng)的引腳,然后用萬用表量一量確認(rèn)一下,就能知道這些鍵分為8行8列,最后一行5個按鍵,其他行每行8個。具體分布如下:

主板矩陣分布

這個矩陣鍵盤的電路的結(jié)構(gòu)和GH60的很像,只是行列的排布有一點區(qū)別。大多數(shù)鍵盤的應(yīng)該都差不多。 大家可以去下載GH60的電路看一看。

矩陣按鍵電路跟單片機的小矩陣鍵盤有點區(qū)別,每個按鍵串聯(lián)了一個二極管。因為矩陣鍵盤在掃描時,會拉低一個掃描線,同時保持其他掃描線為高電平。但是當(dāng)多個按鍵同時按下時,可能會形成回路拉低條其它掃描線,出現(xiàn)多條掃描線同時為低,如下圖(1)。這個二極管可以阻止這個回路的形成,如下圖(2)。

矩陣鍵盤電路 (1)無二極管 (2)帶二極管

我們只要把矩陣鍵盤的行列都引出來,接到單片機的IO上就可以了。剩下的問題基本上就是軟件實現(xiàn)USB設(shè)備、鍵盤掃描了。

STM32流程打通

軟件環(huán)境

之前其實沒用過STM32單片機,大部分都是用的51單片機。讀一些資料后,開始搭建環(huán)境,經(jīng)過嘗試,覺得最省事的開發(fā)環(huán)境就是STM32CubeIDE了?;贓clipse,集成了STM32CubeMX,裝好后裝了個VIM插件就直接開用了。因為不需要寫太多代碼,所以找個最省心的環(huán)境就可以了。

STM32CubeIDE主界面

使用STM32CubeMX + Vscode + platformIO的同學(xué),需要注意一下platformIO對CubeMx生成的USB庫的支持不是太好,生成代碼后不能直接編譯通過,可能需要配置一番。
不得不說現(xiàn)在STM32的軟件做得真方便,直接在圖形界面里配置好了之后,按一下生成代碼,所有初始化代碼就全部生成了,很省事。

開發(fā)板hello world

用的開發(fā)板是很多年前買的YL-8開發(fā)板。還好在網(wǎng)盤里找到的它的電路圖。買的開發(fā)板、模塊什么的,一般都會把資料放到網(wǎng)盤里,防止哪天要用的時候,發(fā)現(xiàn)只剩板子,啥資料也沒有了,真?zhèn)€好習(xí)慣,哈哈。
按照小開發(fā)板的電路圖,在CubeIDE配置好引腳后,在主循環(huán)里加了兩行代碼,就實現(xiàn)了一個檢測按鍵狀態(tài)控制LED亮滅的小Demo。

int i = HAL_GPIO_ReadPin(button1_GPIO_Port, button1_Pin);
HAL_GPIO_WritePin(GPIOC, led1_Pin, i);

使用STM32的USB接口

為了實現(xiàn)USB鍵盤,先要會用STM32的USB模塊,這塊感覺挺麻煩的,好在網(wǎng)上有很多現(xiàn)成的例子,相關(guān)教程不再贅述了,大家需要的網(wǎng)上找一找就有了。
我這里遇到了一個棘手的問題:按照網(wǎng)上的例子配置完成后,電腦竟然不識別USB設(shè)備! 被這個問題困擾了好久,還買來一本《圈圈教你玩USB》來學(xué)習(xí)USB協(xié)議,但是還是不行。調(diào)試USB初始化代碼,也沒有報錯。找來網(wǎng)上的例程燒進(jìn)去,也沒有反應(yīng)。直到一天看書時注意到,USB主設(shè)備會根據(jù)從設(shè)備的上拉電阻來檢測從設(shè)備,再看看YL-8開發(fā)板,USB接口并沒有上拉電阻,而網(wǎng)上找的其它開發(fā)板的電路,則是帶上拉電阻的。

USB電路,注意關(guān)鍵的1.5K電阻

難道是STM32F103RC里面不帶上拉電阻? 于是我接上了一個電阻試一了試,果然立馬識別出USB設(shè)備了!

識別出的USB設(shè)備

原來只是一個電阻的問題!后來又在網(wǎng)上看了不少開發(fā)板,很多mini開發(fā)板USB接口電路都沒有接好。這種開發(fā)板一般也沒有帶USB相關(guān)的例程,使用時需要注意檢查一下電路。正常情況下,在CubeIDE里配置好了USB設(shè)備,燒進(jìn)單片機之后,USB設(shè)備就能正常識別的。如果不能正常識別,很可能就是電路有問題。
不過經(jīng)過這個問題,倒是學(xué)到了不少USB相關(guān)的知識,推薦《圈圈教你玩USB》這本書,學(xué)到了不少東西。

鍵盤HID設(shè)備實現(xiàn)

為了實現(xiàn)鍵盤的功能,需要把USB設(shè)備配置為HID鍵盤。CubeIDE生成的默認(rèn)設(shè)備是一個Joystick的,我們主要需要改兩個地方,一個是配置描述符,把端點從鼠標(biāo)改成鍵盤;另一個是要新建一個鍵盤的報告描述符,這里偷懶直接把圈圈的報告描述符拷過來了。這些改動大部分都在usbd_hid.c里。具體改動可以看在Github上找到:https://github.com/thelxz/xzkb
我們后面發(fā)報告要按報告描述符描述的格式來發(fā),所以只要弄明白報告描述符描述的格式就可以了。因為報告描述符用的圈圈的,所以報告格式和他的也是一樣的,一共有八個字節(jié):

報告描述符格式

第一個字節(jié)是特殊按鍵的狀態(tài),第二個字節(jié)是固定的0,之后的六個字節(jié)分別是同時按下的除特殊按鍵外的六個按鍵的UID。每個鍵對應(yīng)的UID可以通過《USB HID Usage Tables》這個文檔的"keyboard/keypad page"找到。
我一開始有點懷疑,只記錄六個鍵夠不夠?后來試了下,因為功能鍵有單獨的bit控制,除了功能鍵,我?guī)缀醪豢赡芡瑫r按下六個按鍵,所以如果不玩對按鍵要求比較高的游戲的話,這里一般就夠用了。這點好像也是普通的USB鍵盤不能實現(xiàn)全鍵無沖的原因,有一些特殊的方法可以實現(xiàn)全鍵無沖,但是我們這里就不考慮了。
按這個格式生成報告了之后,使用下面的接口發(fā)送Report,沒有意外的話,就電腦就可以收到單片機發(fā)送的按鍵了!

USBD_HID_SendReport(&hUsbDeviceFS, reportBuf, reportLen);

連接鍵盤和開發(fā)板

這一步比較簡單,就是連線,我把行列分別連到了GPIOA和GPIOB上。唯一需要注意的地址是,最好找?guī)讉€連續(xù)的引腳,這樣后面編程會方便一些。

通過飛線連接矩陣鍵盤到開發(fā)板

添加軟件邏輯

其實本來是想直接用TMK的代碼的,但是發(fā)現(xiàn)TMK對STM32的支持好像并不是太好,而且還使用了ChibiOS這個BIOS,比較復(fù)雜,想看懂需要花些時間。于是決定自己寫,更簡單可控。
大家可以直接看代碼,主要邏輯都在keyboard.h和keyboard.c里。
使用了兩個數(shù)組作為字典來表示兩個層,默認(rèn)情況下,每個按鍵對應(yīng)的UID通過keyUID[0]翻譯,當(dāng)Fn按下時,對應(yīng)的按鍵通過keyUID[1]來翻譯。這個邏輯是很簡單的,代碼可以在這里找到。但這樣做其實有一個小問題,比如使用F2(組合鍵Fn+2)重命名文檔時,如果先松開了Fn,2這個鍵就會發(fā)出去,結(jié)果就把文檔重命名成“2”了。不過這個問題不常出現(xiàn),我們先不管它,后面再修。
完成這一步之后,我們的鍵盤其實就能用了!

開發(fā)板鍵盤

但是很明顯,這樣有點丑,而且插的線偶爾會接觸不良或脫落,導(dǎo)致一些按鍵失靈!看來為了把電路板塞到鍵盤殼子里,需要一個小一點的主控板了。

制作主控板

KiCAD介紹

正如之前提到的,網(wǎng)上好多比較小的開發(fā)板,有很多USB電路都不是直接連好的,就想著干脆自己做一個吧。發(fā)現(xiàn)現(xiàn)在PCB比以前便宜多了,10×10的才30來塊錢,也好久沒做過了,就試一下吧。
電路圖軟件試了試Eagle和KiCAD。很久以前用Eagle挺好用的,命令很方便,但是現(xiàn)在發(fā)現(xiàn)Eagle被Autodesk收購了,功能也有變化,比如顯示3D庫會直接跳到Autodesk網(wǎng)站,感覺Eagle已經(jīng)變了,只好放棄它了。
反觀KiCAD,最近發(fā)展好像很迅猛,裝上之后發(fā)現(xiàn)功能比幾年前強大了許多,文檔也很豐富了,建議大家試一試。如果是第一次用,建議先把中文文檔瀏覽一遍。

電路圖:

KiCAD電路圖

PCB和3D圖:

PCB圖
3D image

PCB畫完之后,可以生成gerber發(fā)現(xiàn)商家制作了。本來還擔(dān)心KiCAD國內(nèi)用的不多,PCB制作會有問題,結(jié)果卻很順利,文件發(fā)過去直接就做出來了。
軟件的各種操作在官方文檔里說的很全了,有一些覺得有用的點分享給大家:

  1. 布線模式設(shè)置為推擠(shove),可以在步線時把之前的線推走,默認(rèn)沒有打開
推擠模式
  1. 3D模型的制作

    方法1:對Blender比較熟悉的話,可以使用Blender制作3D模型, 導(dǎo)出OBJ之后FreeCAD選擇材質(zhì),再導(dǎo)出wrl文件,KiCAD就可以導(dǎo)入了。Blender建模型比較快,但是導(dǎo)入KiCAD之后還需要重新調(diào)整大小,而且Blender的材質(zhì)不能導(dǎo)出后就丟了。
    方法2:直接使用FreeCAD制作模型,導(dǎo)出STEP文件,這樣的話,直接導(dǎo)入KiCAD里面就會帶材質(zhì),而且大小也不需要調(diào)整。后面嘗試了一下,這個流程是可以的,但是我FreeCAD用的不熟,建模很慢。

前面PCB的3D模型里,缺了一些元件的模型,用Blender做了幾個:


用Blender做的元件的3D模型

焊接組裝

PCB回來發(fā)現(xiàn)做工一般,便宜了質(zhì)量果然有些下降,但也還好,沒什么問題。因為想讓它當(dāng)個小開發(fā)板的,所以沒有做太小,還加了一些按鍵和LED。

PCB

開工焊元件吧!結(jié)果發(fā)現(xiàn)自己動手能力已經(jīng)嚴(yán)重退化了,鑷子夾著元件抖得不行。還發(fā)現(xiàn)自己電路畫錯了,Reset鍵不靈,只好搞了個飛線,看一下最后效果,簡直慘不忍睹…

慘不忍睹的板子

上面黑乎乎的是松香,記得之前酒精是可以洗掉松香的,現(xiàn)在怎么洗了半天洗不掉,不知道是酒精不行還是松香不好。算了,就這樣吧,反正放到殼子里也看不到。

板子安裝到殼子里

為了降高度,一些不用的元件去掉了,把SWD調(diào)試口接了一個MicroUSB連到外面去了,方便下載程序。這樣處理是偷懶了,后面有心情時再研究一下怎么通過USB升級程序或者把USB接口復(fù)用一下,只留一個接口。
裝上殼子,外面看起來還不錯吧!

裝上殼子之后

細(xì)節(jié)處理

安裝支腳、防滑墊

RK61是沒有支腳的,不是太舒服,而且原來的防滑墊也老化了,掉了兩個,都需要處理一下。

支腳網(wǎng)上有賣的,挺好看的,但是大都需要運費,就自己打了個孔,裝了個六角銅柱,套上了一個小橡膠帽來防滑就可以了,橡膠帽是原來吃雞手柄帶的電容屏按鍵帽,防滑效果還是挺好的。

支撐腳

下面加了一個原來買鍵盤托帶的橡膠墊,用螺絲刀的六角刀頭在螺絲處打一個孔。

防滑墊

Fn功能鍵優(yōu)化

現(xiàn)在來處理Fn鍵松開后,已經(jīng)按下的鍵功能發(fā)生變化的問題。為了解決這個問題,不能只考慮現(xiàn)在按鍵的狀態(tài),還必須考慮到上次按鍵的狀態(tài)。代碼的變化主要有:

  1. 按鍵的level不是全局的,而是每個按下的鍵都有一個自己的level。
  2. 在按鍵掃描時,記錄上次掃描狀態(tài),如果這個鍵上次掃描就已經(jīng)按下了,它的level狀態(tài)就不受現(xiàn)在Fn狀態(tài)的影響,而是直接復(fù)制上次的level信息。

功耗優(yōu)化

現(xiàn)在鍵盤的功能基本上搞完了,但是心里一直有一個疑惑:我寫的程序一直循環(huán)檢查按鍵狀態(tài),就算等待的時間,也是在原地循環(huán),這樣電路的功耗會不會很大?為了方便的搞清這個問題,采購了一個測量USB電流的小設(shè)備。這個工具主要是用來測量充電器的功率的,但是精確到了mA級,測量鍵盤的功率應(yīng)該也是可以的。測量結(jié)果如下:

幾個鍵盤的功率對比

我們做的鍵盤功耗是有一點大,比達(dá)爾優(yōu)的104鍵還大一點。但是再看HHKB Pro2,好家伙,功耗竟然是我的三倍多!難道是內(nèi)部集成了USB HUB的原因?不知道現(xiàn)在新的HHKB功耗降下去沒有。
優(yōu)化功耗可以從兩方面入手:

  1. 把延時程序的循環(huán)查詢改成Sleep
  2. 降低MCU的頻率

我們先看一看HDL_Delay() 這個延時函數(shù):

__weak void HAL_Delay(uint32_t Delay) //注意 __weak
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;

  /* Add a freq to guarantee minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }
  while ((HAL_GetTick() - tickstart) < wait)
  { //這里是用循環(huán)在等時間到達(dá)
  }
}

發(fā)現(xiàn)這個函數(shù)是個弱函數(shù),我們只要按照它重新實現(xiàn)一個就可以,不需要修改HAL庫。我們把它的循環(huán)等待里加一行sleep函數(shù),讓它在等待時進(jìn)入低功耗狀態(tài),等systick來了的時候,會從sleep狀態(tài)喚醒它,檢查時間是否到達(dá)。代碼如下:

void HAL_Delay(uint32_t Delay)
{
  uint32_t tickstart = HAL_GetTick();
  uint32_t wait = Delay;
  /* Add a freq to guarantee minimum wait */
  if (wait < HAL_MAX_DELAY)
  {
    wait += (uint32_t)(uwTickFreq);
  }
  while ((HAL_GetTick() - tickstart) < wait)
  {
      HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
  }
}

其中的HAL_PWR_EnterSLEEPMode()函數(shù)可以調(diào)用WFI,進(jìn)入低功耗狀態(tài)??匆幌滦薷耐瓿珊蟮墓β剩?/p>

睡眠等待之后的功率

效果還是很明顯的,功耗降低了約50%。下面再試試降低時鐘頻率,把AHB總線的時鐘4分頻了一下,再看鍵盤的功耗:

降頻之后的功率

又降了40%!雖然只有兩點比較簡單的改進(jìn),但是效果還是相當(dāng)不錯的,現(xiàn)在鍵盤的功率已經(jīng)降到了60mW,試了試比我手上所有的USB設(shè)備都省電,就先這樣吧!

完工

我們的鍵盤基本上完工了,總結(jié)一下情況吧:
主控:STM32F103RET6
代碼量:< 500 行(不含自動生成代碼)
接口:MiniUSB,SWD接口
按鍵:61鍵,國產(chǎn)紅軸,F(xiàn)n組合鍵類似HHKB
源碼:https://github.com/thelxz/xzkb
電路PCB:https://github.com/thelxz/xzkb_pcb

鍵盤外觀

因為只有周日有時間,改裝鍵盤的過程前前后后經(jīng)歷了好幾周,但是收獲還是很多的,了解了USB協(xié)議,學(xué)會了KiCAD,搶救了一下我的動手能力,也完成了我們最初的目標(biāo):HHKB再也不用來回帶了。
現(xiàn)在這個鍵盤已經(jīng)成為在家的主力鍵盤了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容