专业版
#第九届立创电赛#键盘鼠标转手机触摸设备

创建时间:2个月前

242 0

视频

描述

<p><strong>在报名阶段填写 ↓</strong></p> <p> </p> <p><strong>* 1</strong><strong>、项目功能介绍</strong></p> <div align="center"><hr align="center" width="100%"></div> <p> 相比电脑游戏,手机手机更加灵活,对于设备的要求也会更小,加之现在通讯技术发达,随时对地都能进行游戏,因此,手机游戏日益火爆。</p> <p>这次制作的就是一个将键盘鼠标转化为USB触摸进行游戏的设备。能够将键盘的 WASD 模拟为手指按键控制方向,然后鼠标移动映射为视角的变化,鼠标左键是开火,右键是打开瞄准镜。</p> <p> </p> <p><strong>*2</strong><strong>、项目属性</strong></p> <div align="center"><hr align="center" width="100%"></div> <p>原创,首次公开</p> <p> </p> <p><strong>* 3</strong><strong>、开源协议</strong></p> <div align="center"><hr align="center" width="100%"></div> <p><strong>LGPL</strong></p> <p> </p> <p> </p> <p><strong>请在竞赛阶段填写 ↓</strong></p> <p> </p> <p><strong>*4</strong><strong>、硬件部分</strong></p> <div align="center"><hr align="center" width="100%"></div> <p>1.      WCH 的 CH9350 芯片,这是一款能够接收并且解析USB HID 设备数据,然后转为串口输出的芯片。具有使用简单,兼容性强,外围元件简单的特点。它在设个项目中负责转出两个 USB Host 接口,分别连接键盘和鼠标,获得数据会从串口输出;</p> <p>2.      ESP32 S3 芯片,这款芯片自身带有 USB Device,我们通过编程的方式让它模拟为一个USB触摸屏,连接到手机之后,通过模拟触摸动作来实现我们需要的操作。</p> <p> </p> <p><strong>*5</strong><strong>、软件部分</strong></p> <div align="center"><hr align="center" width="100%"></div> <p>代码使用 Arduino 开发。基本的数据结构是:设计一个环形队列用于存放触摸操作。比如,当有 w 按键时,分析串口数据后会将一个手指的按键信息放入这个队列中。然后每隔50ms会进行队列检测,如果有按键信息,那么就按照要求发送触摸信息给手机。</p> <p> </p> <p>1.首先使用如下的描述符即可将 ESP32 S3 模拟为 USB 触摸屏</p> <p> </p> <p>static const uint8_t report_descriptor[] = { // 8 TouchData<br>  0x05, 0x0D,        // Usage Page (Digitizer)<br>  0x09, 0x04,        // Usage (Touch Screen)<br>  0xA1, 0x01,        // Collection (Application)<br>  0x09, 0x22,        //   Usage (Finger)<br>  0xA1, 0x02,        //   Collection (Logical)<br>  0x09, 0x42,        //     Usage (Tip Switch)<br>  0x15, 0x00,        //     Logical Minimum (0)<br>  0x25, 0x01,        //     Logical Maximum (1)<br>  0x75, 0x01,        //     Report Size (1)<br>  0x95, 0x01,        //     Report Count (1)<br>  0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)<br>  0x09, 0x30,        //     Usage (Tip Pressure)<br>  0x25, 0x7F,        //     Logical Maximum (127)<br>  0x75, 0x07,        //     Report Size (7)<br>  0x95, 0x01,        //     Report Count (1)<br>  0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)<br>  0x09, 0x51,        //     Usage (0x51)<br>  0x26, 0xFF, 0x00,  //     Logical Maximum (255)<br>  0x75, 0x08,        //     Report Size (8)<br>  0x95, 0x01,        //     Report Count (1)<br>  0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)<br>  0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)<br>  0x16, 0x00, 0x00, //HID_LogicalMinS (0)<br>  0x26, 0xB0, 0x04,// LOGICAL_MAXIMUM (1366)<br>  0x46, 0xB0, 0x04,// PHYSICAL_MAXIMUM (1366)<br>  0x75, 0x10,// REPORT_SIZE (16)<br>  0x55, 0x00,// UNIT_EXPONENT (0)<br>  0x65, 0x00,// UNIT (00)<br>  0x09, 0x30,// USAGE (X)<br>  0x36, 0x00, 0x00, // PHYSICAL_MINIMUM (0)<br>  0x46, 0x56, 0x05,// PHYSICAL_MAXIMUM (1366)<br>  0x95, 0x01,// REPORT_COUNT (1)<br>  0x81, 0x02,// INPUT (Data,Var,Abs)<br>  0x26, 0x68, 0x0A,// LOGICAL_MAXIMUM (2664)<br>  0x46, 0x68, 0x0A,// PHYSICAL_MAXIMUM (2664)<br>  0x09, 0x31,// USAGE (Y)<br>  0x81, 0x02,// INPUT (Data,Var,Abs)<br>  0xC0,              //   End Collection<br>  0x05, 0x0D,        //   Usage Page (Digitizer)<br>  0x27, 0xFF, 0xFF, 0x00, 0x00,  //   Logical Maximum (65534)<br>  0x75, 0x10,        //   Report Size (16)<br>  0x95, 0x01,        //   Report Count (1)<br>  0x09, 0x56,        //   Usage (0x56)<br>  0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)<br>  0x09, 0x54,        //   Usage (0x54)<br>  0x25, 0x0A,        //   Logical Maximum (10)<br>  0x75, 0x08,        //   Report Size (8)<br>  0x95, 0x01,        //   Report Count (1)<br>  0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)<br>  0x05, 0x0D,        //   Usage Page (Digitizer)<br>  0x09, 0x55,        //   Usage (0x55)<br>  0x25, 0x0A,        //   Logical Maximum (10)<br>  0x75, 0x08,        //   Report Size (8)<br>  0x95, 0x01,        //   Report Count (1)<br>  0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)<br>  0xC0,              // End Collection<br>  // 99 bytes<br>};</p> <p> </p> <p>2.定义一个存放触摸数据的队列:</p> <p> </p> <p>typedef struct {<br>  uint8_t  pressure;<br>  uint8_t     finger;<br>  uint16_t x;<br>  uint16_t y;<br>} TouchScreen;</p> <p>#define CQLENTH 200<br>TouchScreen TouchQC[CQLENTH];</p> <p> </p> <p>3.处理键盘按键,比如,按下 W 键,那么就对触摸数据队列插入一个按键信息。</p> <p> </p> <p>            if (((KeyPressFlag & KEY_W) != 0) && ((LastKeyPressFlag & KEY_W) == 0)) { //当前按下 W 键<br>              ts = { 0x81, FINGER0, FINGER0_ORG_X + 170, FINGER0_ORG_Y};<br>              SetToCircularQueue(ts);<br>            }</p> <p> </p> <p>4.循环处理触摸队列,根据队列发送按下或者抬起的动作</p> <p> </p> <p> // 每隔50ms处理一次,如果间隔太低游戏不会响应<br>  if (millis() - Elsp > 50) {<br>    int tsIndex = GetToCircularQueue();<br>    if (tsIndex != 0xFF) {<br>      Serial.print("Send Data, Index:");<br>      Serial.println(tsIndex);</p> <p>      //如果当前是按压事件<br>      if (TouchQC[tsIndex].pressure == 0x81) {</p> <p>        if ((FingerFlag & (1 << TouchQC[tsIndex].finger)) == 0) {<br>          PressedFingerNumber++;<br>        }<br>        FingerFlag = FingerFlag | (1 << TouchQC[tsIndex].finger);<br>      } else {<br>        // 抬起事件<br>        PressedFingerNumber--;<br>        FingerFlag = FingerFlag & (~(1 << TouchQC[tsIndex].finger));<br>      }<br>      if (HID.ready()) {<br>        TouchData[0] = TouchQC[tsIndex].pressure;<br>        TouchData[1] = TouchQC[tsIndex].finger;<br>        TouchData[2] = TouchQC[tsIndex].x & 0xFF;<br>        TouchData[3] = (TouchQC[tsIndex].x) >> 8 & 0xFF;<br>        TouchData[4] = TouchQC[tsIndex].y & 0xFF;<br>        TouchData[5] = (TouchQC[tsIndex].y) >> 8 & 0xFF;<br>        TouchData[6] = millis() & 0xFF; TouchData[7] = (millis() >> 8) & 0xFF;<br>        TouchData[8] = PressedFingerNumber;<br>        Device.send(TouchData);<br>      }<br>      ShowBuffer((char *)TouchData, 9);<br>      Elsp = millis();<br>    }</p> <p><strong>*6</strong><strong>、BOM</strong><strong>清单</strong></p> <div align="center"><hr align="center" width="100%"></div> <p>请输入内容…</p> <p> </p> <p>注:项目涉及的BOM清单。在<u><a href="https://lceda.cn/editor" target="_blank">嘉立创EDA</a> </u>生成/上传设计文件后,BOM将自动生成至项目详情;建议包括型号、品牌、名称、封装、采购渠道、用途等内容。具体内容和形式应以表达清楚项目构成为准。</p> <p> </p> <p><strong>*7</strong><strong>、大赛LOGO</strong><strong>验证</strong></p> <div align="center"><hr align="center" width="100%"></div> <p> </p> <p><img src="//image.lceda.cn/pullimage/YdG3r25cmnRkWJuzbHAPY9qtoAYrt5DedRBGTxCA.png" alt="" width="573" height="600"></p> <p> </p> <p><strong>* 8</strong><strong>、演示您的项目并录制成视频上传</strong></p> <div align="center"><hr align="center" width="100%"></div> <p> </p> <p>视频要求:请横屏拍摄,分辨率不低于1280×720,格式Mp4/Mov,单个视频大小限100M内;</p> <p>视频标题:立创电赛:{项目名称}-{视频模块名称};如立创电赛:《自动驾驶》-团队介绍。</p> <p> </p> <p><a href="/posts/de460543d4cf4dacb5f0326612455578" target="_blank">前往查看更多详情 ></a></p> <p> </p> <p> </p>

文档

BOM

暂无

附件

附件名 下载
ESP32Ch9350KBMS.ino

评论(1)

  • 表情
    emoji
    小嘉工作篇
    小嘉日常篇
  • 图片
成功
工程所有者当前已关闭评论
立创电赛 回复
<p>需要补充一下PCB设计图哦~</p>
goToTop
svg-battery svg-battery-wifi svg-books svg-more svg-paste svg-pencil svg-plant svg-ruler svg-share svg-user svg-logo-cn svg-double-arrow