去年的这个时候,我做了一个 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 用的