ESP32S2 USB触摸屏作图

这次实验使用 ESP32 S2 模拟触摸屏的方式绘制一个心形和渐开线。

首先介绍的是“笛卡尔的爱情坐标公式”:心形函数r=a(1-sinθ),常被人当做表达爱和浪漫的一种方法。并且关于这个函数的由来有一个传播很广的故事。

笛卡尔在52岁时邂逅了当时瑞典的公主,当时他是公主的数学老师,不久公主就对笛卡尔产生了爱慕之情。然而,国王知道后,非常愤怒,将他流放回法国。在那里,笛卡尔给公主写的信都会被拦截。

在笛卡尔寄出第十三封信后,笛卡尔永远离开了这个世界。在最后的一封信上,笛卡尔只写了一个公式:r=a(1-sinΘ)

国王也看不懂,于是把这封信交给了公主。这就是我们知道的极坐标下的心型函数。

这封情书至今保存在欧洲笛卡尔纪念馆里。【这一段是“读者”体,真实情况如果用震惊体来描述的话就是“天才数学家竟被女王惨无人道的折磨”参考1】

在这个公式中有2个变量:a和θ。我们首先使用网页版的绘图工具【参考2】验证一下这个公式:

上述公式的参数方程形式为:

参数方程形式:

x= a*(2*sin(t)-sin(2*t))
y= a*(2*cos(t)-cos(2*t))
0<=t<=2*pi

根据上述公式,设计代码如下:

#include "USB.h"
#include "USBHID.h"
USBHID HID;

#define STEP 600
int STARTX=5000;
int STARTY=13000;
int STARTR=5000;
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()) {
    delay(1000);
    Serial.println("Finger");
    int iX,iY;
    iX=STARTX+(STARTR*(2*sin(0)-sin(0)))/3;
    iY=STARTY-(STARTR*(2*cos(0)-cos(0)));
    TouchData[0] = 0x81; 
    TouchData[1] = 0x02;
    TouchData[2] = (iX)&0xFF; 
    TouchData[3] = (iX)>>8&0xFF;
    TouchData[4] = (iY)&0xFF; 
    TouchData[5] = (iY)>>8&0xFF;
    TouchData[6] = (millis()*10)&0xFF; TouchData[7] = (millis()*10>>8)&0xFF;
    TouchData[8] = 0x01; 
    Device.send(TouchData);
    delay(20);
    TouchData[0] = 0x81; 
    TouchData[1] = 0x02;
    TouchData[2] = (iX+1)&0xFF; 
    TouchData[3] = (iX+1)>>8&0xFF;
    TouchData[4] = (iY)&0xFF; 
    TouchData[5] = (iY)>>8&0xFF;
    TouchData[6] = (millis()*10)&0xFF; TouchData[7] = (millis()*10>>8)&0xFF;
    TouchData[8] = 0x01; 
    Device.send(TouchData);
    delay(40);

    // 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<STEP+1;i++) {
    TouchData[0] = 0x81; TouchData[1] = 0x01;
    iX=STARTX+(STARTR*(2*sin(2*PI*i/STEP)-sin(2*2*PI*i/STEP)))/3;
    iY=STARTY-(STARTR*(2*cos(2*PI*i/STEP)-cos(2*2*PI*i/STEP)));
    Serial.print(iX);Serial.print("  ");Serial.println(iY);
    TouchData[2] = ((int)(iX))&0xFF; 
    TouchData[3] = ((int)(iX))>>8&0xFF;
    TouchData[4] = ((int)(iY))&0xFF; 
    TouchData[5] = ((int)(iY))>>8&0xFF;
    TouchData[6] = (millis()*10)&0xFF; TouchData[7] = (millis()*10>>8)&0xFF;
    TouchData[8] = 0x01; 
    Device.send(TouchData);
    delay(20);
    }
    //每隔10秒
    delay(2000);
    STARTX=STARTX+6000;
    STARTY=STARTY;
    
  }

}

渐开线的参数方程:

iX=r*cos(b)+r*b*sin(b)
iY=r*sin(b)-r*b*cos(b)

完整代码:

#include "USB.h"
#include "USBHID.h"
USBHID HID;

#define STEP 100
int STARTX = 18000;
int STARTY = 18000;
int STARTR = 100;
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()) {
    delay(1000);
    Serial.println("Finger");
    int iX, iY;
    /*
    iX = STARTX + (STARTR * (2 * sin(0) - sin(0))) / 3;
    iY = STARTY - (STARTR * (2 * cos(0) - cos(0)));
    TouchData[0] = 0x81;
    TouchData[1] = 0x02;
    TouchData[2] = (iX) & 0xFF;
    TouchData[3] = (iX) >> 8 & 0xFF;
    TouchData[4] = (iY) & 0xFF;
    TouchData[5] = (iY) >> 8 & 0xFF;
    TouchData[6] = (millis() * 10) & 0xFF; TouchData[7] = (millis() * 10 >> 8) & 0xFF;
    TouchData[8] = 0x01;
    Device.send(TouchData);
    delay(20);
    TouchData[0] = 0x81;
    TouchData[1] = 0x02;
    TouchData[2] = (iX + 1) & 0xFF;
    TouchData[3] = (iX + 1) >> 8 & 0xFF;
    TouchData[4] = (iY) & 0xFF;
    TouchData[5] = (iY) >> 8 & 0xFF;
    TouchData[6] = (millis() * 10) & 0xFF; TouchData[7] = (millis() * 10 >> 8) & 0xFF;
    TouchData[8] = 0x01;
    Device.send(TouchData);
    delay(40);
*/
    // 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 < STEP*18; i++) {
      TouchData[0] = 0x81; TouchData[1] = 0x01;
      iX = STARTX+(STARTR * cos(2*PI*i/STEP) + STARTR * (2*PI*i/STEP) * sin(2*PI*i/STEP))*3/4;
      iY = STARTY+STARTR * sin(2*PI*i/STEP) - STARTR * (2*PI*i/STEP) * cos(2*PI*i/STEP);
      Serial.print(iX); Serial.print("  "); Serial.println(iY);
      TouchData[2] = ((int)(iX)) & 0xFF;
      TouchData[3] = ((int)(iX)) >> 8 & 0xFF;
      TouchData[4] = ((int)(iY)) & 0xFF;
      TouchData[5] = ((int)(iY)) >> 8 & 0xFF;
      TouchData[6] = (millis() * 10) & 0xFF; TouchData[7] = (millis() * 10 >> 8) & 0xFF;
      TouchData[8] = 0x01;
      Device.send(TouchData);
      delay(20);
    }
    //每隔10秒
    delay(2000);
    STARTX = STARTX + 3;
    STARTY = STARTY;

  }

}

运行结果:

参考:

1. https://baijiahao.baidu.com/s?id=1721580028060990553&wfr=spider&for=pc

2. https://zuotu.91maths.com/#W3sidHlwZSI6MSwiZXEiOiIyKigxLXNpbih0aGV0YSkpIiwiY29sb3IiOiIjMDA4MGNjIiwidGhldGFtaW4iOiIwIiwidGhldGFtYXgiOiIycGkiLCJ0aGV0YXN0ZXAiOiIwLjAxIn0seyJ0eXBlIjoxMDAwLCJ3aW5kb3ciOlsiLTguMjE1MTExOTk5OTk5OTkiLCI4LjAzNDg4Nzk5OTk5OTk5MiIsIi01LjI3ODUyNzk5OTk5OTk5NSIsIjQuNzIxNDcxOTk5OTk5OTk2Il0sImdyaWQiOlsiMSIsIjEiXX1d

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注