3. SPI接口TFT屏初始化与清屏

SPI接口TFT屏初始化与清屏 学习卡片

任务说明

本案例要求在已初始化的TFT LCD(以ILI9341为例,240×320分辨率)上显示中文字符“单片机”。核心工作是:集成一个最小中文字库(16×16点阵),实现汉字点阵提取与显示函数,并理解汉字GB2312编码到点阵存储地址的映射关系。

汉字编码与点阵存储原理

GB2312编码中,每个汉字占2字节。第一个字节为区码(0xA1~0xFE),第二个字节为位码(0xA1~0xFE)。16×16点阵字库按区位码顺序连续存储,每个汉字占用32字节(16行×每行2字节)。字库中某汉字的偏移地址计算公式为:

offset = ((区码 - 0xA1) * 94 + (位码 - 0xA1)) * 32

其中94表示每区有94个汉字位。显示时,逐字节读取点阵数据,每个字节的8个bit对应一行中的8个像素点,bit为1时点亮前景色,为0时显示背景色。

代码实现

以下代码包含:16×16点阵字库(仅收录“单片机”三字,共96字节)、汉字显示函数、以及主函数调用示例。字库数据按GB2312区位码顺序排列,“单”区码0xB5(181),位码0xE5(229);“片”区码0xC6(198),位码0xAC(172);“机”区码0xBB(187),位码0xFA(250)。


// font_demo.c - 在ILI9341 LCD上显示中文字符"单片机"
// 硬件接口:SPI或并口驱动,需自行实现底层画点函数LCD_DrawPixel

#include <stdint.h>
#include <string.h>

// ---------- 底层接口声明(需根据实际硬件实现) ----------
// 在(x,y)位置画一个像素点,color为RGB565格式
void LCD_DrawPixel(uint16_t x, uint16_t y, uint16_t color);
// 初始化LCD(已由前序案例完成)
void LCD_Init(void);
// 清屏
void LCD_Clear(uint16_t color);

// ---------- 16x16点阵字库(仅含"单片机"三字) ----------
// 按GB2312区位码顺序存储:单(0xB5E5)、片(0xC6AC)、机(0xBBFA)
// 每个汉字32字节,每字节对应一行中的8个像素点
static const uint8_t font_hanzi[3][32] = {
    // "单" - 0xB5E5
    {0x00,0x00,0x7F,0xFC,0x08,0x20,0x08,0x20,
     0x08,0x20,0x08,0x20,0x0F,0xE0,0x08,0x20,
     0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,
     0x08,0x20,0x7F,0xFC,0x00,0x00,0x00,0x00},
    // "片" - 0xC6AC
    {0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,
     0x20,0x08,0x20,0x08,0x3F,0xF8,0x20,0x08,
     0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,
     0x20,0x08,0x3F,0xF8,0x00,0x00,0x00,0x00},
    // "机" - 0xBBFA
    {0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,
     0x20,0x08,0x20,0x08,0x3F,0xF8,0x20,0x08,
     0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,
     0x20,0x08,0x3F,0xF8,0x00,0x00,0x00,0x00}
};

// ---------- 汉字显示函数 ----------
// x,y: 显示起始坐标(左上角);str: 以'\0'结尾的GB2312中文字符串
// color: 前景色;bgcolor: 背景色
void LCD_ShowChinese(uint16_t x, uint16_t y, const char *str,
                     uint16_t color, uint16_t bgcolor)
{
    while (*str != '\0') {
        // 只处理GB2312双字节汉字(两个字节均>=0xA1)
        if ((uint8_t)str[0] >= 0xA1 && (uint8_t)str[1] >= 0xA1) {
            uint8_t qu = (uint8_t)str[0] - 0xA1;  // 区码索引
            uint8_t wei = (uint8_t)str[1] - 0xA1; // 位码索引
            uint32_t offset = ((uint32_t)qu * 94 + wei) * 32; // 字库偏移

            // 遍历16行
            for (uint8_t row = 0; row < 16; row++) {
                uint8_t byteL = font_hanzi[0][offset + row*2];     // 高字节(左8像素)
                uint8_t byteH = font_hanzi[0][offset + row*2 + 1]; // 低字节(右8像素)
                // 左半部分8像素
                for (uint8_t bit = 0; bit < 8; bit++) {
                    if (byteL & (0x80 >> bit))
                        LCD_DrawPixel(x + bit, y + row, color);
                    else
                        LCD_DrawPixel(x + bit, y + row, bgcolor);
                }
                // 右半部分8像素
                for (uint8_t bit = 0; bit < 8; bit++) {
                    if (byteH & (0x80 >> bit))
                        LCD_DrawPixel(x + 8 + bit, y + row, color);
                    else
                        LCD_DrawPixel(x + 8 + bit, y + row, bgcolor);
                }
            }
            x += 16; // 移动到下一个汉字位置
            str += 2; // 跳过2字节
        } else {
            str++; // 非汉字字符跳过(本案例不处理ASCII)
        }
    }
}

// ---------- 主函数示例 ----------
int main(void)
{
    LCD_Init();
    LCD_Clear(0xFFFF); // 白色背景

    // 在坐标(50,100)处用红色显示"单片机"
    LCD_ShowChinese(50, 100, "单片机", 0xF800, 0xFFFF);

    while (1) {
        // 主循环空转
    }
    return 0;
}

代码说明

上述代码中,font_hanzi数组仅包含“单片机”三个字的点阵数据,实际项目中可替换为完整字库文件。显示函数LCD_ShowChinese通过计算GB2312区位码偏移量,从字库中提取对应汉字的32字节点阵数据,逐行逐像素绘制。注意:本示例字库中三个字的点阵数据为示意性数据(“片”和“机”使用了相同字形),实际应用需替换为真实字库点阵。

验证方法

将代码编译烧录至目标板,观察LCD屏幕坐标(50,100)处是否显示“单片机”三个汉字。判定标准:三个汉字清晰可辨,每个汉字尺寸为16×16像素,字间距为16像素,背景为白色,文字为红色。若显示异常,可检查:1)字库点阵数据是否正确;2)GB2312编码是否与字库存储顺序匹配;3)画点函数坐标方向是否与LCD面板一致。

汉字显示数据流与存储映射 GB2312编码 "单" = 0xB5E5 "片" = 0xC6AC "机" = 0xBBFA 区码 = 字节1 - 0xA1 位码 = 字节2 - 0xA1 偏移 16×16点阵字库 偏移0: "单" 32B 偏移32: "片" 32B 偏移64: "机" 32B 每字32字节 (16行×2字节) 逐行 LCD屏幕显示 每个汉字16×16像素 bit=1 → 前景色 bit=0 → 背景色

关键理解点

本案例的核心在于理解汉字编码到点阵数据的映射关系。GB2312编码通过区位码定位字库中的存储位置,而点阵数据则直接决定了像素的亮灭状态。实际工程中,中文字库通常存储在外部Flash中,通过文件系统或地址映射访问,本案例将其内嵌在代码中以便演示完整流程。若要扩展显示更多汉字,只需将完整字库文件(如HZK16)按相同格式集成即可。