去年的这个时候,我做了一个 USB键盘转蓝牙的装置【参考1】,有很多朋友根据我的方法成功制作出自己的转接装置。本文将介绍如何用Arduino打造一个USB鼠标转蓝牙的装置。
从原理上来说,Arduino 通过 USB Host Shield 驱动 USB 鼠标,将其切换为 Boot Protocol 模式,该模式下鼠标会用固定的格式和Arduino通讯,这样避免了不同设备需要单独解析 HID Protocol的问题 。之后,Arduino将解析出来的鼠标动作通过串口,以规定的格式告知蓝牙模块,最后在手机或者电脑端即可以蓝牙鼠标的方式进行动作。
使用的硬件如下
Arduino Uno | 1块 |
USB Host Shield
|
1块 |
带面包板的Shield板
|
1块 |
XM-04-HID-M 蓝牙HID鼠标模块 | 1块 |
18650电池(选配)
|
2节 |
18650 电池盒(选配) | 1个 |
最主要的配件如下
和之前的键盘转接装置相比,最大的不同在于本文代码使用了USB Host Shield 2.0的库,大量的底层操作都被封装起来,编程上非常简单,完全可以专注于“做什么”而不是“如何做”,这也是 Arduino的魅力所在。
代码需要用到 USB Host Shield2.0这个库,安装的方法很简单,打开 Sketch->Include Library->Manage Libraries 调出 Library Manager,直接搜索 “USB Host”字样,然后点击Install即可。
(我们需要安装的是 USB Host Shield Library 2.0,这是用起来驱动 USB Host Shield的。另外那个 USBHost是给Due 用的)
USB Host 解析出来的鼠标数据格式如下:
struct MOUSEINFO {
struct {
uint8_t bmLeftButton : 1; //鼠标左键按下标记
uint8_t bmRightButton : 1; //鼠标右键按下标记
uint8_t bmMiddleButton : 1; //鼠标中键按下标记
uint8_t bmDummy : 5; //保留
};
int8_t dX; //水平方向移动偏移
int8_t dY; //垂直方向移动偏移
};
Arduino和蓝牙模块是通过串口进行通讯的,通讯报文长为8字节,每个字节分别如下【参考3】:
BYTE1 | 0x08 | 固定值(包长度) |
BYTE2 | 0x00 | 固定值 |
BYTE3 | 0xA1 | 固定值 |
BYTE4 | 0x02 | 固定值 |
BYTE5 | Button 1/2/3 | |
BYTE6 | X-Axis(-127~127) | |
BYTE7 | Y-Axis(-127~127) | |
BYTE8 | Whell (-127~+127) |
我们需要做的只是将USB HOST 解析出来的MOUSEINFO转发给串口模块即可。
#include <hidboot.h> #include <SPI.h> #define BIT0 1 #define BIT1 2 #define BIT2 4 class MouseRptParser : public MouseReportParser { protected: void OnMouseMove (MOUSEINFO *mi); void OnLeftButtonUp (MOUSEINFO *mi); void OnLeftButtonDown (MOUSEINFO *mi); void OnRightButtonUp (MOUSEINFO *mi); void OnRightButtonDown (MOUSEINFO *mi); void OnMiddleButtonUp (MOUSEINFO *mi); void OnMiddleButtonDown (MOUSEINFO *mi); }; void SendToBT(MOUSEINFO *mi) { byte Button=0; if (mi->bmLeftButton) Button |= BIT0; else Button & !BIT0; if (mi->bmRightButton) Button |= BIT1; else Button & !BIT1; if (mi->bmMiddleButton) Button |= BIT2; else Button & !BIT2; /* Serial.println("L Mouse Move"); Serial.print("dx="); Serial.print(mi->dX, DEC); Serial.print(" dy="); Serial.println(mi->dY, DEC); Serial.println(Button,DEC); */ Serial.write(0x08); //BYTE1 Serial.write(0x00); //BYTE2 Serial.write(0xA1); //BYTE3 Serial.write(0x02); //BYTE4 Serial.write(Button); //BYTE5 Serial.write(mi->dX); //BYTE6 Serial.write(mi->dY); //BYTE7 Serial.write(0); //BYTE8 } void MouseRptParser::OnMouseMove(MOUSEINFO *mi) { SendToBT(mi); }; void MouseRptParser::OnLeftButtonUp (MOUSEINFO *mi) { //Serial.println("L Butt Up"); SendToBT(mi); }; void MouseRptParser::OnLeftButtonDown (MOUSEINFO *mi) { //Serial.println("L Butt Dn"); SendToBT(mi); }; void MouseRptParser::OnRightButtonUp (MOUSEINFO *mi) { //Serial.println("R Butt Up"); SendToBT(mi); }; void MouseRptParser::OnRightButtonDown (MOUSEINFO *mi) { //Serial.println("R Butt Dn"); SendToBT(mi); }; void MouseRptParser::OnMiddleButtonUp (MOUSEINFO *mi) { //Serial.println("M Butt Up"); SendToBT(mi); }; void MouseRptParser::OnMiddleButtonDown (MOUSEINFO *mi) { //Serial.println("M Butt Dn"); SendToBT(mi); }; USB Usb; HIDBoot<HID_PROTOCOL_MOUSE> HidMouse(&Usb); uint32_t next_time; MouseRptParser Prs; void setup() { Serial.begin( 115200 ); Serial.println("Start"); if (Usb.Init() == -1) Serial.println("OSC did not start."); delay( 200 ); next_time = millis() + 5000; HidMouse.SetReportParser(0,(HIDReportParser*)&Prs); } void loop() { Usb.Task(); }
最终的成品,Arduino和其他Shield堆叠起来,使用电池独立供电
特别注意的地方:
- 如果使用USB 供电,Arduino可能会遇到供电不足的问题(外围有USB Host Shield / USB Mouse / Bluetooth),解决办法是直接从圆形 DC 口接入电池,这就是本文使用18650电池的原因;
- 本文使用的蓝牙模块并非普通的串口蓝牙(HC05/06),而是专门的蓝牙鼠标模块。之前制作USB键盘转接设备的时候,很多朋友没有注意,购买的是 HC05/06这样的蓝牙串口模块,最后只得重新购买。关于蓝牙鼠标模块的更多信息可以在之前的介绍中看到【参考2】;
- 蓝牙 HID 模块默认波特率只有是 9600,在操作时有明显卡顿,需要对其下 AT 命令,将波特率升到 115200。
参考:
- http://www.arduino.cn/thread-17412-1-1.html U2B: USB键盘转蓝牙键盘的设备
- http://www.arduino.cn/thread-22076-1-1.html 介绍一个蓝牙鼠标模块
- XM-04-HID-M 蓝牙HID鼠标模块规格书0
老哥,你这两篇键鼠教程怎么说呢。。。其实点错科技树了。。。首先你推荐的蓝牙模块本身就是键鼠都可以用的。。。其次你推荐的这个蓝牙模块是带USB interface的,只需要飞线上去就可以达成目的,不需要额外增加arduino甚至usb host shield。。。甚至加一个usb hub模块,你可以只用一个xm04hidk就可以同时转键鼠。
您的意思是这个模块自带 USB Host 功能?
我记得模块上的 D+ D- 一般是做 Device 用的