1、个人网站 [color=rgb(85, 136, 255) !important]www.lab-z.com 一直在使用 Arduino 制作各种设备 2、一些特定情况下,公司的机器不支持USB接口,因此想在电脑上使用USB接口的键盘鼠标会遇到问题。对于传统的有线鼠标可以通过淘宝上的转接器直接完成(能够实现这一点是因为USB鼠标芯片能够直接识别当前所用的接口),但是非常不幸的是无线鼠标并没有这样的接口,因此无法通过这种转接器来完成转接。因此,使用 Arduino 制作一个能将无线USB转接为 PS/2、的设备。 < br> 【请在竞赛阶段填写 ↓】 * 1、描述项目详情 USB是由英特尔等多家公司联合在1996年推出的一种外部总线标准,用于电脑与外部设备的连接和通讯。相比之前的串口并口等等接口,USB具有方便扩展,可连接多种外设以及支持热插拔等等优点。因为上述优点,USB接口迅速普及,很快就应用于键盘鼠标和主机的连接。在USB普及之前,PS/2接口是专门为键盘鼠标设计的接口,更早之前还有串口作为鼠标接口。键盘鼠标可以通过这个接口接入电脑中,PS/2和USB这两种接口从外形到协议都是截然不同的。通常如果想将一个 USB键盘鼠标设备接入到PS2接口上可以使用下面这个转接器。 实际上其中没有任何元件只是物理连接,将USB6的D+ D-连接到 PS2的CLK 和DATA。通过键盘鼠标设备在上电的时候判断接口类型自动选择协议。非常不幸的是,很多无线键盘鼠标的接收器并没有这个功能,因此,用户无法在PS2接口上使用USB无线键盘鼠标,当然市场上也从未出见过PS2接口的无线键盘鼠标。这次就是使用 Arduino 制作一个将无线鼠标转接为PS2的设备。 * 2、描述项目所面临的挑战及所解决的问题 基本原理如下:鼠标将移动和按键数据通过无线协议发送给USB接收器,接收器取得数据后以HID协议上报给Arduino USB Host Shield,接下来 Arduino 负责将USB数据解析出来再转化为 PS2协议发送给主机: 【参考1】对于 X 方向有 Byte 1 的 Bit 4 (X sign bit)来表示方向(正负),还有 Byte 1的 Bit 6 (X overflow) 以及Byte 2 来表示移动距离。所以 PS/2 鼠标的 X 移动范围是 -255 ~ +255 。 * 3、描述项目硬件、软件部分涉及到的关键点 这次转接的目标是罗技 M105 无线鼠标,此外还有下列元件
元件 数量选择理由
USB Host Shield Mini1为了保证转接器体积小,这次选择 USB Host Shield Mini来作为USB Host;
3.3V Arduino Pro Micro1常见的 Arduino Pro Micro 是5V 这次选择的是3.3V版本的,因为这个版本信号也都是3.3V电平可以直接和 USB Host Mini Shield 进行通讯。如果选择5V版本,只有加入电平转换电路才能正常通讯;
PS2 公头线1用于将PS2连接到PC端
3mm 铜柱螺丝若干整体固定电路图如下: 上述主要分为 2部分,一个是USB Host Mini 对 Arduino Pro Micro 3.3V 的连接,双方是通过SPI进行通讯的。这里再次强调必须是 3.3V 版本的 Arduino Pro Micro才能直接通讯;另外一部分是Arduino 对PS2的通讯,因为 Arduino 是 3.3V,所以需要使用下面这个电路来进行双向电平转换,来自 Arduino D3_3.3V 和 D3_5V 进行通讯, PCB 设计如下: 预览: 硬件确定后即可开始软件设计。第一步:USB 数据的解析。特别注意,不同的鼠标发出来的格式不同,这里使用的是罗技 M185无线鼠标。首先用USBLyzer 分析USB接收器的 HID 数据,抓取到的如下: 再通过实验确定数据格式: 每次鼠标接收器会发送8字节的数据给主机:AA XX BB CC DD EE FF GGAA 的低三位对于鼠标三个按键;XX 一直为00;BB CC 给出 x 方向移动数据(0xCCBB); DD EE 给出 y 方向的移动数据(0xEEDD); FF 是滚轮移动的距离;GG 这里在 Descriptor 中的描述是 AC Pan, 这是一种水平方向的滚轮,但是在笔者使用的M185上并不存在这个滚轮,所以始终为0。鼠标发送的格式就是下面这个结构体。 struct USBMouseData_LogitechM185{ struct { unsigned char _left_btn : 1; // 1 byte unsigned char _right_btn : 1; unsigned char _middle_btn : 1; unsigned char _dummy : 5; }; char na1; int _delta_x; int _delta_y; char _delta_z; char na2; };< br> < br> 鼠标的解析在之前的文章中介绍过很多次,这里就不过多复述。还有一个需要注意的地方是USB Host Library 会比对本次数据和上一次的数据,如果有差别那么就不会将新的数据发送给上层。这个设计会影响鼠标的滚轮,因为滚轮转动数据量不大,经常只是滚动一行,这样会出现滚动并不灵敏的情况,因此在 \USB_Host_Shield_Library_2.0\hiduniversal.cpp 中做如下修改: bool HIDUniversal::BuffersIdentical(uint8_t len, uint8_t *buf1, uint8_t *buf2) { for(uint8_t i = 0; i < len; i++) if(buf1 != buf2) return false; if (buf1[6]!=0) return false; //LABZDebug return true;}< br> < br> 只要USB 传来的数据中,第七个数值不为零,就认为这个数据应该发送给上层处理。USB 数据会在 void on_usb_data(USBMouseData_LogitechM185* data) 函数中处理。这里对收到的鼠标 X Y移动数据进行处理。PS2 鼠标的移动范围是-255 到 +255,罗技 M185 鼠标的移动范围是-32767到+32767.通常的想法是使用 MAP 函数进行处理,但是这样做的结果会导致鼠标灵敏度下降。经过研究发现这是因为大部分的移动数值很小,使用MAP 函数会将这个数值变得更小,导致灵敏度下降。于是,编写mousemap() 函数,对于超过255的移动直接变成 255\, 对于绝对值小于 255的数值不做处理。 int mousemap(int value) { if (value< -255) {return -255;} if ((value>=-255)&&(value< =255)) {return value;} if (value>255) {return 255;}}< br> < br> 经过上面的处理后,通过 PS2MouseSample() 函数即将数据通过 PS2 接口发送给主机端。网上有很多 Arduino PS/2 的库,但是大多数是Arduino作为PS2 Host ,这里我们需要将 Arduino 作为 PS2 Device,因此使用 [color=rgb(85, 136, 255) !important]https://github.com/harvie/ps2dev 这个库。最初我使用一个 PS/2 转USB 的转接线来进行实验(理论上,现在的 PS/2 已经支持了热插拔,但是我确实见过热插拔烧坏主板的事情,稳妥起见并不建议在主板上进行PS/2 设备的热插拔)。 但是实验中发现 PS2Dev 库无法在上面工作,后来试用了DSLogic逻辑分析仪【参控2】,发现这个竟然无法解析PS/2协议,最终入手了Kingst LA2016usb逻辑分析仪。 * 4、项目材料清单展示 这次转接的目标是罗技 M105 无线鼠标,此外还有下列元件
元件 数量选择理由
USB Host Shield Mini1为了保证转接器体积小,这次选择 USB Host Shield Mini来作为USB Host;
3.3V Arduino Pro Micro1常见的 Arduino Pro Micro 是5V 这次选择的是3.3V版本的,因为这个版本信号也都是3.3V电平可以直接和 USB Host Mini Shield 进行通讯。如果选择5V版本,只有加入电平转换电路才能正常通讯;
PS2 公头线1用于将PS2连接到PC端
3mm 铜柱螺丝若干整体固定* 5、项目图片上传 7、是否首次公开发布 首次发表 7.1、项目之前是否发表过或获奖,请说明 未发表过 7.2、若项目是在原有基础上优化,请说明优化部分 8、开源文档 源代码可以在附件中下载到 * 9、参考文献 参考: - [color=rgb(85, 136, 255) !important]https://isdaman.com/alsos/hardware/mouse/ps2interface.htm
- [color=rgb(85, 136, 255) !important]http://www.lab-z.com/dslogic/ DSLogic逻辑分析仪试用
- [color=rgb(85, 136, 255) !important]http://www-ug.eecg.toronto.edu/msl/nios_devices/datasheets/PS2%20Keyboard%20Protocol.htm *0xFA (Set All Keys Typematic/Make/Break) - Keyboard responds with "ack" (0xFA). Sets all keys to their normal setting (generate scan codes on make, break, and typematic repeat) 4. [color=rgb(85, 136, 255) !important]https://github.com/liumazi/MzMouse
|