老鍵盤來自老筆電,鍵盤呈現是最原始的配置,輸出方面只有薄膜的端子。一般薄膜式鍵盤是透過上下兩層的薄膜接觸產生線路的導通,微控制器透過輸出入端子進行掃描式讀取,因此可以得知目前鍵盤按鍵的情況。如果再透過usb控制器將掃描碼輸出,那麼一個usb鍵盤就完成了。
這套系統稱作「老鍵盤復活器」,希望這個鍵盤復活器可以百搭大部分回收的筆電鍵盤。目前手上這個鍵盤來自一部486筆電,這部筆電目前已經被分解了,所幸鍵盤部分完整留下。
鍵盤按鍵的行為可以分為按下與放開,一般稱為press與release,所以為控制器的程式碼必須用一種機制來判斷這兩個行為,這裡是用一組陣列變數存放每一個按鍵的上一次狀態,然後每次掃描狀態的時候,就跟上一次狀態做比較,這樣就可以產出每個按鍵的press與release事件了。
鍵盤的信號與電腦作業系統之間靠的是鍵盤掃描碼,就usb來說,他有一份定義好的鍵盤掃描碼,所以初步想到需要一個轉換表,可以用來快速轉換硬體掃描的位置與對應的掃描碼,因此這裡使用一組二維陣列,這個二維陣列的索引範圍就是等於硬體的線路。
老鍵盤的薄膜端子有兩個,分別是8條與16條,代表著這具鍵盤最多可以偵測16*8=256顆按鍵,以控制器為觀點,這邊選擇8條線的端子為輸入,16條的端子為輸出,當輸出的信號輪流輸出一個高電位,然後每次切換輸出信號的時候就看一下輸入信號哪一隻是高電位,輸出的高電位信號從第1條到第16條跑一遍,最後就可以知道哪一顆按鍵被按下。
由於電路零件與為控制器的特性緣故,上述的邏輯必須以顛倒方式運作,也就是說,常態時所有輸出入信號都是高電位,需要動作的那條拉成低電為,輸入的部分也是偵測低電位,這樣一來硬體的設計就會比較精簡。
arduino uno的輸出入腳一共有14條數位6條類比,加起來也才20條,扣掉第0第1兩條要用來傳遞資料,所以剩下18條,這樣要如何執行上述的(16+8=24)條的硬體規劃。因此這裡使用74138這棵俗稱「3對8解碼器」來精簡線路。
為什麼會知道要用74138?可以透過觀察法。
首先把鍵盤掃描的各種狀況寫下來,寫成一張真值表。然後可以發現兩條薄膜端子分別一次只會有一條線動作。因為輸入信號的部分是要給cpu內部的程式去判斷用的,所以會希望硬體過程越簡單越好,如果用16線作為輸入,那cpu只會剩下2條線,根本不夠驅動剩下的鍵盤8條線。因此改變思考方向以8條那組作為輸入,16條那組就是輸出,所以16條線一次只有一條動作,一般都是解碼行為,所以馬上就會往解碼器的功能去想。但如果要找4對16調解碼的IC一般來說少見,所以退一步想如果把動作拆開來呢?這個時候因為74138這個IC太普遍了,所以它馬上會從思緒之中跳出來,接著只要仔細看一下74138的資料手冊後一切就昭然若揭了。
74138是一顆把3線輸入轉換成8條單線輸出的解碼器,那3線輸入就像是三個開關,也可以說是門牌號碼輸入,而被選中的那條輸出線就會呈現低電位。另外74138還有三隻晶片致能(Chip Enable, CE)腳,兩隻低電位動作一隻高電位動作,因此如果把一顆74138的低電位CE與另一顆74138的高電位CE接在一起,就可以用四隻腳控制兩顆74138做到16腳輸出,剛好符合硬體的需求。
原本的16隻輸出信號的需求精簡成4隻腳就可以辦到,加上輸入的8隻腳總共12隻腳,這樣一來就可以用arduino uno來讀取鍵盤的按鍵了。以上功能先用arduino uno的傳統軟硬體設計方式實現了,並且藉由串列埠輸出到電腦觀察驗證成功。
接下來還有。這個專題的目標是造出一具usb鍵盤,而arduino 雖然有keyboard.h這個函式庫,但是僅限於cpu是mega32u4的板子才可以運作,而且keyboard.h太過陽春,僅能產生press一種事件,無法產生長按的效果。不管怎樣,最終是因為手邊剛好有arduino uno所以試著先從arduino uno來思考。
所幸,這邊的arudino uno是r3版本,板上的usb是用16u2來實現的,這個16u2是可以改變其程式內容的,目前官方是將16u2規劃成兩個功能:一是提供arduino uno 的cpu上傳程式的功能,二是橋接arduino uno的cpu與電腦usb虛擬串列埠。
因此網路上有神人開發出名為LUFA的avr mega專用usb函式庫。可以用來開發arduino的avr系列cpu的usb功能,甚至arduino官方就是用這套LUFA來寫成上述16u2的功能,而且原始碼就在IDE的資料夾裡面。
雖然LUFA函式庫還附有usb鍵盤的demo原始碼,但那是固定輸出鍵盤掃描碼的程式,不是可以自造usb鍵盤的程式。為了達到自製usb鍵盤的功能,必須利用arduino uno的cpu先做到鍵盤的硬體信號掃描,並轉成掃描碼,然後透過arduino板上原本的內置串列埠通道傳給16u2,再由16u2藉由usb的hid鍵盤功能與電腦溝通。
於是把arduino uno的16u2原始碼打開,可以發現它是分成兩套程式,一是負責arduino程式上傳功能,另一是串列埠功能。把串列埠部分的原始碼攤開,再與LUFA的keyboard程式做比較,然後…哇啦!
程式就寫好了。
於是我就有了一具用回收鍵盤製成的usb鍵盤了。
以上文字是用這具鍵盤打出來的。
Github:
https://github.com/pondahai/diy-usb-keyboard
參考資料:
https://www.arduino.cc/en/Hacking/DFUProgramming8U2
http://yehnan.blogspot.com/2013/08/arduino-unousb.html
https://www.arduino.cc/reference/en/language/functions/usb/keyboard/
http://wukcsoft.blogspot.com/2017/03/atmega16u2-usb.html
https://forum.arduino.cc/index.php?topic=99.0
http://mitchtech.net/arduino-usb-hid-keyboard/
https://github.com/Palatis/Arduino-Lufa
https://forum.arduino.cc/index.php?topic=111.0
http://coopermaa2nd.blogspot.com/2011/11/arduino-uno-mouse.html
https://github.com/coopermaa/USBKeyboard
https://www.instructables.com/id/How-to-Restore-the-Arduino-UNO-R3-ATmega16U2-Firmw/
http://maxembedded.com/2015/06/setting-up-avr-gcc-toolchain-on-linux-and-mac-os-x/
toolchain
http://ee-classes.usc.edu/ee459/library/toolchain/
minicom
https://www.itread01.com/content/1541899100.html
LUFA
http://www.fourwalledcubicle.com/files/LUFA/Doc/130901/html/