本帖最后由 zoologist 于 2022-4-16 20:16 编辑
参照Teensy的触摸【参考1】,在 ESP32 S2 上实现了触摸屏。最关键的步骤有2个: 1. 正确的 HID Descriptor,下面是一个10指触摸的触摸屏幕的描述符
- static const uint8_t report_descriptor[] = { // 8 TouchData
- 0x05, 0x0D,
- 0x09, 0x04,
- 0xA1, 0x01,
- 0x09, 0x22,
- 0xA1, 0x02,
- 0x09, 0x42,
- 0x15, 0x00,
- 0x25, 0x01,
- 0x75, 0x01,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x09, 0x30,
- 0x25, 0x7F,
- 0x75, 0x07,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x09, 0x51,
- 0x26, 0xFF, 0x00,
- 0x75, 0x08,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x05, 0x01,
- 0x09, 0x30,
- 0x09, 0x31,
- 0x26, 0xFF, 0x7F,
- 0x65, 0x00,
- 0x75, 0x10,
- 0x95, 0x02,
- 0x81, 0x02,
- 0xC0,
- 0x05, 0x0D,
- 0x27, 0xFF, 0xFF, 0x00, 0x00,
- 0x75, 0x10,
- 0x95, 0x01,
- 0x09, 0x56,
- 0x81, 0x02,
- 0x09, 0x54,
- 0x25, 0x0A,
- 0x75, 0x08,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x05, 0x0D,
- 0x09, 0x55,
- 0x25, 0x0A,
- 0x75, 0x08,
- 0x95, 0x01,
- 0xB1, 0x02,
- 0xC0,
- };
复制代码
对应发送的数据结构是: - // touch report
- // 0: on/off + pressure
- // 1: contact id
- // 2: X lsb
- // 3: X msb
- // 4: Y lsb
- // 5: Y msb
- // 6: scan time lsb
- // 7: scan time msb
- // 8: contact count
复制代码
其中 Byte0 Bit0 是按下标志,一直为1,Bit1-7 是按键压力;Byte1是按键编号,从 0-255,可以理解为手指编号,比如:右手食指按下,编号为0;右手中指按下,编号为1;右手抬起后再次按下,会重新分配一个编号。Byte2-3按键的X坐标;Byte4-5按键的Y坐标;Byte6-7是按压发生的事件,是以 100us为单位;Byte8是当前正在发生的按压事件中触摸点的数量。在【参考2】有一个例子:
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 中的数据。
Teensy 例子中上位机发送 GET_REPORT 收到返回值0x0a 如果不在代码中特别处理,对于这个命令会 STALL 关于这个 COMMAND 的含义,目前没搞清楚【参考3】
对于我们来说,只要有一个返回值就能让它工作正常。最终一个可以工作的代码如下: - #include "USB.h"
- #include "USBHID.h"
- USBHID HID;
-
- static const uint8_t report_descriptor[] = { // 8 TouchData
- 0x05, 0x0D,
- 0x09, 0x04,
- 0xA1, 0x01,
- 0x09, 0x22,
- 0xA1, 0x02,
- 0x09, 0x42,
- 0x15, 0x00,
- 0x25, 0x01,
- 0x75, 0x01,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x09, 0x30,
- 0x25, 0x7F,
- 0x75, 0x07,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x09, 0x51,
- 0x26, 0xFF, 0x00,
- 0x75, 0x08,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x05, 0x01,
- 0x09, 0x30,
- 0x09, 0x31,
- 0x26, 0xFF, 0x7F,
- 0x65, 0x00,
- 0x75, 0x10,
- 0x95, 0x02,
- 0x81, 0x02,
- 0xC0,
- 0x05, 0x0D,
- 0x27, 0xFF, 0xFF, 0x00, 0x00,
- 0x75, 0x10,
- 0x95, 0x01,
- 0x09, 0x56,
- 0x81, 0x02,
- 0x09, 0x54,
- 0x25, 0x0A,
- 0x75, 0x08,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x05, 0x0D,
- 0x09, 0x55,
- 0x25, 0x0A,
- 0x75, 0x08,
- 0x95, 0x01,
- 0xB1, 0x02,
- 0xC0,
- };
-
- class CustomHIDDevice: public USBHIDDevice {
- public:
- CustomHIDDevice(void) {
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
- HID.addDevice(this, sizeof(report_descriptor));
- }
- }
- uint16_t _onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_t len)
- {
- buffer[0]=0x0A;
- return 0x01;
- }
- void begin(void) {
- HID.begin();
- }
-
- uint16_t _onGetDescriptor(uint8_t* buffer) {
- memcpy(buffer, report_descriptor, sizeof(report_descriptor));
- return sizeof(report_descriptor);
- }
-
- bool send(uint8_t * value) {
- return HID.SendReport(0, value, 9);
- }
- };
-
- CustomHIDDevice Device;
-
- const int buttonPin = 0;
- int previousButtonState = HIGH;
- uint8_t TouchData[9];
-
- void setup() {
- Serial.begin(115200);
- Serial.setDebugOutput(true);
- Device.begin();
- USB.begin();
- }
-
- void loop() {
- if (HID.ready()) {
- Serial.println("Finger");
- // touch report
- // 0: on/off + pressure
- // 1: contact id
- // 2: X lsb
- // 3: X msb
- // 4: Y lsb
- // 5: Y msb
- // 6: scan time lsb
- // 7: scan time msb
- // 8: contact count
- for (int i=0;i<200;i+=100) {
- TouchData[0] = 0x81; TouchData[1] = 0x08;
- TouchData[2] = (16000)&0xFF; TouchData[3] = ((16000)>>8)&0xFF;
- TouchData[4] = (4000+i)&0xFF; TouchData[5] = ((4000+i)>>8)&0xFF;
- TouchData[6] = (millis()*10)&0xFF; TouchData[7] = (millis()*10>>8)&0xFF;
- TouchData[8] = 0x01;
- Device.send(TouchData);
- delay(10);
- TouchData[0] = 0x81; TouchData[1] = 0x08;
- TouchData[2] = (16000)&0xFF; TouchData[3] = ((16000)>>8)&0xFF;
- TouchData[4] = (4000+i)&0xFF; TouchData[5] = ((4000+i)>>8)&0xFF;
- TouchData[6] = (millis()*10)&0xFF; TouchData[7] = (millis()*10>>8)&0xFF;
- TouchData[8] = 0x01;
- delay(10);
- }
- //每隔10秒
- delay(5000);
- }
- }
复制代码
再复杂一点,做一个画圆的:
- #include "USB.h"
- #include "USBHID.h"
- USBHID HID;
-
- int STARTX=16000;
- int STARTY=12000;
- int STARTR=2000;
- static const uint8_t report_descriptor[] = { // 8 TouchData
- 0x05, 0x0D,
- 0x09, 0x04,
- 0xA1, 0x01,
- 0x09, 0x22,
- 0xA1, 0x02,
- 0x09, 0x42,
- 0x15, 0x00,
- 0x25, 0x01,
- 0x75, 0x01,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x09, 0x30,
- 0x25, 0x7F,
- 0x75, 0x07,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x09, 0x51,
- 0x26, 0xFF, 0x00,
- 0x75, 0x08,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x05, 0x01,
- 0x09, 0x30,
- 0x09, 0x31,
- 0x26, 0xFF, 0x7F,
- 0x65, 0x00,
- 0x75, 0x10,
- 0x95, 0x02,
- 0x81, 0x02,
- 0xC0,
- 0x05, 0x0D,
- 0x27, 0xFF, 0xFF, 0x00, 0x00,
- 0x75, 0x10,
- 0x95, 0x01,
- 0x09, 0x56,
- 0x81, 0x02,
- 0x09, 0x54,
- 0x25, 0x0A,
- 0x75, 0x08,
- 0x95, 0x01,
- 0x81, 0x02,
- 0x05, 0x0D,
- 0x09, 0x55,
- 0x25, 0x0A,
- 0x75, 0x08,
- 0x95, 0x01,
- 0xB1, 0x02,
- 0xC0,
- };
-
- class CustomHIDDevice: public USBHIDDevice {
- public:
- CustomHIDDevice(void) {
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
- HID.addDevice(this, sizeof(report_descriptor));
- }
- }
- uint16_t _onGetFeature(uint8_t report_id, uint8_t* buffer, uint16_t len)
- {
- buffer[0]=0x0a;
- return 1;
- }
- void begin(void) {
- HID.begin();
- }
-
- uint16_t _onGetDescriptor(uint8_t* buffer) {
- memcpy(buffer, report_descriptor, sizeof(report_descriptor));
- return sizeof(report_descriptor);
- }
-
- bool send(uint8_t * value) {
- return HID.SendReport(0, value, 9);
- }
- };
-
- CustomHIDDevice Device;
-
- const int buttonPin = 0;
- int previousButtonState = HIGH;
- uint8_t TouchData[9];
-
- void setup() {
- Serial.begin(115200);
- Serial.setDebugOutput(true);
- Device.begin();
- USB.begin();
- }
-
- void loop() {
- if (HID.ready()) {
- Serial.println("Finger");
- // touch report
- // 0: on/off + pressure
- // 1: contact id
- // 2: X lsb
- // 3: X msb
- // 4: Y lsb
- // 5: Y msb
- // 6: scan time lsb
- // 7: scan time msb
- // 8: contact count
- for (int i=0;i<101;i++) {
- TouchData[0] = 0x81; TouchData[1] = 0x08;
- TouchData[2] = ((int)(STARTX+STARTR*sin(2*PI*i/100)))&0xFF;
- TouchData[3] = ((int)(STARTX+STARTR*sin(2*PI*i/100)))>>8&0xFF;
- TouchData[4] = ((int)(STARTY+STARTR*cos(2*PI*i/100)))&0xFF;
- TouchData[5] = ((int)(STARTY+STARTR*cos(2*PI*i/100)))>>8&0xFF;
- TouchData[6] = (millis()*10)&0xFF; TouchData[7] = (millis()*10>>8)&0xFF;
- TouchData[8] = 0x01;
- Device.send(TouchData);
- delay(10);
- }
- //每隔10秒
- delay(5000);
- STARTX=STARTX+300;
- STARTY=STARTY+300;
-
- }
- }
复制代码
测试结果:
视频: 就是这样,不要问这个能干啥, 还没想好。
参考:
|