見出し画像

M5Core2 タッチパネルテスト1 M5Touch.hから使えそうな関数を試してみた。

M5Core2ライブラリーのクラスメソッドで、タッチパネルの基礎を学習します。

0.M5Touch::M5Touch() クラスインスタンス生成

M5Core2.cpp内でM5Core2クラスインスタンス宣言。このとき、M5touchクラスインスタンスも生成される。M5Core2()コンストラクタはisInitedをfalseにしている。

M5Core2::M5Core2() : isInited(0) {}

1. Touch.begin();

M5.begin()の中で実行される。ispressedメソッドは、IOピンを読んでいるだけのようだ。

void M5Touch::begin() {
  Wire1.begin(21, 22);
  pinMode(CST_INT, INPUT);

  // By default, the FT6336 will pulse the INT line for every touch
  // event. But because it shares the Wire1 TwoWire/I2C with other
  // devices, we cannot easily create an interrupt service routine to
  // handle these events. So instead, we set the INT wire to polled mode,
  // so it simply goes low as long as there is at least one valid touch.
  ft6336(0xA4, 0x00);

  Serial.print("touch: ");
  if (interval(DEFAULT_INTERVAL) == DEFAULT_INTERVAL) {
    Serial.printf("FT6336 ready (fw id 0x%02X rel %d, lib 0x%02X%02X)\n",
                  ft6336(0xA6), ft6336(0xAF), ft6336(0xA1), ft6336(0xA2));
  } else {
    Serial.println("ERROR - FT6336 not responding");
  }
}

2.M5.Touch.ispressed();

タッチパネルに触っていると、trueを返す。

bool M5Touch::ispressed() { return (digitalRead(CST_INT) == LOW); }

3.M5.Touch.getPressPoint();

振れているタッチパネルの座標を返す。

Point M5Touch::getPressPoint() {
  read();
  if (point[0]) return point[0];
  return Point(-1, -1);  // -1, -1 is old API's definition of invalid
}

Pointクラスは、変換関数を使用して、Pointクラスインスタンスをbool値にキャストしている。if(point[0]]) という書き方は、C言語にはない、C++のオーバーライド機能。

Point::operator bool() { return !(x == INVALID_VALUE && y == INVALID_VALUE); }

3.1 bool M5Touch::read()

getPressPoint()の中で呼ばれる関数。ft6336からデータを読み出し。
・触れているポイント数:uint8_t pts (2つが最大)
・触れている座標 :Pointp[2]
・直前の座標と今回の座標が違う:Touchクラスメンバchanged=true;
・finger ID: p0f (0 or1) 

// This is normally called from update()
bool M5Touch::read() {
  // true if real read, not a "come back later"
  wasRead = false;

  // true is something actually changed on the touchpad
  changed = false;

  // Return immediately if read() is called more frequently than the
  // touch sensor updates. This prevents unnecessary I2C reads, and the
  // data can also get corrupted if reads are too close together.
  if (millis() - _lastRead < _interval) return false;
  _lastRead = millis();

  Point p[2];
  uint8_t pts = 0;
  uint8_t p0f = 0;
  if (ispressed()) {
    uint8_t data[11];
    ft6336(0x02, 11, data);
    pts = data[0];
    if (pts > 2) return false;
    if (pts) {
      // Read the data. Never mind trying to read the "weight" and
      // "size" properties or using the built-in gestures: they
      // are always set to zero.
      p0f = (data[3] >> 4) ? 1 : 0;
      p[0].x = ((data[1] << 8) | data[2]) & 0x0fff;
      p[0].y = ((data[3] << 8) | data[4]) & 0x0fff;
      if (p[0].x >= TOUCH_W || p[0].y >= TOUCH_H) return false;
      if (pts == 2) {
        p[1].x = ((data[7] << 8) | data[8]) & 0x0fff;
        p[1].y = ((data[9] << 8) | data[10]) & 0x0fff;
        if (p[1].x >= TOUCH_W || p[1].y >= TOUCH_H) return false;
      }
    }
  }

#ifdef TFT
  p[0].rotate(TFT->rotation);
  p[1].rotate(TFT->rotation);
#endif /* TFT */

  if (p[0] != point[0] || p[1] != point[1]) {
    changed = true;
    point[0] = p[0];
    point[1] = p[1];
    points = pts;
    point0finger = p0f;
  }
  wasRead = true;
  return true;
}

p[2]とptsのローカル変数は、M5Touchクラスメンバのpoint[2]とpointsに格納されて関数を終了する。point0fingerの使い方がよくわからない。

4.HotZoneクラス 領域の確認

// For compatibility with older M5Core2 code
class HotZone : public Zone {
 public:
  HotZone(int16_t x0_, int16_t y0_, int16_t x1_, int16_t y1_,
          void (*fun_)() = nullptr);
  void setZone(int16_t x0_, int16_t y0_, int16_t x1_, int16_t y1_,
               void (*fun_)() = nullptr);
  bool inHotZone(Point& p);
  bool inHotZoneDoFun(Point& p);
  void (*fun)();
};

Zoneクラスをpublic継承。Zoneクラスのpublicメンバも扱える。
HotZoneコンストラクタ引数に注意。(x0,y0)は指定領域矩形のTopLeft、(x1,y1)はBottomRight。やっていることは、Zoneクラスコンストラクタに、描画原点(x0,y0)とwideとheightを計算して引数を渡している。

HotZone::HotZone(int16_t x0_, int16_t y0_, int16_t x1_, int16_t y1_,
                 void (*fun_)() /* = nullptr */
                 )
    : Zone(x0_, y0_, x1_ - x0_, y1_ - y0_) {
  fun = fun_;
}

4.1 HotZoneクラス inHotZone(Point &p)

コンストラクタで指定した領域内で、タッチされたかどうかを返す。

bool HotZone::inHotZone(Point& p) { return contains(p); }
bool Zone::contains(const Point& p) { return contains(p.x, p.y); }
bool Zone::contains(int16_t x_, int16_t y_) {
#ifdef TFT
  if (rot1 && TFT->rotation != 1) {
    Zone t = *this;
    t.rotate(TFT->rotation);
    return (y_ >= t.y && y_ <= t.y + t.h && x_ >= t.x && x_ <= t.x + t.w);
  }
#endif /* TFT */

  return (y_ >= y && y_ <= y + h && x_ >= x && x_ <= x + w);
}

Zoneクラスのcontain関数で判定している。

5.ソースコード

#include <M5Core2.h>

#define LCDWIDE 320
#define LCDHEIGHT 240

bool flag[5];

void btn1Callback();
void btn2Callback();
void btn3Callback();
void btn4Callback();

//Create Hotzone
HotZone Btn1(0, 20, 100, 120, &btn1Callback);
HotZone Btn2(LCDWIDE-100,20,LCDWIDE,120,&btn2Callback);
HotZone Btn3(0, LCDHEIGHT-100, 100, LCDHEIGHT, &btn3Callback);
HotZone Btn4(LCDWIDE-100,LCDHEIGHT-100,LCDWIDE,LCDHEIGHT,&btn4Callback);

//HotZone Btn1 Callback function
void btn1Callback(void)
{
    M5.Lcd.fillRect(Btn1.x,Btn1.y,Btn1.w,Btn1.h,BLACK);
    if(flag[1])
    {
        flag[1]=false;
        M5.Lcd.fillRect(Btn1.x,Btn1.y,Btn1.w,Btn1.h,DARKGREEN);
    }  
    else
    {
        flag[1]=true;
        M5.Lcd.drawRect(Btn1.x,Btn1.y,Btn1.w,Btn1.h,DARKGREEN);
    }   
}
//HotZone Btn2 Callback function
void btn2Callback(void)
{
    M5.Lcd.fillRect(Btn2.x,Btn2.y,Btn2.w,Btn2.h,BLACK);
    if(flag[2])
    {
        flag[2]=false;
        M5.Lcd.fillRect(Btn2.x,Btn2.y,Btn2.w,Btn2.h,BLUE);
    }  
    else
    {
        flag[2]=true;
        M5.Lcd.drawRect(Btn2.x,Btn2.y,Btn2.w,Btn2.h,BLUE);
    }   
}
//HotZone Btn3 Callback function
void btn3Callback(void)
{
    M5.Lcd.fillRect(Btn3.x,Btn3.y,Btn3.w,Btn3.h,BLACK);
    if(flag[3])
    {
        flag[3]=false;
        M5.Lcd.fillRect(Btn3.x,Btn3.y,Btn3.w,Btn3.h,RED);
    }  
    else
    {
        flag[3]=true;
        M5.Lcd.drawRect(Btn3.x,Btn3.y,Btn3.w,Btn3.h,RED);
    }   
}
//HotZone Btn4 Callback function
void btn4Callback(void)
{
    M5.Lcd.fillRect(Btn4.x,Btn4.y,Btn4.w,Btn4.h,BLACK);
    if(flag[4])
    {
        flag[4]=false;
        M5.Lcd.fillRect(Btn4.x,Btn4.y,Btn4.w,Btn4.h,YELLOW);
    }  
    else
    {
        flag[4]=true;
        M5.Lcd.drawRect(Btn4.x,Btn4.y,Btn4.w,Btn4.h,YELLOW);
    }   
}


void setup()
{
    M5.begin();
    M5.Lcd.setTextSize(2);
    M5.Lcd.setTextColor(RED);
    M5.Lcd.setBrightness(100);
    M5.Lcd.println("Core2 Touch Display");  
    M5.Lcd.drawRect(Btn1.x,Btn1.y,Btn1.w,Btn1.h,DARKGREEN);
    M5.Lcd.drawRect(Btn2.x,Btn2.y,Btn2.w,Btn2.h,BLUE);
    M5.Lcd.drawRect(Btn3.x,Btn3.y,Btn3.w,Btn3.h,RED);
    M5.Lcd.drawRect(Btn4.x,Btn4.y,Btn4.w,Btn4.h,YELLOW);
    flag[1]=flag[2]=flag[3]=flag[4]=true;
}


void loop() 
{ 
    static TouchPoint_t coordinate;
   
    if(M5.Touch.ispressed())
    {
        coordinate = M5.Touch.getPressPoint();//read();
        //Serial.printf("(%d,%d) pre(%d,%d) \r\n", coordinate.x, coordinate.y, prePt.x, prePt.y);
        Btn1.inHotZoneDoFun(coordinate);
        Btn2.inHotZoneDoFun(coordinate);
        Btn3.inHotZoneDoFun(coordinate);
        Btn4.inHotZoneDoFun(coordinate);
        if(M5.Touch.changed)
        {
            for(int i=0; i<M5.Touch.points; i++)
            {
                Serial.printf("Point[%d]:(%d,%d)",i,M5.Touch.point[i].x, M5.Touch.point[i].y);
            }
            Serial.println("");
        }

        delay(300);
    }


    delay(1);
}



この記事が気に入ったらサポートをしてみませんか?