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