查看: 9037|回复: 9

Arduino打造 USB转蓝牙鼠标的装置

[复制链接]

该用户从未签到

发表于 2016-8-23 21:16 | 显示全部楼层 |阅读模式
本帖最后由 Zoologist 于 2016-8-23 21:41 编辑

去年的这个时候,我做了一个 USB键盘转蓝牙的装置【参考1】,有很多朋友根据我的方法成功制作出自己的转接装置。本文将介绍如何用Arduino打造一个USB鼠标转蓝牙的装置。
无标题.png
从原理上来说,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个

最主要的配件如下
image002.jpg


和之前的键盘转接装置相比,最大的不同在于本文代码使用了USB Host Shield 2.0的库,大量的底层操作都被封装起来,编程上非常简单,完全可以专注于“做什么”而不是“如何做”,这也是 Arduino的魅力所在。
代码需要用到 USB Host Shield2.0这个库,安装的方法很简单,打开 Sketch->Include Library->Manage Libraries 调出 Library Manager,直接搜索 “USBHost”字样,然后点击Install即可。

(我们需要安装的是 USB Host Shield Library 2.0,这是用起来驱动 USB HostShield的。另外那个 USBHost是给Due 用的)
image003.png
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转发给串口模块即可。

kittenblock中小学创客名师推荐的图形化编程软件

#include <hidboot.h>
#include <SPI.h>
#define BIT0  1
#define BIT1  2
#define BIT2  4
class MouseRptParser : publicMouseReportParser
{
protected:
         voidOnMouseMove     (MOUSEINFO *mi);
         voidOnLeftButtonUp   (MOUSEINFO *mi);
         voidOnLeftButtonDown      (MOUSEINFO *mi);
         voidOnRightButtonUp (MOUSEINFO *mi);
         voidOnRightButtonDown    (MOUSEINFO *mi);
         voidOnMiddleButtonUp      (MOUSEINFO *mi);
         voidOnMiddleButtonDown         (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 notstart.");
   delay( 200 );
   next_time = millis() + 5000;
   HidMouse.SetReportParser(0,(HIDReportParser*)&Prs);
}
void loop()
{
Usb.Task();
}
最终的成品,Arduino和其他Shield堆叠起来,使用电池独立供电
image004.jpg

特别注意的地方:
1.      如果使用USB 供电,Arduino可能会遇到供电不足的问题(外围有USB Host Shield / USB Mouse / Bluetooth),解决办法是直接从圆形DC 口接入电池,这就是本文使用18650电池的原因;
2.      本文使用的蓝牙模块并非普通的串口蓝牙(HC05/06),而是专门的蓝牙鼠标模块。之前制作USB键盘转接设备的时候,很多朋友没有注意,购买的是 HC05/06这样的蓝牙串口模块,最后只得重新购买。关于蓝牙鼠标模块的更多信息可以在之前的介绍中看到【参考2】;
3.      蓝牙 HID 模块默认波特率只有是 9600,在操作时有明显卡顿,需要对其下 AT 命令,将波特率升到 115200。

参考:
1.      http://www.arduino.cn/thread-17412-1-1.html  U2B: USB键盘转蓝牙键盘的设备
2.      http://www.arduino.cn/thread-22076-1-1.html介绍一个蓝牙鼠标模块
3.      XM-04-HID-M 蓝牙HID鼠标模块规格书 V1.0

打赏作者鼓励一下!

该用户从未签到

发表于 2016-8-24 11:10 | 显示全部楼层
赞一个,感谢分享
  • TA的每日心情
    开心
    2019-9-6 09:30
  • 签到天数: 742 天

    [LV.9]以坛为家II

    发表于 2016-12-10 22:59 | 显示全部楼层
    赞一个  感谢分享
    打赏作者鼓励一下!

    该用户从未签到

    发表于 2018-8-24 15:50 | 显示全部楼层
    大神你好,我是arduino小菜鸡,用了你的代码,但是出现了些问题,你能帮忙看一下吗?Arduino:1.8.4 (Windows 10), 开发板:"Arduino/Genuino Uno"  sketch_jul11a:7: error: expected class-name before '{' token   {   ^  sketch_jul11a:55: error: no 'void MouseRptParser::OnMouseMove(MOUSEINFO*)' member function declared in class 'MouseRptParser'   void MouseRptParser::OnMouseMove(MOUSEINFO*mi)                                                ^  sketch_jul11a:59: error: no 'void MouseRptParser::OnLeftButtonUp(MOUSEINFO*)' member function declared in class 'MouseRptParser'   void MouseRptParser::OnLeftButtonUp   (MOUSEINFO *mi)                                                       ^  sketch_jul11a:64: error: no 'void MouseRptParser::OnLeftButtonDown(MOUSEINFO*)' member function declared in class 'MouseRptParser'   void MouseRptParser::OnLeftButtonDown       (MOUSEINFO *mi)                                                             ^  sketch_jul11a:69: error: no 'void MouseRptParser::OnRightButtonUp(MOUSEINFO*)' member function declared in class 'MouseRptParser'   void MouseRptParser::OnRightButtonUp (MOUSEINFO *mi)                                                      ^  sketch_jul11a:74: error: no 'void MouseRptParser::OnRightButtonDown(MOUSEINFO*)' member function declared in class 'MouseRptParser'   void MouseRptParser::OnRightButtonDown    (MOUSEINFO *mi)                                                           ^  sketch_jul11a:79: error: no 'void MouseRptParser::OnMiddleButtonUp(MOUSEINFO*)' member function declared in class 'MouseRptParser'   void MouseRptParser::OnMiddleButtonUp      (MOUSEINFO *mi)                                                            ^  sketch_jul11a:84: error: no 'void MouseRptParser::OnMiddleButtonDown(MOUSEINFO*)' member function declared in class 'MouseRptParser'   void MouseRptParser::OnMiddleButtonDown          (MOUSEINFO *mi)                                                                  ^  sketch_jul11a:90: error: 'HID_PROTOCOL_MOUSE' was not declared in this scope   HIDBoot<HID_PROTOCOL_MOUSE>    HidMouse(&Usb);           ^  sketch_jul11a:90: error: template argument 1 is invalid   HIDBoot<HID_PROTOCOL_MOUSE>    HidMouse(&Usb);                             ^  sketch_jul11a:90: error: invalid type in declaration before '(' token   HIDBoot<HID_PROTOCOL_MOUSE>    HidMouse(&Usb);                                          ^  C:\Users\YZY\Documents\Arduino\sketch_jul11a\sketch_jul11a.ino: In function 'void setup()':  sketch_jul11a:101: error: request for member 'SetReportParser' in 'HidMouse', which is of non-class type 'int'      HidMouse.SetReportParser(0,(HIDReportParser*)&Prs);               ^  "hidboot.h" 对应多个库  已使用: C:\Users\YZY\Documents\Arduino\libraries\USB_Host_Shield_2.0-master  未使用:F:\Arduino\libraries\USB_Host_Shield_2.0-master  未使用:F:\Arduino\libraries\USB_Host_Shield_2.0-master  未使用:F:\Arduino\libraries\USB_Host_Shield_2.0-master  未使用:F:\Arduino\libraries\USB_Host_Shield_2.0-master exit status 1 expected class-name before '{' token  在文件 -> 首选项开启 “编译过程中显示详细输出”选项 这份报告会包含更多信息。

    该用户从未签到

    发表于 2018-8-24 15:52 | 显示全部楼层
    大神你好,我是arduino小菜鸡,用了你的代码,不知道出现了什么问题,你能帮忙看一下吗?


    Arduino:1.8.4 (Windows 10), 开发板:"Arduino/Genuino Uno"

    sketch_jul11a:7: error: expected class-name before '{' token

    {

    ^

    sketch_jul11a:55: error: no 'void MouseRptParser::OnMouseMove(MOUSEINFO*)' member function declared in class 'MouseRptParser'

    void MouseRptParser::OnMouseMove(MOUSEINFO*mi)

                                                  ^

    sketch_jul11a:59: error: no 'void MouseRptParser::OnLeftButtonUp(MOUSEINFO*)' member function declared in class 'MouseRptParser'

    void MouseRptParser::OnLeftButtonUp   (MOUSEINFO *mi)

                                                         ^

    sketch_jul11a:64: error: no 'void MouseRptParser::OnLeftButtonDown(MOUSEINFO*)' member function declared in class 'MouseRptParser'

    void MouseRptParser::OnLeftButtonDown       (MOUSEINFO *mi)

                                                               ^

    sketch_jul11a:69: error: no 'void MouseRptParser::OnRightButtonUp(MOUSEINFO*)' member function declared in class 'MouseRptParser'

    void MouseRptParser::OnRightButtonUp (MOUSEINFO *mi)

                                                        ^

    sketch_jul11a:74: error: no 'void MouseRptParser::OnRightButtonDown(MOUSEINFO*)' member function declared in class 'MouseRptParser'

    void MouseRptParser::OnRightButtonDown    (MOUSEINFO *mi)

                                                             ^

    sketch_jul11a:79: error: no 'void MouseRptParser::OnMiddleButtonUp(MOUSEINFO*)' member function declared in class 'MouseRptParser'

    void MouseRptParser::OnMiddleButtonUp      (MOUSEINFO *mi)

                                                              ^

    sketch_jul11a:84: error: no 'void MouseRptParser::OnMiddleButtonDown(MOUSEINFO*)' member function declared in class 'MouseRptParser'

    void MouseRptParser::OnMiddleButtonDown          (MOUSEINFO *mi)

                                                                    ^

    sketch_jul11a:90: error: 'HID_PROTOCOL_MOUSE' was not declared in this scope

    HIDBoot<HID_PROTOCOL_MOUSE>    HidMouse(&Usb);

             ^

    sketch_jul11a:90: error: template argument 1 is invalid

    HIDBoot<HID_PROTOCOL_MOUSE>    HidMouse(&Usb);

                               ^

    sketch_jul11a:90: error: invalid type in declaration before '(' token

    HIDBoot<HID_PROTOCOL_MOUSE>    HidMouse(&Usb);

                                            ^

    C:\Users\YZY\Documents\Arduino\sketch_jul11a\sketch_jul11a.ino: In function 'void setup()':

    sketch_jul11a:101: error: request for member 'SetReportParser' in 'HidMouse', which is of non-class type 'int'

        HidMouse.SetReportParser(0,(HIDReportParser*)&Prs);

                 ^

    "hidboot.h" 对应多个库
    已使用: C:\Users\YZY\Documents\Arduino\libraries\USB_Host_Shield_2.0-master
    未使用:F:\Arduino\libraries\USB_Host_Shield_2.0-master
    未使用:F:\Arduino\libraries\USB_Host_Shield_2.0-master
    未使用:F:\Arduino\libraries\USB_Host_Shield_2.0-master
    未使用:F:\Arduino\libraries\USB_Host_Shield_2.0-master
    exit status 1
    expected class-name before '{' token

    在文件 -> 首选项开启
    “编译过程中显示详细输出”选项
    这份报告会包含更多信息。

    该用户从未签到

    发表于 2018-8-24 15:54 | 显示全部楼层
    william_bit 发表于 2018-8-24 15:50
    大神你好,我是arduino小菜鸡,用了你的代码,但是出现了些问题,你能帮忙看一下吗?Arduino:1.8.4 (Window ...

    不会玩,又在下面重新发了一个,可能下面那一个更清晰一些

    该用户从未签到

    发表于 2018-9-8 17:28 | 显示全部楼层
    为什么用了您的代码,正确连接了硬件,然后与电脑蓝牙连接后还是无法实现功能

    该用户从未签到

     楼主| 发表于 2018-9-9 08:16 | 显示全部楼层
    william_bit 发表于 2018-9-8 17:28
    为什么用了您的代码,正确连接了硬件,然后与电脑蓝牙连接后还是无法实现功能 ...

    有可能是你键盘不支持 Boot protocol
    打赏作者鼓励一下!
  • TA的每日心情
    奋斗
    2019-9-17 00:35
  • 签到天数: 48 天

    [LV.5]常住居民I

    发表于 2019-8-23 17:35 | 显示全部楼层

    kittenblock中小学创客名师推荐的图形化编程软件

        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;

    这段代码什么意思呢 按下  抬起么?

    该用户从未签到

     楼主| 发表于 2019-8-23 20:02 | 显示全部楼层
    想学坏的小孩 发表于 2019-8-23 17:35
    [mw_shl_code=arduino,true]    byte  Button=0;
         
        if (mi->bmLeftButton)

    把按键信息解析之后重新排列从蓝牙发送出去
    打赏作者鼓励一下!
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    新手求助,串口通信AT指令发送无反应
    新手求助,串口通信AT指令
    现在想用arduino uno板连接esp12-N无线模块发送数据,但是使用串口助手发送AT指令
    【Arduino】108种传感器模块系列实验(40)---旋转编码器模块
    【Arduino】108种传感器模
    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是
    Arduino串口事件
    Arduino串口事件
    向各位大佬求助,学习了serialEvent(),按照书上的程序,我是直接使用的示例中的serial
    基于arduino的delta并联机械手
    基于arduino的delta并联机
    delta并联机械手现在广泛应用于工业,因为资金有限,用舵机做的,底座这些也是
    基于机器视觉的智能分拣机械臂
    基于机器视觉的智能分拣机
    本作品是一个基于机器视觉的智能机械臂操作平台,其采用atmega32单片机作为主控制系统
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表