Arduinoでタッチスクリーンを使う・図形描画

Arduino
DSC_1816

タッチスクリーンでグラフィックを使う

このTFTタッチスクリーンでは、240×320ピクセル(または320×240ピクセル)・16ビットカラーのグラフィック描画を行うことができます。座標は文字列の時と同様、左上隅が(0,0)、右がx正方向、下がy正方向です。

グラフィックのサンプルプログラム

#include "Elegoo_GFX.h"
#include "Elegoo_TFTLCD.h"

// ピンの定義
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RST A4

// 色の定義
#define	BLACK   0x0000
#define	BLUE    0x001F
#define	RED     0xF800
#define	GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

// インスタンスの生成
Elegoo_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RST);

void setup() {
  // 初期化
  tft.reset();
  uint16_t identifier = tft.readID();
  if(identifier==0x0101){     
    identifier=0x9341;
  }else if(identifier==0x1111){     
    identifier=0x9328;
  }
  tft.begin(identifier);
}

void loop() {
  // 画面クリア
  tft.fillScreen(WHITE);
  tft.setRotation(3);
  tft.drawLine(0,0,319,239,RED);
  tft.drawLine(100,-20,-20,100,RED);
  tft.drawFastHLine(240,120,60,RED);
  tft.drawFastVLine(270,90,60,RED);
  tft.drawRect(16,12,80,60,BLUE);
  tft.fillRect(80,60,80,60,GREEN);
  tft.drawCircle(160,120,50,MAGENTA);
  tft.fillCircle(240,180,30,CYAN);
  tft.drawRoundRect(16,160,80,60,20,BLACK);
  tft.fillRoundRect(220,20,80,60,20,YELLOW);
  while(true);
}

プログラムの解説

各種宣言とsetup()関数内は文字列表示の時とまったく同じなので、loop()関数内のみ解説します。

画面の向きの設定
  tft.setRotation(3);

Elegoo_TFTLCD.setRotation()関数は画面の向きを設定しています。今回は文字描画の例の時とは違い、3を指定してUSB端子が左側(Arduino基板上のロゴが読める方向)になる向きで横長(横320×縦240ピクセル)の画面にしています。

線分の描画
  tft.drawLine(0,0,319,239,RED);
  tft.drawLine(100,-20,-20,100,RED);

Elegoo_TFTLCD.drawLine()関数は線分を描画します。

書式
void Elegoo_TFTLCD.drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
引数
名前意味
x0int16_t描画する線分の始点のx座標
y0int16_t描画する線分の始点のy座標
x1int16_t描画する線分の終点のx座標
y1int16_t描画する線分の終点のy座標
coloruint16_t描画する線分の色
補足

始点や終点が画面外の座標でも、画面内を通過する部分があれば正常に描画されます。

水平な線分の描画
  tft.drawFastHLine(240,120,60,RED);

Elegoo_TFTLCD.drawFastHLine()関数は、水平な直線を高速に描画します。

書式
void Elegoo_TFTLCD.drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
引数
名前意味
xint16_t描画する線分の始点(左端点)のx座標
yint16_t描画する線分の始点(左端点)のy座標
wint16_t描画する線分の幅(水平方向の長さ)
coloruint16_t描画する線分の色
補足

任意の角度の線分の描画には繰り返し多くの計算が必要で時間がかかりますが、水平な線分は単純な繰り返しで描画できます。drawFastHLine()関数は水平な線分を高速に描画可能です。

鉛直な線分の描画
  tft.drawFastVLine(270,90,60,RED);

Elegoo_TFTLCD.drawFastVLine()関数は、鉛直な直線を高速に描画します。

書式
void Elegoo_TFTLCD.drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
引数
名前意味
xint16_t描画する線分の始点(左端点)のx座標
yint16_t描画する線分の始点(左端点)のy座標
hint16_t描画する線分の高さ(鉛直方向の長さ)
coloruint16_t描画する線分の色
補足

任意の角度の線分の描画には繰り返し多くの計算が必要で時間がかかりますが、鉛直な線分は単純な繰り返しで描画できます。drawFastVLine()関数は鉛直な線分を高速に描画可能です。

矩形の描画
  tft.drawRect(16,12,80,60,BLUE);
  tft.fillRect(80,60,80,60,GREEN);

Elegoo_TFTLCD.drawRect()関数は、矩形を描画します。
Elegoo_TFTLCD.fillRect()関数は、中を塗りつぶした矩形を描画します。

書式
void Elegoo_TFTLCD.drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
void Elegoo_TFTLCD.fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
引数
名前意味
xint16_t描画する矩形左上角のx座標
yint16_t描画する矩形左上角のy座標
wint16_t描画する矩形の幅(水平方向の長さ)
hint16_t描画する矩形の高さ(鉛直方向の長さ)
coloruint16_t描画する矩形の色
補足

drawRect()関数は矩形の周のみ描画します。中の部分は先に描画された図形が残ります。

円の描画
  tft.drawCircle(160,120,50,MAGENTA);
  tft.fillCircle(240,180,30,CYAN);

Elegoo_TFTLCD.drawCircle()関数は、円を描画します。
Elegoo_TFTLCD.fillCircle()関数は、中を塗りつぶした円を描画します。

書式
void Elegoo_TFTLCD.drawCircle(int16_t x, int16_t y, int16_t r, uint16_t color)
void Elegoo_TFTLCD.fillCircle(int16_t x, int16_t y, int16_t r, uint16_t color)
引数
名前意味
xint16_t描画する円の中心のx座標
yint16_t描画する円の中心のy座標
rint16_t描画する円の半径
coloruint16_t描画する円の色
補足

drawCircle()関数は円の周のみ描画します。中の部分は先に描画された図形が残ります。

角の丸い矩形の描画
  tft.drawRoundRect(16,160,80,60,20,BLACK);
  tft.fillRoundRect(220,20,80,60,20,YELLOW);

Elegoo_TFTLCD.drawRoundRect()関数は、角が丸い矩形を描画します。
Elegoo_TFTLCD.fillRoundRect()関数は、中身を塗りつぶした角が丸い矩形を描画します。

書式
void Elegoo_TFTLCD.drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
void Elegoo_TFTLCD.fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color)
引数
名前意味
xint16_t描画する矩形の左上角のx座標
yint16_t描画する矩形の左上角のy座標
wint16_t描画する矩形の幅(水平方向の長さ)
hint16_t描画する矩形の高さ(鉛直方向の長さ)
rint16_t矩形の角の丸みの半径
coloruint16_t描画する
補足

drawRoundRect()関数は円の周のみ描画します。中の部分は先に描画された図形が残ります。

実行結果

このように各種図形を描画することができます。8bit時代後期のPCくらいの描画はできそうです。ただArduino R3の処理能力の限界か描画はかなり遅めです…まぁ8bit時代のPCも全画面にアニメ調の絵を表示しようとすると数秒待たされたものですが。

検証

drawFastHLine()はdrawLine()よりどれくらい速いのか

簡単なテストプログラムを作り、実行速度を比較しました。240本の水平な赤い線分を画面に敷き詰めて全画面を塗りつぶすプログラムです。

drawLine()関数を用いた場合と、水平線専門のdrawFastHLine()関数を用いた場合、それぞれ所要時間をμ秒単位で計測します。

drawLine()関数(水平線)の場合
  unsigned long start = micros();
  for(int i=0;i<240;i++){
    tft.drawLine(0,i,319,i,RED);
//    tft.drawFastHLine(0,i,320,RED);
  }
  unsigned long end = micros();
  Serial.println(end-start);

結果は9,848,840μ秒、約10秒でした。

drawFastHLine()関数の場合
  unsigned long start = micros();
  for(int i=0;i<240;i++){
//    tft.drawLine(0,i,319,i,RED);
    tft.drawFastHLine(0,i,320,RED);
  }
  unsigned long end = micros();
  Serial.println(end-start);

動画を見るだけでも明らかな違いがあります。計測結果は354,424μ秒、約0.35秒でした。drawFastHLine()関数の方がdrawLine()関数より27倍も速いことが判ります。

drawFastVLine()はdrawLine()よりどれくらい速いのか

同様に、鉛直線専用のdrawFastVLine()関数がdrawLine()関数よりどれくらい速いのか試してみます。

drawLine()関数(鉛直線)の場合
  unsigned long start = micros();
  for(int i=0;i<320;i++){
    tft.drawLine(i,0,i,239,RED);
//    tft.drawFastVLine(i,0,240,RED);
  }
  unsigned long end = micros();
  Serial.println(end-start);

結果は9,830,356μ秒、約10秒でした。ループ回数が1.3倍になっていますが実行時間はほとんど変わっていません。1ピクセル毎の描画(座標計算)にかかる時間の割合が大きいのだと思われます。

drawFastVLine()関数の場合
  unsigned long start = micros();
  for(int i=0;i<320;i++){
//    tft.drawLine(i,0,i,239,RED);
    tft.drawFastVLine(i,0,240,RED);
  }
  unsigned long end = micros();

結果は366,844μ秒、約0.37秒でした。こちらもdrawFastVLine()関数の方が約27倍速いという結果が出ました。

色指定

色はRGB光の三原色による指定で、プログラム内ではR(赤)が5bit+G(緑)が6bit+B(青)が5bitの16bitの数値で行います。ディスプレイで実際に色の表示が可能なのかを実験しました。

以下の簡単なプログラムで実験してみます。Rは31(5bitの最大値)、Bは0に固定で、Gを0~63(6bitの最大値)の間で変化させながら並べて表示していきます。上手くいけば赤~オレンジ~黄のグラデーションになるはずです。

  for(int i=0;i<64;i++){
    uint16_t color = 31<<11|i<<5;
    tft.fillRect(i*5,0,5,240,color);
  }

結果は以下のようになりました。

右端で突然黄色になっているように見えますが、そこまでは赤~オレンジのグラデーションになっています。一応16bitカラーと言っても良さそうです。

まとめ

  • 簡単な図形を描画する関数はひととおりある

コメント

タイトルとURLをコピーしました