今回はKeypad_240x320です。場所はファイルー>スケッチ例ー>TFT_eSPIー>320×240ー>Keypad_240x320にあります。このデモは、タッチセンサーとGUIのボタンの説明が主です。

タッチセンサにはキャリブレーションが必要
タッチセンサを使う前にキャリブレーションを行います。キャリブレーションしないとタッチセンサが正しく動作しない事が有ります。キャリブレーションは、関数touch_calibrate()で行います。この関数を実行する画面の端に矢印が表示されこの矢印に触りながらキャリブレーションを行います。

関数touch_calibrate()はプログラムの下の方に有ります。
Keypad_240x320.ino
void touch_calibrate()
{
uint16_t calData[5];
uint8_t calDataOK = 0;
// check file system exists
if (!SPIFFS.begin()) {
Serial.println("formatting file system");
SPIFFS.format();
SPIFFS.begin();
}
// check if calibration file exists and size is correct
if (SPIFFS.exists(CALIBRATION_FILE)) {
if (REPEAT_CAL)
{
// Delete if we want to re-calibrate
SPIFFS.remove(CALIBRATION_FILE);
}
else
{
File f = SPIFFS.open(CALIBRATION_FILE, "r");
if (f) {
if (f.readBytes((char *)calData, 14) == 14)
calDataOK = 1;
f.close();
}
}
}
if (calDataOK && !REPEAT_CAL) {
// calibration data valid
tft.setTouch(calData);
} else {
// data not valid so recalibrate
tft.fillScreen(TFT_BLACK);
tft.setCursor(20, 0);
tft.setTextFont(2);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.println("Touch corners as indicated");
tft.setTextFont(1);
tft.println();
if (REPEAT_CAL) {
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.println("Set REPEAT_CAL to false to stop this running again!");
}
tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.println("Calibration complete!");
// store data
File f = SPIFFS.open(CALIBRATION_FILE, "w");
if (f) {
f.write((const unsigned char *)calData, 14);
f.close();
}
}
}
- “/TouchCalData1″というファイルがFLASHに有るか無いかでキャリブレーション済みかどうか判断。
- “/TouchCalData1″ファイルが
- 有る: キャリブレーション実行済み。保存されたデータを読み込む。
- 無い: キャリブレーション(上記)を実行。実行後、データを保存。
キャリブレーションデータ用にuint16_t calData[5]; と符号なし16ビットの変数5個宣言しているのですが、データの読み込み(228行)、書き込み(264行)で14個の符号なし8ビットのデータを読み書きしています。 16ビット5個は8ビット10個ですから4バイト数が合いません。
ソースを見ると、引数として渡されたuint16_t のポインタに5個のデータを代入しています。何で4バイト多く読み書きしているのか分かりません。書きはともかく、読みは宣言した配列の外部にデータを読み込んでいるので問題になる思のですが、動いているので良しとしています。
関数と色一覧
キャリブレーションが終わると、図形描写用の関数が続きます。
tft.fillRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_BLACK);
tft.drawRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_WHITE);
TFT_eSPIで定義されている関数の一覧は/Arduino/libraries/TFT_eSPI/TFT_eSPI.hに有ります。下記はその一部です。このリストを元に大半の関数のおおよその機能を予測出来ます。tft.fillRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_BLACK);は塗り潰しの長方形。tft.drawRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_WHITE);は枠のみの長方形を描写します
TFT_eSPI.h
// These are virtual so the TFT_eSprite class can override them with sprite specific functions
virtual void drawPixel(int32_t x, int32_t y, uint32_t color),
drawChar(int32_t x, int32_t y, uint16_t c, uint32_t color, uint32_t bg, uint8_t size),
drawLine(int32_t xs, int32_t ys, int32_t xe, int32_t ye, uint32_t color),
drawFastVLine(int32_t x, int32_t y, int32_t h, uint32_t color),
drawFastHLine(int32_t x, int32_t y, int32_t w, uint32_t color),
fillRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color);
virtual int16_t drawChar(uint16_t uniCode, int32_t x, int32_t y, uint8_t font),
drawChar(uint16_t uniCode, int32_t x, int32_t y),
height(void),
width(void);
// Read the colour of a pixel at x,y and return value in 565 format
virtual uint16_t readPixel(int32_t x, int32_t y);
virtual void setWindow(int32_t xs, int32_t ys, int32_t xe, int32_t ye); // Note: start + end coordinates
// Push (aka write pixel) colours to the set window
virtual void pushColor(uint16_t color);
// These are non-inlined to enable override
virtual void begin_nin_write();
virtual void end_nin_write();
void setRotation(uint8_t r); // Set the display image orientation to 0, 1, 2 or 3
uint8_t getRotation(void); // Read the current rotation
// Change the origin position from the default top left
// Note: setRotation, setViewport and resetViewport will revert origin to top left corner of screen/sprite
void setOrigin(int32_t x, int32_t y);
int32_t getOriginX(void);
int32_t getOriginY(void);
void invertDisplay(bool i); // Tell TFT to invert all displayed colours
// The TFT_eSprite class inherits the following functions (not all are useful to Sprite class
void setAddrWindow(int32_t xs, int32_t ys, int32_t w, int32_t h); // Note: start coordinates + width and height
// Viewport commands, see "Viewport_Demo" sketch
void setViewport(int32_t x, int32_t y, int32_t w, int32_t h, bool vpDatum = true);
bool checkViewport(int32_t x, int32_t y, int32_t w, int32_t h);
int32_t getViewportX(void);
int32_t getViewportY(void);
int32_t getViewportWidth(void);
int32_t getViewportHeight(void);
bool getViewportDatum(void);
void frameViewport(uint16_t color, int32_t w);
void resetViewport(void);
// Clip input window to viewport bounds, return false if whole area is out of bounds
bool clipAddrWindow(int32_t* x, int32_t* y, int32_t* w, int32_t* h);
// Clip input window area to viewport bounds, return false if whole area is out of bounds
bool clipWindow(int32_t* xs, int32_t* ys, int32_t* xe, int32_t* ye);
// Push (aka write pixel) colours to the TFT (use setAddrWindow() first)
void pushColor(uint16_t color, uint32_t len), // Deprecated, use pushBlock()
pushColors(uint16_t *data, uint32_t len, bool swap = true), // With byte swap option
pushColors(uint8_t *data, uint32_t len); // Deprecated, use pushPixels()
// Write a solid block of a single colour
void pushBlock(uint16_t color, uint32_t len);
// Write a set of pixels stored in memory, use setSwapBytes(true/false) function to correct endianess
void pushPixels(const void * data_in, uint32_t len);
// Support for half duplex (bi-directional SDA) SPI bus where MOSI must be switched to input
#ifdef TFT_SDA_READ
#if defined (TFT_eSPI_ENABLE_8_BIT_READ)
uint8_t tft_Read_8(void); // Read 8-bit value from TFT command register
#endif
void begin_SDA_Read(void); // Begin a read on a half duplex (bi-directional SDA) SPI bus - sets MOSI to input
void end_SDA_Read(void); // Restore MOSI to output
#endif
// Graphics drawing
void fillScreen(uint32_t color),
drawRect(int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color),
drawRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color),
fillRoundRect(int32_t x, int32_t y, int32_t w, int32_t h, int32_t radius, uint32_t color);
void fillRectVGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2);
void fillRectHGradient(int16_t x, int16_t y, int16_t w, int16_t h, uint32_t color1, uint32_t color2);
void drawCircle(int32_t x, int32_t y, int32_t r, uint32_t color),
drawCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, uint32_t color),
fillCircle(int32_t x, int32_t y, int32_t r, uint32_t color),
fillCircleHelper(int32_t x, int32_t y, int32_t r, uint8_t cornername, int32_t delta, uint32_t color),
drawEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color),
fillEllipse(int16_t x, int16_t y, int32_t rx, int32_t ry, uint16_t color),
// Corner 1 Corner 2 Corner 3
drawTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color),
fillTriangle(int32_t x1,int32_t y1, int32_t x2,int32_t y2, int32_t x3,int32_t y3, uint32_t color);
実は、予め登録されている24色もTFT_eSPI.hに有ります。
TFT_eSPI.h
/***************************************************************************************
** Section 6: Colour enumeration
***************************************************************************************/
// Default color definitions
#define TFT_BLACK 0x0000 /* 0, 0, 0 */
#define TFT_NAVY 0x000F /* 0, 0, 128 */
#define TFT_DARKGREEN 0x03E0 /* 0, 128, 0 */
#define TFT_DARKCYAN 0x03EF /* 0, 128, 128 */
#define TFT_MAROON 0x7800 /* 128, 0, 0 */
#define TFT_PURPLE 0x780F /* 128, 0, 128 */
#define TFT_OLIVE 0x7BE0 /* 128, 128, 0 */
#define TFT_LIGHTGREY 0xD69A /* 211, 211, 211 */
#define TFT_DARKGREY 0x7BEF /* 128, 128, 128 */
#define TFT_BLUE 0x001F /* 0, 0, 255 */
#define TFT_GREEN 0x07E0 /* 0, 255, 0 */
#define TFT_CYAN 0x07FF /* 0, 255, 255 */
#define TFT_RED 0xF800 /* 255, 0, 0 */
#define TFT_MAGENTA 0xF81F /* 255, 0, 255 */
#define TFT_YELLOW 0xFFE0 /* 255, 255, 0 */
#define TFT_WHITE 0xFFFF /* 255, 255, 255 */
#define TFT_ORANGE 0xFDA0 /* 255, 180, 0 */
#define TFT_GREENYELLOW 0xB7E0 /* 180, 255, 0 */
#define TFT_PINK 0xFE19 /* 255, 192, 203 */ //Lighter pink, was 0xFC9F
#define TFT_BROWN 0x9A60 /* 150, 75, 0 */
#define TFT_GOLD 0xFEA0 /* 255, 215, 0 */
#define TFT_SILVER 0xC618 /* 192, 192, 192 */
#define TFT_SKYBLUE 0x867D /* 135, 206, 235 */
#define TFT_VIOLET 0x915C /* 180, 46, 226 */
GUIボタン
ここで使用されているボタンは、TFT_eSPI_Buttonクラスのボタンです。本体は/Arduino/libraries/TFT_eSPI/Extensions/Button.cppです。主な関数は、
ボタンのパラメータを設定する関数
void TFT_eSPI_Button::initButtonUL(TFT_eSPI *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h,
uint16_t outline, uint16_t fill, uint16_t textcolor,char *label, uint8_t textsize)
この関数はボタンのパラメータを設定するのみで描画はしません。各引数とボタンパラメータの関係は以下の通り

デモコードではinitButton()関数が使われています。この関数はX,Yがボタンの中心になるように調整したものです。
実際にボタンを描写する関数は void TFT_eSPI_Button::drawButton(bool inverted, String long_name)。 この関数の使い方は以下の通り。

bool invertedの値によってボタンの内側と文字の色が逆転します。Inverted が falseの時、これがボタンオフの状態で初期設定の色となります。)Inverted が trueの時、これがボタンオンの状態で文字と内側の色が入れ替わります(ボタンが押された感じになる)。2番めの引数 String long_name ですが、ボタンに表示される文字列です。この引数が定義されていればそれ自体を、されてなければ初期設定で指定した文字列がボタンに表示されます。
bool TFT_eSPI_Button::contains(int16_t x, int16_t y) この関数は指定した引数(x,y)がボタンの領域内か外か判断します。内側ならtrue、外側ならfalseを返します。
ボタンの動作は下記の4つの関数で管理されます。
void TFT_eSPI_Button::press(bool p) {
laststate = currstate;
currstate = p;
}
bool TFT_eSPI_Button::isPressed() { return currstate; }
bool TFT_eSPI_Button::justPressed() { return (currstate && !laststate); }
bool TFT_eSPI_Button::justReleased() { return (!currstate && laststate); }
各ボタンは laststate、 currstate という2つの変数を持っていて初期は各々Falseに設定されています。
- 0: 初期状態。isPressed() justPressed() justReleased() は全て False。
- 1: スキャンした時にボタンが押されていた場合
- press(true)を実行する。 laststate: false currstate: true に変わる。
- isPressed()とjustPressed()がtrueになる。ー> このボタンが今押されたものと判断出来る。
- 2: そのまま押し続けた状態でスキャンした場合
- press(true)を実行する。 laststate: true currstate: true に変わる。
- isPressed()のみがtrueになる。ー> このボタンは押され続けている事が分かる。
- 3: その後スキャンした時にボタンが離れていれば
- press(false)を実行する。 laststate: true currstate: false に変わる。
- justReleased()のみがtrueになる。ー> このボタンが離された事が分かる。
- 4: その後スキャンした時にボタンが離れていれば
- press(false)を実行する。 laststate: false currstate: false に変わる。
- 全てがfalseになる。ー> 押されているボタンは無し。(1に戻る。)

この様に2つの変数 laststate と currstate の組み合わせによりボタンの状態を判断します。後はボタンの状態に従って必要な処理を行っています。
コードに戻って
Keypad_240x320.ino
/*
The TFT_eSPI library incorporates an Adafruit_GFX compatible
button handling class, this sketch is based on the Arduin-o-phone
example.
This example displays a keypad where numbers can be entered and
sent to the Serial Monitor window.
The sketch has been tested on the ESP8266 (which supports SPIFFS)
The minimum screen size is 320 x 240 as that is the keypad size.
*/
// The SPIFFS (FLASH filing system) is used to hold touch screen
// calibration data
#include "FS.h"
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
// This is the file name used to store the calibration data
// You can change this to create new calibration files.
// The SPIFFS file name must start with "/".
#define CALIBRATION_FILE "/TouchCalData1"
// Set REPEAT_CAL to true instead of false to run calibration
// again, otherwise it will only be done once.
// Repeat calibration if you change the screen rotation.
#define REPEAT_CAL false
// Keypad start position, key sizes and spacing
#define KEY_X 40 // Centre of key
#define KEY_Y 96
#define KEY_W 62 // Width and height
#define KEY_H 30
#define KEY_SPACING_X 18 // X and Y gap
#define KEY_SPACING_Y 20
#define KEY_TEXTSIZE 1 // Font size multiplier
// Using two fonts since numbers are nice when bold
#define LABEL1_FONT &FreeSansOblique12pt7b // Key label font 1
#define LABEL2_FONT &FreeSansBold12pt7b // Key label font 2
// Numeric display box size and location
#define DISP_X 1
#define DISP_Y 10
#define DISP_W 238
#define DISP_H 50
#define DISP_TSIZE 3
#define DISP_TCOLOR TFT_CYAN
// Number length, buffer for storing it and character index
#define NUM_LEN 12
char numberBuffer[NUM_LEN + 1] = "";
uint8_t numberIndex = 0;
// We have a status line for messages
#define STATUS_X 120 // Centred on this
#define STATUS_Y 65
// Create 15 keys for the keypad
char keyLabel[15][5] = {"New", "Del", "Send", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "0", "#" };
uint16_t keyColor[15] = {TFT_RED, TFT_DARKGREY, TFT_DARKGREEN,
TFT_BLUE, TFT_BLUE, TFT_BLUE,
TFT_BLUE, TFT_BLUE, TFT_BLUE,
TFT_BLUE, TFT_BLUE, TFT_BLUE,
TFT_BLUE, TFT_BLUE, TFT_BLUE
};
// Invoke the TFT_eSPI button class and create all the button objects
TFT_eSPI_Button key[15];
//------------------------------------------------------------------------------------------
void setup() {
// Use serial port
Serial.begin(9600);
// Initialise the TFT screen
tft.init();
// Set the rotation before we calibrate
tft.setRotation(0);
// Calibrate the touch screen and retrieve the scaling factors
touch_calibrate();
// Clear the screen
tft.fillScreen(TFT_BLACK);
// Draw keypad background
tft.fillRect(0, 0, 240, 320, TFT_DARKGREY);
// Draw number display area and frame
tft.fillRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_BLACK);
tft.drawRect(DISP_X, DISP_Y, DISP_W, DISP_H, TFT_WHITE);
// Draw keypad
drawKeypad();
}
//------------------------------------------------------------------------------------------
void loop(void) {
uint16_t t_x = 0, t_y = 0; // To store the touch coordinates
// Pressed will be set true is there is a valid touch on the screen
bool pressed = tft.getTouch(&t_x, &t_y);
// / Check if any key coordinate boxes contain the touch coordinates
for (uint8_t b = 0; b < 15; b++) {
if (pressed && key[b].contains(t_x, t_y)) {
key[b].press(true); // tell the button it is pressed
} else {
key[b].press(false); // tell the button it is NOT pressed
}
}
// Check if any key has changed state
for (uint8_t b = 0; b < 15; b++) {
if (b < 3) tft.setFreeFont(LABEL1_FONT);
else tft.setFreeFont(LABEL2_FONT);
if (key[b].justReleased()) key[b].drawButton(); // draw normal
if (key[b].justPressed()) {
key[b].drawButton(true); // draw invert
// if a numberpad button, append the relevant # to the numberBuffer
if (b >= 3) {
if (numberIndex < NUM_LEN) {
numberBuffer[numberIndex] = keyLabel[b][0];
numberIndex++;
numberBuffer[numberIndex] = 0; // zero terminate
}
status(""); // Clear the old status
}
// Del button, so delete last char
if (b == 1) {
numberBuffer[numberIndex] = 0;
if (numberIndex > 0) {
numberIndex--;
numberBuffer[numberIndex] = 0;//' ';
}
status(""); // Clear the old status
}
if (b == 2) {
status("Sent value to serial port");
Serial.println(numberBuffer);
}
// we dont really check that the text field makes sense
// just try to call
if (b == 0) {
status("Value cleared");
numberIndex = 0; // Reset index to 0
numberBuffer[numberIndex] = 0; // Place null in buffer
}
// Update the number display field
tft.setTextDatum(TL_DATUM); // Use top left corner as text coord datum
tft.setFreeFont(&FreeSans18pt7b); // Choose a nice font that fits box
tft.setTextColor(DISP_TCOLOR); // Set the font colour
// Draw the string, the value returned is the width in pixels
int xwidth = tft.drawString(numberBuffer, DISP_X + 4, DISP_Y + 12);
// Now cover up the rest of the line up by drawing a black rectangle. No flicker this way
// but it will not work with italic or oblique fonts due to character overlap.
tft.fillRect(DISP_X + 4 + xwidth, DISP_Y + 1, DISP_W - xwidth - 5, DISP_H - 2, TFT_BLACK);
delay(10); // UI debouncing
}
}
}
//------------------------------------------------------------------------------------------
void drawKeypad()
{
// Draw the keys
for (uint8_t row = 0; row < 5; row++) {
for (uint8_t col = 0; col < 3; col++) {
uint8_t b = col + row * 3;
if (b < 3) tft.setFreeFont(LABEL1_FONT);
else tft.setFreeFont(LABEL2_FONT);
key[b].initButton(&tft, KEY_X + col * (KEY_W + KEY_SPACING_X),
KEY_Y + row * (KEY_H + KEY_SPACING_Y), // x, y, w, h, outline, fill, text
KEY_W, KEY_H, TFT_WHITE, keyColor[b], TFT_WHITE,
keyLabel[b], KEY_TEXTSIZE);
key[b].drawButton();
}
}
}
//------------------------------------------------------------------------------------------
void touch_calibrate()
{
uint16_t calData[5];
uint8_t calDataOK = 0;
// check file system exists
if (!SPIFFS.begin()) {
Serial.println("formatting file system");
SPIFFS.format();
SPIFFS.begin();
}
// check if calibration file exists and size is correct
if (SPIFFS.exists(CALIBRATION_FILE)) {
if (REPEAT_CAL)
{
// Delete if we want to re-calibrate
SPIFFS.remove(CALIBRATION_FILE);
}
else
{
File f = SPIFFS.open(CALIBRATION_FILE, "r");
if (f) {
if (f.readBytes((char *)calData, 14) == 14)
calDataOK = 1;
f.close();
}
}
}
if (calDataOK && !REPEAT_CAL) {
// calibration data valid
tft.setTouch(calData);
} else {
// data not valid so recalibrate
tft.fillScreen(TFT_BLACK);
tft.setCursor(20, 0);
tft.setTextFont(2);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.println("Touch corners as indicated");
tft.setTextFont(1);
tft.println();
if (REPEAT_CAL) {
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.println("Set REPEAT_CAL to false to stop this running again!");
}
tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.println("Calibration complete!");
// store data
File f = SPIFFS.open(CALIBRATION_FILE, "w");
if (f) {
f.write((const unsigned char *)calData, 14);
f.close();
}
}
}
//------------------------------------------------------------------------------------------
// Print something in the mini status bar
void status(const char *msg) {
tft.setTextPadding(240);
//tft.setCursor(STATUS_X, STATUS_Y);
tft.setTextColor(TFT_WHITE, TFT_DARKGREY);
tft.setTextFont(0);
tft.setTextDatum(TC_DATUM);
tft.setTextSize(1);
tft.drawString(msg, STATUS_X, STATUS_Y);
}
//------------------------------------------------------------------------------------------
- 184行
void drawKeypad()
でキーパッドが作成されています。- 194行 key[b].initButton()でボタンパラメータの初期化
- 198行 key[b].drawButton();でボタンを描画(引数無しの場合 False)
- 本体は107行からの
void loop(void) {
- 111行 bool pressed = tft.getTouch(&t_x, &t_y);
- この関数が実行された時点でのLCDへのタッチ状態をチェックします。
- タッチが有れば t_x, t_yにタッチのX,Y座標を代入し true を返します。
- タッチが無ければ、 false が返って来ます。
- 114から120行 ここで各ボタンの状態をセットしています。
- タッチした座標がボタンの
- 領域内:key[b].press(true);を実行
- 領域外:
key[b].press(false);
を実行
- 123から179行 ここでボタンの状態に合わせて処理を行っています。
- 134行 numberpad buttonの処理
- 144行 Del buttonの処理
- 153行 Sent buttonの処理
- 159行 New buttonの処理
- タッチした座標がボタンの
- 166から177行 表示部の更新を行った後Loopトップへ戻ります。
- 111行 bool pressed = tft.getTouch(&t_x, &t_y);
これだけの仕組みが、確かにボタンが押さえた感じが表現されています。
このPadをちょっと変更して
このPadをちょっと変更してColor Editorを作って見ました。

このプログラムの動作は以下の通り
- 上段のRGBボタンを選び、RGBの値を10進でセット
- 10進数のRGBデータを16進数変換し表示
- 最上段の枠が指定した色で塗り潰される
上部3個のRGBボタンは下の数字ボタンを違った動きをしますが使っているクラスは同じTFT_eSPI_Buttonクラスです。
color_pad.ino
#include "FS.h"
#include <SPI.h>
#include <TFT_eSPI.h> // Hardware-specific library
TFT_eSPI tft = TFT_eSPI(); // Invoke custom library
#define CALIBRATION_FILE "/TouchCalData1"
#define REPEAT_CAL false
#define LABEL2_FONT &FreeSansBold12pt7b // Key label font 2
// Numeric display box size and location
#define DISP_X 1
#define DISP_Y 10
#define DISP_W 238
#define DISP_H 50
// Keypad start position, key sizes and spacing
#define KEY_X 40 // Centre of key
#define KEY_Y 130
#define KEY_W 62 // Width and height
#define KEY_H 30
#define KEY_SPACING_X 18 // X and Y gap
#define KEY_SPACING_Y 10
#define KEY_TEXTSIZE 1 // Font size multiplier
// Create 15 keys for the keypad
uint8_t rgb_flg;
char rgb_data[3][5];
char keyLabel[15][5] = {"", "", "", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "no", "ok" };
uint16_t keyColor[15] = {TFT_BLACK, TFT_BLACK, TFT_BLACK,
TFT_BLUE, TFT_BLUE, TFT_BLUE,
TFT_BLUE, TFT_BLUE, TFT_BLUE,
TFT_BLUE, TFT_BLUE, TFT_BLUE,
TFT_BLUE, TFT_BLUE, TFT_BLUE
};
// Invoke the TFT_eSPI button class and create all the button objects
TFT_eSPI_Button key[15];
//------------------------------------------------------------------------------------------
void setup() {
// Use serial port
Serial.begin(115200);
// Initialise the TFT screen
tft.init();
tft.setRotation(0);
touch_calibrate();
// Draw keypad background
tft.fillScreen(TFT_BLACK);
tft.fillRect(0, 0, 240, 320, TFT_DARKGREY);
tft.setFreeFont(LABEL2_FONT);
}
//------------------------------------------------------------------------------------------
void loop(void) {
uint16_t t_x, t_y;
bool pressed, chk_ok;
uint8_t b, temp_data, c_len, st_rgb;
char prt_data[10];
for(b = 0; b < 3; b ++)
sprintf(rgb_data[b], "%d", 0);
temp_data = c_len = 0;
drawKeypad();
rgb_flg = 5;
make_color(prt_data);
chk_ok = true;
st_rgb = char_to_int(rgb_data[0]);
while(1){
pressed = tft.getTouch(&t_x, &t_y);
for (b = 0; b < 15; b++) {
if (pressed && key[b].contains(t_x, t_y))
key[b].press(true); // tell the button it is pressed
else
key[b].press(false); // tell the button it is NOT pressed
}
for(b = 0; b < 15; b ++){
if(key[b].justReleased() && (b > 2))
key[b].drawButton();
if(key[b].justPressed()) {
if(b < 3){
if(chk_ok){
rgb_flg = b;
temp_data = c_len = 0;
key[b].drawButton(true, "0");
chk_ok = false;
}
}
else{
key[b].drawButton(true);
if ((b < 13) && (rgb_flg < 3)) {
if (c_len < 2) {
if(c_len) temp_data *= 10;
temp_data += (b - 3);
sprintf(prt_data, "%d", temp_data);
key[rgb_flg].drawButton(true, prt_data);
c_len ++;
}
}
if(b == 13){ // no
key[rgb_flg].drawButton(false, rgb_data[rgb_flg]);
rgb_flg = 5;
chk_ok = true;
}
if(b == 14){ // OK
if(rgb_flg == 1){
if(temp_data > 62)
temp_data = 62;
}
else{
if(temp_data > 31)
temp_data = 31;
}
sprintf(rgb_data[rgb_flg], "%d", temp_data);
rgb_flg = 5;
make_color(prt_data);
Serial.print("Color Code: ");
Serial.println(prt_data);
chk_ok = true;
}
}
}
}
}
}
//------------------------------------------------------------------------------------------
void drawKeypad()
{
int c_data[3] = {TFT_RED, TFT_GREEN, TFT_BLUE};
int a, c;
char* rgb_txt;
// Draw the keys
tft.drawRect(80, 70, 80, 30, TFT_WHITE);
for (uint8_t row = 0; row < 5; row++) {
for (uint8_t col = 0; col < 3; col++) {
uint8_t b = col + row * 3;
if(b < 3){
a = c_data[b];
rgb_txt = rgb_data[b];
}
else{
a = TFT_WHITE;
rgb_txt = keyLabel[b];
}
key[b].initButton(&tft, KEY_X + col * (KEY_W + KEY_SPACING_X),
KEY_Y + row * (KEY_H + KEY_SPACING_Y), // x, y, w, h, outline, fill, text
KEY_W, KEY_H, a, keyColor[b], a,
rgb_txt, KEY_TEXTSIZE);
key[b].drawButton();
}
}
}
//------------------------------------------------------------------------------------------
uint8_t char_to_int(char* c_buf){
uint8_t a;
a = c_buf[0] - 0x30;
if(c_buf[1])
a = a * 10 + c_buf[1] - 0x30;
return(a);
}
void make_color(char* prt_data){
int a;
for(a = 0; a < 3; a++){
if(a == rgb_flg) key[a].drawButton(true, rgb_data[a]);
else key[a].drawButton(false, rgb_data[a]);
}
a = char_to_int(rgb_data[0]) << 11;
a |= (char_to_int(rgb_data[1]) << 5);
a |= char_to_int(rgb_data[2]);
sprintf(prt_data, "%04X", a);
tft.drawRect(80, 70, 80, 30, TFT_WHITE);
tft.fillRect(81, 71, 78, 28, TFT_BLACK);
tft.setTextDatum(TC_DATUM);
tft.setTextColor(TFT_WHITE,TFT_WHITE);
tft.drawString(prt_data, 120, 75);
tft.fillRect(DISP_X + 1, DISP_Y + 1, DISP_W - 2 , DISP_H - 2, a);
}
void touch_calibrate()
{
uint16_t calData[5];
uint8_t calDataOK = 0;
// check file system exists
if (!SPIFFS.begin()) {
Serial.println("formatting file system");
SPIFFS.format();
SPIFFS.begin();
}
// check if calibration file exists and size is correct
if (SPIFFS.exists(CALIBRATION_FILE)) {
if (REPEAT_CAL)
{
// Delete if we want to re-calibrate
SPIFFS.remove(CALIBRATION_FILE);
}
else
{
File f = SPIFFS.open(CALIBRATION_FILE, "r");
if (f) {
if (f.readBytes((char *)calData, 14) == 14)
calDataOK = 1;
f.close();
}
}
}
if (calDataOK && !REPEAT_CAL) {
// calibration data valid
tft.setTouch(calData);
} else {
// data not valid so recalibrate
tft.fillScreen(TFT_BLACK);
tft.setCursor(20, 0);
tft.setTextFont(2);
tft.setTextSize(1);
tft.setTextColor(TFT_WHITE, TFT_BLACK);
tft.println("Touch corners as indicated");
tft.setTextFont(1);
tft.println();
if (REPEAT_CAL) {
tft.setTextColor(TFT_RED, TFT_BLACK);
tft.println("Set REPEAT_CAL to false to stop this running again!");
}
tft.calibrateTouch(calData, TFT_MAGENTA, TFT_BLACK, 15);
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.println("Calibration complete!");
// store data
File f = SPIFFS.open(CALIBRATION_FILE, "w");
if (f) {
f.write((const unsigned char *)calData, 14);
f.close();
}
}
}
次回は
次回は画像の表示に付いて説明したいと思います。