前不久,一名在深圳的大學好友聯系到我,他們公司需要做一個USB藍牙接收器,功能大體如下:
USB藍牙接收器插在電腦上使用,被識別為鍵盤;
手機程序連接該USB藍牙接收器;
手機程序向電腦發送鍵盤輸入指令。
整體來說,他這個需求多少有點非主流,看著像是藍牙鍵盤,但物理上卻是USB接口的HID設備,并不是BLE的HID,BLE在這里只是用來接收手機發送的數據。
起初我也沒太認真想如何實現,就隨手發到了交流群里,于是各路高手們紛紛提出了自己的方案:
群友“喵了個咪”的方案是:單片機模擬USB鍵盤+藍牙串口透傳,可以用CH551+KT6368A,KT6368A可以參考之前的文章《成本不足2元的藍牙芯片,你能想得到嗎?》。
群友“heibus”的方案是:串口轉USB HID芯片+藍牙串口透傳,可以用CH9328+KT6368A。
群友“oxlm”、“Pengfei”的方案是:使用單顆藍牙SOC,可以用Nordic的NRF52840、NXP的QN9080等,藍牙芯片自帶USB接口,一顆芯片搞定。
群友“baolei”的方案是:CH340+KT6368A,通過Device Simulation Framework在PC端寫個上位機軟件,將串口收到的數據轉換成虛擬HID。
從原理上來說,以上4種方案都可以實現我這位同學的需求(說到我這個大學同學,請允許我臨時跑個題,當年上學時,他住我宿舍正對面,是個不折不扣的單片機迷,最初玩51單片機,后來搗鼓AVR單片機,然后自學uCosII操作系統,后來不知道怎么又自學了Java,技術上特別愛專研。大學畢業后,我們就一南一北各自闖天涯了,他南下深圳直接工作了,從事安卓相關研發工作。這么多年一直在這個領域,在深圳也是純憑個人能力攢錢買了房子。不得不感慨,干移動互聯網的就是比干嵌入式的更容易搞錢)。
那他為什么要整這個USB藍牙接收器呢?因為他們新開發的這款APP用在國外,而這個藍牙接收器是用來控制彩票機的。大概意思就是,在手機點一點,實現在彩票機購買彩票的功能。
至于為什么不直接在彩票機上購買,他給我解釋了所謂智能的概念,聽的我一頭懵.
神奇了,最近老和BLE打交道,前段時間才研究了那個超便宜的BLE芯片KT6368A,這又來了一個BLE的相關需求,索性就考慮用群友“heibus”提出的CH9328+KT6368A方案來實現看看。
不過,隨著后來進一步的需求溝通,發現用CH9328+KT6368A還不行,原因是它手機端發送的指令并不是原封不動的透傳過去就行了,實際上需要做轉換,比如說手機端發送十進制1,對應到USB HID 的是兩組8字節的16進制數據:00 00 08 00 00 00 00 00和00 00 00 00 00 00 00 00,這樣單純靠硬件就完成不了了,需要涉及到軟件開發。
關于00 00 08 00 00 00 00 00和00 00 00 00 00 00 00 00這兩組數據的含義,那就得簡單補習點USB HID的基礎知識了。
鍵盤發送給PC的數據每次是8個字節:
BYTE1 BYTE2 BYTE3 BYTE4 BYTE5 BYTE6 BYTE7 BYTE8
定義分別是:
BYTE1 :特殊按鍵,具體各位含義如下:
|--bit0: Left Control是否按下,按下為1 |--bit1: Left Shift 是否按下,按下為1|--bit2: Left Alt 是否按下,按下為1 |--bit3: Left GUI 是否按下,按下為1 |--bit4: Right Control是否按下,按下為1 |--bit5: Right Shift 是否按下,按下為1|--bit6: Right Alt 是否按下,按下為1 |--bit7: Right GUI 是否按下,按下為1
BYTE2:保留
BYTE3-BYTE8 :這六個為普通按鍵,鍵值可以參考USB HID to PS/2 Scan Code Translation Table。
舉個例子,比如按鍵a對應的一幀數據是:00 00 0x04 0x00 00 00 00 00,第3字節04就是由下面這個表定義的:
這么說還是有點抽象,得來點更直觀的,電腦端我們可以用Bushound等USB分析軟件,我這里用的是Free USB Analyzer :
我用的是筆記本電腦,先外接一個USB鍵盤
在軟件左側找到USB鍵盤對應的設備,開始監控,這里只選擇Raw Data View
按一下按鍵a并松開,這時軟件界面就會顯示收到了一串數據,它其實是對應了兩組8字節數據,可以看到a確實對應04,另外00 00 00 00 00 00 00 00表示的是按鍵彈起
如果一直按住a不松手,那么顯示的就會是如下信息:
只有當你彈起按鍵a時才會顯示00 00 00 00 00 00 00 00
如果你要同時按下SHIFT+a組合按鍵再同時松開,那么對應的數據就如下:
第一個字節就表示左側的Shift鍵。
當然,如果是你先按下Shift鍵,再按下a鍵,再松開a鍵,最后松開Shift鍵,那么就對應4組數據,其分別為:
為了搞清楚這個,我就花了好久的時間,畢竟以前也沒有怎么實際用過USB。再次回到他的藍牙接收器需求,手機端輸入的范圍是數字1-83,有的數字是對應2個8字節數據,表示的是一個按鍵的按下和松開,有的數字是對應4個字節,表示的是Shift+按鍵的組合按下與松開,并且每8個字節數據之間的時間間隔是200ms。
既然KT6368A不行,那就換一個可以編程的藍牙模塊,比如TI的CC2541模塊、Nordic NRF51822模塊都可以,因為我原來支持過NXP的QN9021芯片,對它相對熟一點,所以就用QN9021來實現了。
用QN9021來實現上述軟件功能(藍牙接收手機發送過來的一串數據,然后轉碼輸出)我本來以為分分鐘就搞定了,結果實際調試起來并不是想象的那么簡單。因為常規的藍牙透傳使用方式是串口接收數據然后藍牙發送,這個需求正好是一個反向的操作。其中涉及到幾個關鍵的問題:
手機端發送過來的是一串長度可能長、可能短的數據。因為QN9021是BLE 4.0芯片,一次發送字節最多是20個字節,所以要考慮超過20字節的情況。
藍牙芯片一邊藍牙接收數據,一邊串口發送數據,要考慮串口沒有發送完,藍牙又來數據的的情況。
手機發送的不同鍵值,程序里要實現轉碼(有的是對應發送2個8字節數據,有的是對應4個8字節數據,每個8字節數據中間都是200ms)的代碼實現問題。
有經驗的程序高手可能不覺得是什么問題,但對我這樣好久沒實際寫代碼的人,還是折騰了不少時間.
上述問題1可以通過手機端分包來解決;
問題2的解決辦法是加一個隊列,把藍牙接收的數據放到隊列里緩存起來,另外一個地方從隊列取數串口發送。隊列如何用C語言實現,讓我直接寫我肯定寫不出來,我用了github上的一個開源代碼:https://github.com/kuaileguyue/Ring-Buffer
問題3我是在200ms定時器函數里做了一個小狀態機來解決的,狀態機通過switch/case和標志位就可以實現。
最后,我們再來總結一下這幾種方案:
方案 | 特點 | 價格(元器件) |
---|---|---|
CH551+KT6368A | CH551可編程,藍牙只透傳不編程 | 幾元錢 |
CH9328+BLE (NRF51822/CC2541/QN9021等) | BLE 可編程,CH9328硬件實現串口轉USB HID | 數十元 |
單BLE(NRF52840/QN9080等) | SOC可編程 | 數十元 |
CH340+KT6368A | 硬件不編程,PC上編程 | 幾元錢 |
從硬件角度來看,這幾種方案都具備BLE和USB功能,只不過軟件部分跑的地方不同,最終都可以實現所需要的功能。
至于在實際項目或產品中,到底選取哪一種方案,實際上是需要綜合考慮多方面的因素的,比如開發周期、成本、軟件開發難易,甚至芯片是否好買等。
下一步我會再研究第一個方案的實現,即CH551+KT6368A,后面大概率會用這個方案,原因大家應該都明白。
作者:wuyage 來源:TopSemic嵌入式 在此特別鳴謝
-
接收器
+關注
關注
14文章
2468瀏覽量
71871 -
usb
+關注
關注
60文章
7936瀏覽量
264475 -
藍牙
+關注
關注
114文章
5809瀏覽量
170188 -
Switch
+關注
關注
1文章
533瀏覽量
58221 -
HID
+關注
關注
2文章
130瀏覽量
46606
原文標題:一個藍牙實戰項目的掏肺總結
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論