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);
}
この記事が気に入ったらサポートをしてみませんか?