[ESP8266/ESP32]ESP32S2 实现触摸屏

1828浏览
查看: 1828|回复: 4

[ESP8266/ESP32] ESP32S2 实现触摸屏

[复制链接]
本帖最后由 zoologist 于 2022-4-16 20:16 编辑

参照Teensy的触摸【参考1】,在 ESP32 S2 上实现了触摸屏。最关键的步骤有2个:
1.     正确的 HID Descriptor,下面是一个10指触摸的触摸屏幕的描述符
  1. static const uint8_t report_descriptor[] = { // 8 TouchData
  2.   0x05, 0x0D,
  3.   0x09, 0x04,
  4.   0xA1, 0x01,
  5.   0x09, 0x22,
  6.   0xA1, 0x02,
  7.   0x09, 0x42,
  8.   0x15, 0x00,
  9.   0x25, 0x01,
  10.   0x75, 0x01,
  11.   0x95, 0x01,
  12.   0x81, 0x02,
  13.   0x09, 0x30,
  14.   0x25, 0x7F,
  15.   0x75, 0x07,
  16.   0x95, 0x01,
  17.   0x81, 0x02,
  18.   0x09, 0x51,
  19.   0x26, 0xFF, 0x00,
  20.   0x75, 0x08,
  21.   0x95, 0x01,
  22.   0x81, 0x02,
  23.   0x05, 0x01,
  24.   0x09, 0x30,
  25.   0x09, 0x31,
  26.   0x26, 0xFF, 0x7F,
  27.   0x65, 0x00,
  28.   0x75, 0x10,
  29.   0x95, 0x02,
  30.   0x81, 0x02,
  31.   0xC0,
  32.   0x05, 0x0D,
  33.   0x27, 0xFF, 0xFF, 0x00, 0x00,
  34.   0x75, 0x10,
  35.   0x95, 0x01,
  36.   0x09, 0x56,
  37.   0x81, 0x02,
  38.   0x09, 0x54,
  39.   0x25, 0x0A,
  40.   0x75, 0x08,
  41.   0x95, 0x01,
  42.   0x81, 0x02,
  43.   0x05, 0x0D,
  44.   0x09, 0x55,
  45.   0x25, 0x0A,
  46.   0x75, 0x08,
  47.   0x95, 0x01,
  48.   0xB1, 0x02,
  49.   0xC0,
  50. };
复制代码

对应发送的数据结构是:
  1.     // touch report
  2.     //  0: on/off + pressure
  3.     //  1: contact id
  4.     //  2: X lsb
  5.     //  3: X msb
  6.     //  4: Y lsb
  7.     //  5: Y msb
  8.     //  6: scan time lsb
  9.     //  7: scan time msb
  10. //  8: contact count
复制代码
其中 Byte0 Bit0 是按下标志,一直为1Bit1-7 是按键压力;Byte1是按键编号,从 0-255,可以理解为手指编号,比如:右手食指按下,编号为0;右手中指按下,编号为1;右手抬起后再次按下,会重新分配一个编号。Byte2-3按键的X坐标;Byte4-5按键的Y坐标;Byte6-7是按压发生的事件,是以 100us为单位;Byte8是当前正在发生的按压事件中触摸点的数量。在【参考2】有一个例子:

ESP32S2 实现触摸屏图1
Table 7 Report Sequence for Two Contacts with Separated Lift(Two-Finger Hybrid)

  
   
Report
   
   
1
   
   
2
   
   
3
   
   
4
   
   
5
   
   
6
   
   
7
   
   
8
   
   
9
   
   
10
   
   
11
   
  
Contact Count
  
  
2
  
  
2
  
  
2
  
  
2
  
  
2
  
  
2
  
  
1
  
  
1
  
  
1
  
  
1
  
  
1
  
  
Contact 1 Tip Switch
  
  
1
  
  
1
  
  
1
  
  
1
  
  
1
  
  
0
  
  
NR
  
  
NR
  
  
NR
  
  
NR
  
  
NR
  
  
Contact 1 X,Y
  
  
X₁,Y₁
  
  
X₂,Y₂
  
  
X₃,Y₃
  
  
X₄,Y₄
  
  
X₅,Y₅
  
  
X₅,Y₅
  
  
NR
  
  
NR
  
  
NR
  
  
NR
  
  
NR
  
  
Contact 2 Tip Switch
  
  
1
  
  
1
  
  
1
  
  
1
  
  
1
  
  
1
  
  
1
  
  
1
  
  
1
  
  
1
  
  
0
  
  
Contact 2 X,Y
  
  
X₁,Y₁
  
  
X₂,Y₂
  
  
X₃,Y₃
  
  
X₄,Y₄
  
  
X₅,Y₅
  
  
X₆,Y₆
  
  
X₇,Y₇
  
  
X₈,Y₈
  
  
X₉,Y₉
  
  
X₁₀,Y₁₀
  
  
X₁₀,Y₁₀
  

  
图中是2个手指
图中是2个手指进行触摸的例子,R1 会分别报告手指1和2移动的信息,同时 Byte8 的 Contract Count 会等于2;R6的时候,因为手指1已经抬起,所以Contract Count会变成1.
.另外一个重要的,容易被忽视的要求:Get Report 的处理。即使上面的描述符正确报告,然后数据也正常发送到Windows中,你的触摸屏依然无法正常工作,原因就是缺少了对Get Report的处理。更糟糕的是:你无法使用 USBlyzer 这样的工具抓到 Teensy 中的数据。
ESP32S2 实现触摸屏图2
Teensy 例子中上位机发送 GET_REPORT 收到返回值0x0a
如果不在代码中特别处理,对于这个命令会 STALL
ESP32S2 实现触摸屏图3
关于这个 COMMAND 的含义,目前没搞清楚【参考3】

对于我们来说,只要有一个返回值就能让它工作正常。最终一个可以工作的代码如下:
  1. #include "USB.h"
  2. #include "USBHID.h"
  3. USBHID HID;
  4. static const uint8_t report_descriptor[] = { // 8 TouchData
  5.   0x05, 0x0D,
  6.   0x09, 0x04,
  7.   0xA1, 0x01,
  8.   0x09, 0x22,
  9.   0xA1, 0x02,
  10.   0x09, 0x42,
  11.   0x15, 0x00,
  12.   0x25, 0x01,
  13.   0x75, 0x01,
  14.   0x95, 0x01,
  15.   0x81, 0x02,
  16.   0x09, 0x30,
  17.   0x25, 0x7F,
  18.   0x75, 0x07,
  19.   0x95, 0x01,
  20.   0x81, 0x02,
  21.   0x09, 0x51,
  22.   0x26, 0xFF, 0x00,
  23.   0x75, 0x08,
  24.   0x95, 0x01,
  25.   0x81, 0x02,
  26.   0x05, 0x01,
  27.   0x09, 0x30,
  28.   0x09, 0x31,
  29.   0x26, 0xFF, 0x7F,
  30.   0x65, 0x00,
  31.   0x75, 0x10,
  32.   0x95, 0x02,
  33.   0x81, 0x02,
  34.   0xC0,
  35.   0x05, 0x0D,
  36.   0x27, 0xFF, 0xFF, 0x00, 0x00,
  37.   0x75, 0x10,
  38.   0x95, 0x01,
  39.   0x09, 0x56,
  40.   0x81, 0x02,
  41.   0x09, 0x54,
  42.   0x25, 0x0A,
  43.   0x75, 0x08,
  44.   0x95, 0x01,
  45.   0x81, 0x02,
  46.   0x05, 0x0D,
  47.   0x09, 0x55,
  48.   0x25, 0x0A,
  49.   0x75, 0x08,
  50.   0x95, 0x01,
  51.   0xB1, 0x02,
  52.   0xC0,
  53. };
  54. class CustomHIDDevice: public USBHIDDevice {
  55.   public:
  56.     CustomHIDDevice(void) {
  57.       static bool initialized = false;
  58.       if (!initialized) {
  59.         initialized = true;
  60.         HID.addDevice(this, sizeof(report_descriptor));
  61.       }
  62.     }
  63.     uint16_t _onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_t len)
  64.       {
  65.         buffer[0]=0x0A;
  66.         return 0x01;
  67.       }
  68.     void begin(void) {
  69.       HID.begin();
  70.     }
  71.     uint16_t _onGetDescriptor(uint8_t* buffer) {
  72.       memcpy(buffer, report_descriptor, sizeof(report_descriptor));
  73.       return sizeof(report_descriptor);
  74.     }
  75.     bool send(uint8_t * value) {
  76.       return HID.SendReport(0, value, 9);
  77.     }
  78. };
  79. CustomHIDDevice Device;
  80. const int buttonPin = 0;
  81. int previousButtonState = HIGH;
  82. uint8_t TouchData[9];
  83. void setup() {
  84.   Serial.begin(115200);
  85.   Serial.setDebugOutput(true);
  86.   Device.begin();
  87.   USB.begin();
  88. }
  89. void loop() {
  90.   if (HID.ready()) {
  91.     Serial.println("Finger");
  92.     // touch report
  93.     //  0: on/off + pressure
  94.     //  1: contact id
  95.     //  2: X lsb
  96.     //  3: X msb
  97.     //  4: Y lsb
  98.     //  5: Y msb
  99.     //  6: scan time lsb
  100.     //  7: scan time msb
  101.     //  8: contact count
  102.     for (int i=0;i<200;i+=100) {
  103.     TouchData[0] = 0x81; TouchData[1] = 0x08;
  104.     TouchData[2] = (16000)&0xFF; TouchData[3] = ((16000)>>8)&0xFF;
  105.     TouchData[4] = (4000+i)&0xFF; TouchData[5] = ((4000+i)>>8)&0xFF;
  106.     TouchData[6] = (millis()*10)&0xFF; TouchData[7] = (millis()*10>>8)&0xFF;
  107.     TouchData[8] = 0x01;
  108.     Device.send(TouchData);
  109.     delay(10);
  110.     TouchData[0] = 0x81; TouchData[1] = 0x08;
  111.     TouchData[2] = (16000)&0xFF; TouchData[3] = ((16000)>>8)&0xFF;
  112.     TouchData[4] = (4000+i)&0xFF; TouchData[5] = ((4000+i)>>8)&0xFF;
  113.     TouchData[6] = (millis()*10)&0xFF; TouchData[7] = (millis()*10>>8)&0xFF;
  114.     TouchData[8] = 0x01;
  115.     delay(10);
  116.     }
  117.     //每隔10秒
  118.     delay(5000);
  119.   }
  120. }
复制代码


再复杂一点,做一个画圆的:

  1. #include "USB.h"
  2. #include "USBHID.h"
  3. USBHID HID;
  4. int STARTX=16000;
  5. int STARTY=12000;
  6. int STARTR=2000;
  7. static const uint8_t report_descriptor[] = { // 8 TouchData
  8.   0x05, 0x0D,
  9.   0x09, 0x04,
  10.   0xA1, 0x01,
  11.   0x09, 0x22,
  12.   0xA1, 0x02,
  13.   0x09, 0x42,
  14.   0x15, 0x00,
  15.   0x25, 0x01,
  16.   0x75, 0x01,
  17.   0x95, 0x01,
  18.   0x81, 0x02,
  19.   0x09, 0x30,
  20.   0x25, 0x7F,
  21.   0x75, 0x07,
  22.   0x95, 0x01,
  23.   0x81, 0x02,
  24.   0x09, 0x51,
  25.   0x26, 0xFF, 0x00,
  26.   0x75, 0x08,
  27.   0x95, 0x01,
  28.   0x81, 0x02,
  29.   0x05, 0x01,
  30.   0x09, 0x30,
  31.   0x09, 0x31,
  32.   0x26, 0xFF, 0x7F,
  33.   0x65, 0x00,
  34.   0x75, 0x10,
  35.   0x95, 0x02,
  36.   0x81, 0x02,
  37.   0xC0,
  38.   0x05, 0x0D,
  39.   0x27, 0xFF, 0xFF, 0x00, 0x00,
  40.   0x75, 0x10,
  41.   0x95, 0x01,
  42.   0x09, 0x56,
  43.   0x81, 0x02,
  44.   0x09, 0x54,
  45.   0x25, 0x0A,
  46.   0x75, 0x08,
  47.   0x95, 0x01,
  48.   0x81, 0x02,
  49.   0x05, 0x0D,
  50.   0x09, 0x55,
  51.   0x25, 0x0A,
  52.   0x75, 0x08,
  53.   0x95, 0x01,
  54.   0xB1, 0x02,
  55.   0xC0,
  56. };
  57. class CustomHIDDevice: public USBHIDDevice {
  58.   public:
  59.     CustomHIDDevice(void) {
  60.       static bool initialized = false;
  61.       if (!initialized) {
  62.         initialized = true;
  63.         HID.addDevice(this, sizeof(report_descriptor));
  64.       }
  65.     }
  66.     uint16_t _onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_t len)
  67.       {
  68.         buffer[0]=0x0a;
  69.         return 1;
  70.       }
  71.     void begin(void) {
  72.       HID.begin();
  73.     }
  74.     uint16_t _onGetDescriptor(uint8_t* buffer) {
  75.       memcpy(buffer, report_descriptor, sizeof(report_descriptor));
  76.       return sizeof(report_descriptor);
  77.     }
  78.     bool send(uint8_t * value) {
  79.       return HID.SendReport(0, value, 9);
  80.     }
  81. };
  82. CustomHIDDevice Device;
  83. const int buttonPin = 0;
  84. int previousButtonState = HIGH;
  85. uint8_t TouchData[9];
  86. void setup() {
  87.   Serial.begin(115200);
  88.   Serial.setDebugOutput(true);
  89.   Device.begin();
  90.   USB.begin();
  91. }
  92. void loop() {
  93.   if (HID.ready()) {
  94.     Serial.println("Finger");
  95.     // touch report
  96.     //  0: on/off + pressure
  97.     //  1: contact id
  98.     //  2: X lsb
  99.     //  3: X msb
  100.     //  4: Y lsb
  101.     //  5: Y msb
  102.     //  6: scan time lsb
  103.     //  7: scan time msb
  104.     //  8: contact count
  105.     for (int i=0;i<101;i++) {
  106.     TouchData[0] = 0x81; TouchData[1] = 0x08;
  107.     TouchData[2] = ((int)(STARTX+STARTR*sin(2*PI*i/100)))&0xFF;
  108.     TouchData[3] = ((int)(STARTX+STARTR*sin(2*PI*i/100)))>>8&0xFF;
  109.     TouchData[4] = ((int)(STARTY+STARTR*cos(2*PI*i/100)))&0xFF;
  110.     TouchData[5] = ((int)(STARTY+STARTR*cos(2*PI*i/100)))>>8&0xFF;
  111.     TouchData[6] = (millis()*10)&0xFF; TouchData[7] = (millis()*10>>8)&0xFF;
  112.     TouchData[8] = 0x01;
  113.     Device.send(TouchData);
  114.     delay(10);
  115.     }
  116.     //每隔10秒
  117.     delay(5000);
  118.     STARTX=STARTX+300;
  119.     STARTY=STARTY+300;
  120.    
  121.   }
  122. }
复制代码
测试结果:

ESP32S2 实现触摸屏图4
视频:
就是这样,不要问这个能干啥, 还没想好。

参考:

天意岸  学徒

发表于 2022-8-14 10:59:56

我想问下哈,如果是多点触控,比如两点TouchData数组相当于加长一倍么?那关于最后一位表示按压事件中触摸点的数量,应该全都设置成2么(相当于数组中第8和第17个数就是2)?那这样我看最开始的十点数据也不太对啊
回复

使用道具 举报

zoologist  高级技匠
 楼主|

发表于 2022-8-15 09:09:58

天意岸 发表于 2022-8-14 10:59
我想问下哈,如果是多点触控,比如两点TouchData数组相当于加长一倍么?那关于最后一位表示按压事件中触摸 ...

最前面的描述符就是10点触控的,然后后面的报告中每次发送的长度都是相同的。

两个手指同时操作,数据不会在一起,会分开发送。

比如,物理上我们两个手指从一角滑动到另外一个角落,

数据上是分开发送的,数据据不会变长。
回复

使用道具 举报

天意岸  学徒

发表于 2022-8-15 15:00:30

zoologist 发表于 2022-8-15 09:09
最前面的描述符就是10点触控的,然后后面的报告中每次发送的长度都是相同的。

两个手指同时操作,数据不 ...

哦哦,我明白了,那最后一个问题就是前面两个include文件怎么搞得,我觉得你这个还是很有用的,目前我想用视觉做虚拟触屏,现在坐标可以返回了就差触屏实现了
回复

使用道具 举报

zoologist  高级技匠
 楼主|

发表于 2022-8-15 16:15:15

天意岸 发表于 2022-8-15 15:00
哦哦,我明白了,那最后一个问题就是前面两个include文件怎么搞得,我觉得你这个还是很有用的,目前我想 ...

这个应该是 ESP32 S2自带的,不是第三方的
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail