Making custom characters on TFT LCD

Hi!

Can somebody help me to make custom character on 3.5" TFT LCD?
There are plenty examples how to make this on 16x2 LCD, but I can not find an example for TFT LCD.
I am using Mcufriend 3.5" TFT LCD, ID=0x6814.
I found this solution on internet, but not work on my LCD:

Thank you.

Hi there!

Is then any option for me, to display few Chinese characters on Mcufriend3.5" TFT LCD?
Or it is hopeless?

Best regards!

I wrote a message in English. Google Translate to Chinese. I copy-paste the result into the Arduino sketch. Note that the copy-paste stores UTF8 sequences that store a 16-bit Unicode as a 3-byte sequence.

Obviously I could not include a 6000 character Chinese font. I used a separate sketch to extract the bitmaps for the unicode values that are used.
This seems to work ok for most Google-Translate results. I could NOT find bitmaps for your example characters.

Please try this sketch (in the next message). If you post a list of all the Chinese characters that you want to use, I can post the relevant bitmaps.

Life is much simpler with an external font chip. Then you can print GB2312, GB12345, BIG5 ... or whatever. Size of font is no problem. However most Flash Font chips are 3.3V. Your Uno is 5V.

Most of the current Mcufriend shields have an empty footprint for a Font chip but these will only be ok on a 3.3V Zero, Due, Nucleo, ...

David.

#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;

#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

extern int print_unicode(uint16_t unicode);

uint8_t utf8_msg[] = "由沙子制成的城堡最竟落入海中"
                     ;
uint8_t utf8_fail[] = "由沙子製成的城堡最終落入海中"
                      ;
uint8_t utf8_duff[] = "屁股今天比昨天便宜便宜"
                      ;
uint8_t utf8_veter72[] = "Test (Ceshi):测试Settings (Shezhi):设置"
                         ;
uint16_t unicode_msg[] = {
    0x7531, 0x6c99, 0x5b50, 0x5236, 0x6210, 0x7684, 0x57ce, 0x5821,
    0x6700, 0x7adf, 0x843d, 0x5165, 0x6d77, 0x4e2d,
};

typedef struct {
    uint16_t code;
    uint16_t bits[16];
} font_table_t;

const font_table_t table[] PROGMEM = {
    { 0x7531, {0x0100, 0x0100, 0x0100, 0x0100, 0x3FF8, 0x2108, 0x2108, 0x2108, 0x2108, 0x3FF8, 0x2108, 0x2108, 0x2108, 0x2108, 0x3FF8, 0x2008, } },
    { 0x6C99, {0x0040, 0x2040, 0x1040, 0x1148, 0x8144, 0x4242, 0x4242, 0x1448, 0x1048, 0x2048, 0xE010, 0x2010, 0x2020, 0x2040, 0x2180, 0x0600, } },
    { 0x5B50, {0x0000, 0x7FF8, 0x0010, 0x0020, 0x0040, 0x0180, 0x0100, 0xFFFE, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0500, 0x0200, } },
    { 0x5236, {0x0404, 0x2404, 0x2404, 0x3FA4, 0x4424, 0x0424, 0xFFE4, 0x0424, 0x0424, 0x3FA4, 0x24A4, 0x24A4, 0x2684, 0x2504, 0x0414, 0x0408, } },
    { 0x6210, {0x0050, 0x0048, 0x0040, 0x3FFE, 0x2040, 0x2040, 0x2044, 0x3E44, 0x2244, 0x2228, 0x2228, 0x2212, 0x2A32, 0x444A, 0x4086, 0x8102, } },
    { 0x7684, {0x1040, 0x1040, 0x2040, 0x7E7C, 0x4284, 0x4284, 0x4304, 0x4244, 0x7E24, 0x4224, 0x4204, 0x4204, 0x4204, 0x7E04, 0x4228, 0x0010, } },
    { 0x57CE, {0x2028, 0x2024, 0x2020, 0x27FE, 0x2420, 0xFC20, 0x2424, 0x27A4, 0x24A4, 0x24A8, 0x24A8, 0x3C90, 0xE692, 0x492A, 0x0846, 0x1082, } },
    { 0x5821, {0x0800, 0x0BF8, 0x1208, 0x33F8, 0x5040, 0x97FC, 0x1150, 0x1248, 0x1446, 0x1140, 0x0100, 0x3FF8, 0x0100, 0x0100, 0xFFFE, 0x0000, } },
    { 0x6700, {0x1FF0, 0x1010, 0x1FF0, 0x1010, 0x1FF0, 0x0000, 0xFFFE, 0x2200, 0x3EF8, 0x2288, 0x3E90, 0x2250, 0x2F20, 0xF250, 0x4288, 0x0306, } },
    { 0x7ADF, {0x0200, 0x0100, 0x3FF8, 0x0820, 0x0440, 0xFFFE, 0x0000, 0x1FF0, 0x1010, 0x1FF0, 0x1010, 0x1FF0, 0x0440, 0x0842, 0x1042, 0x603E, } },
    { 0x843D, {0x0820, 0x0820, 0xFFFE, 0x0820, 0x2080, 0x10F8, 0x1108, 0x8290, 0x4860, 0x4998, 0x1606, 0xE1F8, 0x2108, 0x2108, 0x21F8, 0x2108, } },
    { 0x5165, {0x0000, 0x0F00, 0x0100, 0x0100, 0x0100, 0x0280, 0x0280, 0x0280, 0x0440, 0x0440, 0x0820, 0x0820, 0x1010, 0x2010, 0x4008, 0x8006, } },
    { 0x6D77, {0x0100, 0x2100, 0x11FC, 0x1200, 0x85F8, 0x4128, 0x4928, 0x0928, 0x17FE, 0x1148, 0xE248, 0x2248, 0x23FC, 0x2008, 0x2050, 0x0020, } },
    { 0x4E2D, {0x0100, 0x0100, 0x0100, 0x0100, 0x3FF8, 0x2108, 0x2108, 0x2108, 0x2108, 0x2108, 0x3FF8, 0x2108, 0x0100, 0x0100, 0x0100, 0x0100, } },

    { 0x5C41, {0x0000, 0x3FF8, 0x2008, 0x2008, 0x3FF8, 0x2000, 0x2840, 0x2840, 0x2844, 0x2F48, 0x2850, 0x2860, 0x4844, 0x4944, 0x8A44, 0x0C3C, } },
    { 0x80A1, {0x0000, 0x3CF8, 0x2488, 0x2488, 0x2488, 0x3D06, 0x2600, 0x25FC, 0x2484, 0x3C84, 0x2448, 0x2450, 0x2420, 0x4450, 0x5488, 0x8B06, } },
    { 0x4ECA, {0x0100, 0x0100, 0x0280, 0x0440, 0x0820, 0x1210, 0x2108, 0xC106, 0x0000, 0x1FF0, 0x0010, 0x0020, 0x0020, 0x0040, 0x0080, 0x0100, } },
    { 0x5929, {0x0000, 0x3FF8, 0x0100, 0x0100, 0x0100, 0x0100, 0xFFFE, 0x0100, 0x0280, 0x0280, 0x0440, 0x0440, 0x0820, 0x1010, 0x2008, 0xC006, } },
    { 0x6BD4, {0x0080, 0x2080, 0x2080, 0x2084, 0x2088, 0x2090, 0x3EA0, 0x20C0, 0x2080, 0x2080, 0x2080, 0x2082, 0x2682, 0x3882, 0x207E, 0x0000, } },
    { 0x6628, {0x0100, 0x0100, 0x7900, 0x49FE, 0x4A80, 0x4A80, 0x4C80, 0x78F8, 0x4880, 0x4880, 0x4880, 0x48FC, 0x7880, 0x4880, 0x0080, 0x0080, } },
    { 0x5929, {0x0000, 0x3FF8, 0x0100, 0x0100, 0x0100, 0x0100, 0xFFFE, 0x0100, 0x0280, 0x0280, 0x0440, 0x0440, 0x0820, 0x1010, 0x2008, 0xC006, } },
    { 0x4FBF, {0x1000, 0x17FE, 0x1040, 0x27FC, 0x2444, 0x6444, 0x67FC, 0xA444, 0x2444, 0x27FC, 0x2240, 0x2140, 0x2080, 0x2140, 0x2230, 0x2C0E, } },
    { 0x5B9C, {0x0200, 0x0100, 0x7FFE, 0x4002, 0x8004, 0x1FF0, 0x1010, 0x1010, 0x1FF0, 0x1010, 0x1010, 0x1FF0, 0x1010, 0x1010, 0xFFFE, 0x0000, } },

    { 0x88FD, {0x2404, 0x3FA4, 0x4424, 0xFFA4, 0x0424, 0x3F84, 0x2494, 0x2588, 0x0200, 0x0100, 0xFFFE, 0x0488, 0x0C50, 0x3420, 0xC518, 0x0606, } },
    { 0x7D42, {0x1040, 0x1040, 0x207C, 0x2884, 0x4988, 0xF250, 0x1020, 0x2050, 0x4888, 0xFB06, 0x2860, 0x2010, 0xA808, 0xA8C0, 0xA020, 0x2010, } },

    { 0x6D4B, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, } },
    { 0x8BD5, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, } },
    { 0x8BBE, {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, } },
    { 0x7F6E, {0x0000, 0x7FFC, 0x4444, 0x7FFC, 0x0100, 0x7FFC, 0x0100, 0x1FF0, 0x1010, 0x1FF0, 0x5010, 0x5FF0, 0x5010, 0x5FF0, 0x4000, 0x7FFC, } },

};

int UTF8toUnicode(const uint8_t *s)
{
    int wid = 0;
    uint16_t wc;
    int len = strlen(s);
    for ( int i = 0; i < len; )
    {
        uint8_t c = s[i];
        if ( (c & 0x80) == 0 )
        {
            wc = c;
            ++i;
        }
        // most Chinese UTF8 sequences are 2 or 3 byte
        else if ( (c & 0xE0) == 0xC0 )
        {
            wc = (s[i] & 0x1F) << 6;
            wc |= (s[i + 1] & 0x3F);
            i += 2;
        }
        else if ( (c & 0xF0) == 0xE0 )
        {
            wc = (s[i] & 0xF) << 12;
            wc |= (s[i + 1] & 0x3F) << 6;
            wc |= (s[i + 2] & 0x3F);
            i += 3;
        }
        // it is UNLIKELY that you have 4,5,6-byte UTF8 sequences
        // and I make no attempt to support 24-bit Unicode
        else if ( (c & 0xF8) == 0xF0 )
        {
            wc = (s[i] & 0x7) << 18;
            wc |= (s[i + 1] & 0x3F) << 12;
            wc |= (s[i + 2] & 0x3F) << 6;
            wc |= (s[i + 3] & 0x3F);
            i += 4;
        }
        else if ( (c & 0xFC) == 0xF8 )
        {
            wc = (s[i] & 0x3) << 24;
            wc |= (s[i] & 0x3F) << 18;
            wc |= (s[i] & 0x3F) << 12;
            wc |= (s[i] & 0x3F) << 6;
            wc |= (s[i] & 0x3F);
            i += 5;
        }
        else if ( (c & 0xFE) == 0xFC )
        {
            wc = (s[i] & 0x1) << 30;
            wc |= (s[i] & 0x3F) << 24;
            wc |= (s[i] & 0x3F) << 18;
            wc |= (s[i] & 0x3F) << 12;
            wc |= (s[i] & 0x3F) << 6;
            wc |= (s[i] & 0x3F);
            i += 6;
        }
        //Serial.print("0x");
        //Serial.println(wc, HEX);
        if (wc > 0x7f) {
            print_unicode(wc);
        }
        else tft.print((char)wc);
        wid += (wc > 0x7F) ? 16 : 8;

    }
    return wid;
}

void show_letter16_P(const uint16_t *buf, uint8_t w, uint8_t h, uint16_t color, uint16_t bg, int16_t x, int16_t y)
{
    uint16_t bits, carry;
    for (int row = 0; row < h; row++) {
        for (int col = 0; col < w; col++) {
            if ((col & 15) == 0) bits = pgm_read_word(buf++);
            tft.drawPixel(x + col, y + row, (bits & 0x8000) ? color : bg);
            bits <<= 1;
        }
    }
}

int print_unicode(uint16_t unicode)
{
    int x = tft.getCursorX(), y = tft.getCursorY();
    int siz = sizeof(table) / sizeof(table[0]);
    int j;
    for (j = 0; j < siz; j++) {
        if (pgm_read_word(&table[j].code) == unicode) {
            show_letter16_P(&table[j].bits[0], 16, 16, WHITE, RED, x, y);
            break;
        }
    }
    if (j >= siz) tft.fillRect(x, y, 16, 16, GREEN);
    tft.setCursor(x + 16, y);
    return 16;
}

void setup(void)
{
    Serial.begin(9600);
    Serial.println("Chinese print");

    tft.begin(tft.readID());
    tft.setRotation(1);
    tft.fillScreen(BLACK);

    tft.setCursor(0, 0);
    tft.print("Chinese print");

    delay(1000);

    tft.setCursor(0, 100);
    UTF8toUnicode(utf8_msg);

    tft.setCursor(5, 120);
    UTF8toUnicode(utf8_fail);

    tft.setCursor(15, 140);
    UTF8toUnicode(utf8_duff);

    tft.setCursor(5, 160);
    UTF8toUnicode(utf8_veter72);

}

void loop(void)
{
}