[TH] How to used Arduino 2.4″ TFT LCD&Touch Shield with STM32F401?

จากบทความก่อนหน้านี้ที่ได้ใช้จอแสดงผลขนาด 3.5″ สำหรับบอร์ด Raspberry Pi มาใช้งานกับ ESP32 ไปแล้ว ทางทีมงานเรายังมี Arduino 2.4″ TFT LCD&Touch Shield ที่ใช้กับ Arduino Uno และ Arduino Mega (ดังภาพที่ 1) และต้องการใช้งานกับไมโครคอนโทรลเลอร์ STM32F401RET6 ด้วยบอร์ด NUCLEO-F401RE และ STM32F401CC (ภาพที่ 2) ซึ่งเป็น Cortex-M4 ที่มีหน่วยความจำ 96KB และ 64KB ตามลำดับ ส่วนหน่วยความจำ ROM นั้นเป็น 512KB และ 128KB พร้อมทั้งทำการเชื่อมต่อสวิตช์จำนวน 8 ตัวเข้ากับขาของไมโครคอนโทรลเลอร์ โดยในบทความนี้ใช้บอร์ด ET-TEST 10P/INP (ภาพที่ 3) เพื่อใช้แทนปุ่มซ้าย, บน, ล่าง,ขวา, m1,m2, A และ B ตามลำดับ

Nucleo-F401RE+Arduino Uno 2.4" TFT&Touch Shield
ภาพที่ 1 โมดูล Arduino Uno TFT&Touch Shield บนบอร์ด Nucleo-F401RE

Arduino 2.4″ TFT LCD Shield Touch Screen

STM32F401CC+Arduino Uno 2.4" TFT&Touch Shield
ภาพที่ 2 โมดูล Arduino Uno TFT&Touch Shield ผนวกเข้ากับบอร์ด Blackpill STM32F401CC
ET-TEST 10P/INP
ภาพที่ 3 ส่วนสวิตช์ ET-TEST 10P/INP

คุณสมบัติ

คุณสมบัติของโมดูลแสดงผลมีดังนี้

  • ความละเอียดในการแสดงผล 320×240 จุดสี
  • แสดงสีแบบ 16 บิต หรือ 65,535 สี
  • เชื่อมต่อแบบ 8 บิตโดยรับข้อมูลจากไมโครคอนโทรลเลอร์ผ่านขา D0-D1
  • มีบัสควบคุมสั่งงานจากไมโครคอนโทรลเลอร์จำนวน 5 ขา
    • RD ส่งสัญญาณอ่าน
    • WR ส่งสัญญาณเขียน
    • DC ส่งสัญญาณว่าเขียนคำสั่ง
    • RST ส่งสัญญาณรีเซ็ต
    • CS ส่งสัญญาณให้โมดูลรู้ว่าถูกเรียกให้ทำงานหรือไม่ได้ถูกเรียกใช้
  • ชิพขับโมดูลเป็น ili9341 (ภาพที่ 3) หรือ ili9481 (ภาพที่ 4)

ผังวงจร

ผังวงจรการเชื่อมต่อระหว่างขาของโมดูล LCD กับ STM32F401กับสวิตช์และลำโพง เป็นดังภาพที่ 5

dCore-F401 sch.
STM32F401cc+Arduino Uno 2.4" TFT&Touch Shield+ET-TEST 10INP
ภาพที่ 5 วงจรของบอร์ด dCore-F401 ที่ใช้จอแสดงผล Arduino Uno 2.4″ TFT&Touch Sheild

จากภาพที่ 5 มีการเชื่อมต่อกันดังนี้

  • TFT_CS ต่อกับ PB0
  • TFT_RST ต่อกับ PB12
  • TFT_RD ต่อกับ PA0
  • TFT_WR ต่อกับ PA1
  • TFT_DC ต่อกับ PA4
  • SPK ต่อกับ PA7
  • TFT_D0 ต่อเข้ากับ PA9
  • TFT_D1 ต่อเข้ากับ PB13
  • TFT_D2 ต่อเข้ากับ PA10
  • TFT_D3 ต่อเข้ากับ PB3
  • TFT_D4 ต่อเข้ากับ PB5
  • TFT_D5 ต่อเข้ากับ PB4
  • TFT_D6 ต่อเข้ากับ PB10
  • TFT_D7 ต่อเข้ากับ PA8
  • ET-TEST 10P/INP ต่อเข้ากับขาดังต่อไปนี้
    • PC13
    • PC14
    • PB1
    • PB2
    • PA2
    • PA3
    • PA50
    • PA6

การตั้งค่า TFT_eSPI

การตั้งค่าในไฟล์ส่วนหัวของ TFT_eSPI กรณีที่โมดูลแสดงผลใช้ ILI9341 เป็นดังนี้

#define STM32
#define TFT_PARALLEL_8_BIT

#define ILI9341_DRIVER

#define TFT_CS   PB0
#define TFT_DC   PA4
#define TFT_RST  PB12

#define TFT_WR   PA1
#define TFT_RD   PA0

#define TFT_D0   PA9
#define TFT_D1   PB13
#define TFT_D2   PA10
#define TFT_D3   PB3
#define TFT_D4   PB5
#define TFT_D5   PB4
#define TFT_D6   PB10
#define TFT_D7   PA8

#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define SMOOTH_FONT

สำหรับกรณีที่ตัวขับโมดูล TFT เป็นชิพ ILI9481 ให้เปลี่ยนไดรเวอร์โดยกำหนดค่าต่าง ๆ เหมือนเดิม ดังนี้

#define STM32
#define TFT_PARALLEL_8_BIT

#define ILI9481_DRIVER

#define TFT_CS   PB0  // Chip select control pin
#define TFT_DC   PA4  // Data Command control pin
#define TFT_RST  PB12 //PC1  // Reset pin ***

#define TFT_WR   PA1  // Write strobe control pin 
#define TFT_RD   PA0  // Read pin

#define TFT_D0   PA9  // 8 bit parallel bus to TFT
#define TFT_D1   PB13 // PC7 // ***
#define TFT_D2   PA10
#define TFT_D3   PB3
#define TFT_D4   PB5
#define TFT_D5   PB4
#define TFT_D6   PB10
#define TFT_D7   PA8

#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define SMOOTH_FONT

ตัวอย่างโปรแกรม

ตัวอย่างโปรแกรมทดสอบการแสดงผลโดยใช้งานไลบรารี U8g2_for_TFT_eSPI ซึ่งเป็นไลบรารีที่ทำงานผ่านชั้นของ TFT_eSPI อีกทีหนึ่ง โดยไลบรารีนี้มีจุดเเด่นในเรื่องของฟอนต์ที่มีความหลากหลาย (ดูได้จากที่นี่) และเลือกใช้ตัวอย่าง hello ของไลบรารีมาเพิ่มชุดคำสั่งเพื่อใช้งานได้ผลดังภาพที่ 6

/*
  Hello.ino

  Demonstrates how to use U8g2_for_TFT_eSPI library.

  U8g2_for_TFT_eSPI:
    - Use U8g2 fonts with TFT_eSPI
    - Supports UTF-8 in print statement
    - 90, 180 and 270 degree text direction
  
  List of all U8g2 fonts:    https://github.com/olikraus/u8g2/wiki/fntlistall

  TFT_eSPI library:          https://github.com/Bodmer/TFT_eSPI
  U8g2_for_TFT_eSPI library: https://github.com/Bodmer/U8g2_for_TFT_eSPI

*/
#include "SPI.h"
#include "TFT_eSPI.h"
#include "U8g2_for_TFT_eSPI.h"

TFT_eSPI tft = TFT_eSPI();   // tft instance
U8g2_for_TFT_eSPI u8f;       // U8g2 font instance

void setup() {
  tft.begin();
  tft.setRotation(1);
  tft.fillScreen(0x3861);

  u8f.begin(tft);                    
}

unsigned long x = 0;

void loop() {
  u8f.setFontMode(0);                 
  u8f.setFontDirection(0);         
  u8f.setForegroundColor(TFT_WHITE);  

  u8f.setFont(u8g2_font_helvR14_tf);  
  u8f.setCursor(0,20);              
  u8f.print("Hello World");
  u8f.setCursor(0,40);               
  u8f.print("Umlaut ÄÖÜ");           

  u8f.setBackgroundColor(0x3861);
  u8f.setForegroundColor(0xe717);
  u8f.setFont(u8g2_font_osb21_tf);
  u8f.setCursor(40,100);
  u8f.print("www.JarutEx.com");
  u8f.setForegroundColor(TFT_YELLOW);
  u8f.setCursor(20,100);
  u8f.print("~");
  u8f.setCursor(280,100);
  u8f.print("~");

  u8f.setFont(u8g2_font_inb63_mn);    
  u8f.setFontMode(0);                 
  u8f.setForegroundColor(TFT_WHITE); 

  while (1) {
    u8f.setCursor(0,200);  
    u8f.print(x);        
    x++;
    if (x > 99999) {
      x = 0;
    }
    delay(1000);
  }
} 

จากโค้ดตัวอย่างมีคำสั่งที่น่าสนใจดังนี้

  • begin( tft ) หมายถึง ไลบรารีต้องการ tft ซึ่งเป็นวัตถุแบบ TFT_eSPI เพื่อใช้สำหรับวาดตัวอักษร และเป็นคำสั่งเริ่มต้นทำงานของไลบรารี U8g_for_TFT_eSPI
  • setFontMode(0) หมายถึงเป็นการวาดแบบทับพื้นหลัง
  • setFontMode(1) หมายถึงวาดแบบลงเฉพาะจุดสีของตัวอักษร
  • setFontDirection(x) หมายถึงกำหนดทิศทางการวาดตัวอักษร (ให้ลองเปลี่ยนค่า x จาก 0 เป็นค่าอื่น ๆ)
  • setFont( x ) หมายถึงเลือกใช้ตัวอักษร x ซึ่งดูตัวอย่างตัวอักษร และค่าได้จากหน้าเว็บนี้
  • setForegroundColor( c ) หมายถึง กำหนดสีของตัวอักษรเป็น c
  • setBackgroundColor( c ) หมายถึง กำหนดสีพื้นหลังของตัวอักษรเป็น c
  • setCursor( x, y ) หมายถึง กำหนดจุดเริ่มวาดตัวอักษรที่พิกัด (x,y) ซึ่งเป็นตำแหน่งด้านล่างซ้ายของการวาดตัวอักษร
  • print(x) หมายถึง แสดงข้อความ x ตามลักษณะอักษร สี สีพื้นหลัง วิธีการวาด และตำแหน่งตามที่กำหนดในคำสั่งก่อนหน้านี้
Hello! ... Arduino Uno 2.4" TFT&Touch Shield
ภาพที่ 6 ตัวอย่างผลลัพธ์จากโปรแกรมตัวอย่าง hello

สรุป

จากบทความนี้จะพบว่าการใช้การเชื่อมต่อแบบ Parallel ต้องการใช้ขามากกว่าการใช้ SPI บัส แต่เมื่อสังเกตที่การตั้งค่าของ TFT_eSPI จะพบว่า ไม่ต้องกำหนดความถี่สัญญาณนาฬิกาในการส่งข้อมูล ทำให้ความเร็วในการส่งโดยภาพรวมนั้นอาจจะได้สูงกว่าแบบ SPI เนื่องจากในความถี่ที่เท่ากัน SPI จะเสียเวลาในการถอดรหัสบิตข้อมูลจากแบบอนุกรมให้เป็นแบบขนาน เนื่องจากส่งมาทีละบิต แต่การนำไปใช้ต้องนำไปใช้ทั้งไบต์ ขณะที่แบบการส่งแบบขนานจะส่งครั้งละไบต์ในคราเดียว

นอกจากนี้ จะพบว่าการใช้ TFT_eSPI ทำให้รองรับการใช้จอแสดงผลที่หลากหลายรุ่นและได้ความเร็วในการทำงานที่อยู่ในระดับที่ดีมาก แต่จุดอ่อนของไลบรารีคือมีตัวอักษรให้เลือกใช้น้อย หรือต้องทำฟอนต์เพื่อมาใช้งานเอง แต่เมื่อเรียกใช้งานไลบรารี U8g_for_TFT_eSPI จะพบว่ามีรูปแบบของฟอนต์ให้ใช้งานมากมาย และหลากหลายรูปแบบ โดยการสั่งงานที่ต้องระมัดระวังคือ ปริมาณหน่วยความจำคงเหลือของระบบ และวิธีการวาดที่จะวาดจากล่างขึ้นบน ด้วยเหตุนี้ค่าที่ส่งให้กับคำสั่ง setCursor(x,y) นั้น ค่า y จะเป็นค่าด้านล่างของการวาดไม่ใช้ด้านบนเหมือนที่เคยใช้มา

สุดท้ายนี้ขอให้สนุกกับการเขียนโปรแกรมครับ

ท่านใดต้องการพูดคุยสามารถคอมเมนท์ได้เลยครับ

(C) 2020-2021, โดย อ.ดนัย เจษฎาฐิติกุล/อ.จารุต บุศราทิจ
ปรับปรุงเมื่อ 2021-10-06, 2021-12-20