이선학 - 2023년 11월 20일
EmbeddedAdafruit 2.8 TFT LCD Shield
Adafruit 2.8 TFT LCD Shield은 Arduino와 호환되는 편리한 디스플레이 모듈이다. 이 모듈은 2.8인치 크기의 컬러 TFT LCD 디스플레이를 제공하여 다양한 그래픽 사용자 인터페이스를 구현하는 데 사용할 수 있다.
주요 특징
- 화면 크기: 2.8인치
- 해상도: 320x240 픽셀
- 색상: 262,000 색상 지원
- 기능: 마이크로SD 카드 슬롯 내장
- Arduino 호환성: Arduino Uno 및 호환 보드에서 사용 가능
하드웨어 연결 방법
설치 및 사용
Arduino IDE에서 다음 라이브러리를 설치
- Adafruit GFX Library
- Adafruit ILI9341 Library
사용 예시
Arduino와 연결하여 기본적인 텍스트 표시 예시 코드
#include <Adafruit_GFX.h> // Adafruit graphics library
#include <Adafruit_ILI9341.h> // Adafruit ILI9341 display library
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
void setup() {
tft.begin();
tft.fillScreen(ILI9341_BLUE);
tft.setCursor(50, 50);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.println("Hello, Adafruit!");
}
void loop() {
// Your code here
}
간단한 그림판을 만드는 코드
#include <Adafruit_GFX.h> // Core graphics library
#include <SPI.h>
#include <Wire.h> // this is needed even tho we aren't using it
#include <Adafruit_ILI9341.h>
#include <Adafruit_STMPE610.h>
// This is calibration data for the raw touch data to the screen coordinates
#define TS_MINX 150
#define TS_MINY 130
#define TS_MAXX 3800
#define TS_MAXY 4000
// The STMPE610 uses hardware SPI on the shield, and #8
#define STMPE_CS 8
Adafruit_STMPE610 ts = Adafruit_STMPE610(STMPE_CS);
// The display also uses hardware SPI, plus #9 & #10
#define TFT_CS 10
#define TFT_DC 9
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
// Size of the color selection boxes and the paintbrush size
#define BOXSIZE 40
#define PENRADIUS 3
int oldcolor, currentcolor;
void setup(void) {
// while (!Serial); // used for leonardo debugging
Serial.begin(9600);
Serial.println(F("Touch Paint!"));
tft.begin();
if (!ts.begin()) {
Serial.println("Couldn't start touchscreen controller");
while (1);
}
Serial.println("Touchscreen started");
tft.fillScreen(ILI9341_BLACK);
// make the color selection boxes
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
// select the current color 'red'
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
currentcolor = ILI9341_RED;
}
void loop()
{
// See if there's any touch data for us
if (ts.bufferEmpty()) {
return;
}
/*
// You can also wait for a touch
if (! ts.touched()) {
return;
}
*/
// Retrieve a point
TS_Point p = ts.getPoint();
// Scale from ~0->4000 to tft.width using the calibration #'s
p.x = map(p.x, TS_MINX, TS_MAXX, 0, tft.width());
p.y = map(p.y, TS_MINY, TS_MAXY, 0, tft.height());
if (p.y < BOXSIZE) {
oldcolor = currentcolor;
if (p.x < BOXSIZE) {
currentcolor = ILI9341_RED;
tft.drawRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*2) {
currentcolor = ILI9341_YELLOW;
tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*3) {
currentcolor = ILI9341_GREEN;
tft.drawRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*4) {
currentcolor = ILI9341_CYAN;
tft.drawRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*5) {
currentcolor = ILI9341_BLUE;
tft.drawRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
} else if (p.x < BOXSIZE*6) {
currentcolor = ILI9341_MAGENTA;
tft.drawRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_WHITE);
}
if (oldcolor != currentcolor) {
if (oldcolor == ILI9341_RED)
tft.fillRect(0, 0, BOXSIZE, BOXSIZE, ILI9341_RED);
if (oldcolor == ILI9341_YELLOW)
tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, ILI9341_YELLOW);
if (oldcolor == ILI9341_GREEN)
tft.fillRect(BOXSIZE*2, 0, BOXSIZE, BOXSIZE, ILI9341_GREEN);
if (oldcolor == ILI9341_CYAN)
tft.fillRect(BOXSIZE*3, 0, BOXSIZE, BOXSIZE, ILI9341_CYAN);
if (oldcolor == ILI9341_BLUE)
tft.fillRect(BOXSIZE*4, 0, BOXSIZE, BOXSIZE, ILI9341_BLUE);
if (oldcolor == ILI9341_MAGENTA)
tft.fillRect(BOXSIZE*5, 0, BOXSIZE, BOXSIZE, ILI9341_MAGENTA);
}
}
if (((p.y-PENRADIUS) > BOXSIZE) && ((p.y+PENRADIUS) < tft.height())) {
tft.fillCircle(p.x, p.y, PENRADIUS, currentcolor);
}
}
sd 카드안에 있는 bmp를 읽어오는 코드
#include <Adafruit_GFX.h>
#include "Adafruit_ILI9341.h"
#include <SPI.h>
#include <SD.h>
#define TFT_DC 9
#define TFT_CS 10
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define SD_CS 4
void setup(void) {
Serial.begin(9600);
tft.begin();
tft.fillScreen(ILI9341_BLUE);
Serial.print("Initializing SD card...");
if (!SD.begin(SD_CS)) {
Serial.println("failed!");
}
Serial.println("OK!");
//bmpDraw("tree.bmp", 0, 0); //사진 한장만 볼때
}
void loop() {
bmpDraw("segu1.bmp", 0, 0);
delay(2000); //길면 사진 오래봄
bmpDraw("segu2.bmp", 0, 0);
delay(2000);
bmpDraw("segu3.bmp", 0, 0);
delay(2000);
}
#define BUFFPIXEL 20
void bmpDraw(char *filename, uint8_t x, uint16_t y) {
File bmpFile;
int bmpWidth, bmpHeight;
uint8_t bmpDepth;
uint32_t bmpImageoffset;
uint32_t rowSize;
uint8_t sdbuffer[3*BUFFPIXEL];
uint8_t buffidx = sizeof(sdbuffer);
boolean goodBmp = false;
boolean flip = true;
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if((x >= tft.width()) || (y >= tft.height())) return;
Serial.println();
Serial.print(F("Loading image '"));
Serial.print(filename);
Serial.println('\'');
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print(F("File not found"));
return;
}
if(read16(bmpFile) == 0x4D42) {
Serial.print(F("File size: ")); Serial.println(read32(bmpFile));
(void)read32(bmpFile);
bmpImageoffset = read32(bmpFile);
Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
Serial.print(F("Header size: ")); Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) {
bmpDepth = read16(bmpFile);
Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) {
goodBmp = true;
Serial.print(F("Image size: "));
Serial.print(bmpWidth);
Serial.print('x');
Serial.println(bmpHeight);
rowSize = (bmpWidth * 3 + 3) & ~3;
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;
tft.setAddrWindow(x, y, x+w-1, y+h-1);
for (row=0; row<h; row++) { // For each scanline...
if(flip)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if(bmpFile.position() != pos) {
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer);
}
for (col=0; col<w; col++) {
if (buffidx >= sizeof(sdbuffer)) {
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0;
}
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft.pushColor(tft.color565(r,g,b));
}
}
Serial.print(F("Loaded in "));
Serial.print(millis() - startTime);
Serial.println(" ms");
}
}
}
bmpFile.close();
if(!goodBmp) Serial.println(F("BMP format not recognized."));
}
uint16_t read16(File &f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read();
((uint8_t *)&result)[1] = f.read();
return result;
}
uint32_t read32(File &f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read();
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read();
return result;
}