手中有一块LCD显示屏上自带GT20L16S1Y字库芯片,索性拿来试一下该字库芯片的使用。

GT20L16S1Y字库芯片比较常用,是16*16点阵的汉字库芯片,支持GB2312国标简体汉字,排列格式为竖置横排。

使用U8G2库调用字库芯片,会更加方便一点,把调试通过的Arduino代码记录一下。接线方面字库芯片和LCD屏共用SPI接口,以CS引脚控制数据传输。以下是手册中引脚说明。
示例代码如下。
#include<Arduino.h>#include<U8g2lib.h>#include<SPI.h>// --- 硬件定义 ---#define PIN_LCD_CS 7#define PIN_LCD_DC 6#define PIN_LCD_RST 11#define PIN_FONT_CS 5// --- U8g2 初始化 ---// 你的屏幕构造函数U8G2_ST7565_NHD_C12864_1_4W_HW_SPI u8g2(U8G2_R0, PIN_LCD_CS, PIN_LCD_DC, PIN_LCD_RST);// 汉字点阵缓冲区 (16x16点阵 = 32字节)uint8_t fontBuffer[32];// 英文字符点阵缓冲8*16uint8_t asciiBuffer[16];voidsetup(){// 初始化串口 (调试用) Serial.begin(115200);// 初始化字库芯片引脚pinMode(PIN_FONT_CS, OUTPUT);digitalWrite(PIN_FONT_CS, HIGH); // 默认拉高,取消选中// 初始化 SPI SPI.begin();// 初始化屏幕 u8g2.begin();}// 从GT20L16S1Y读取16x16汉字点阵数据voidreadFontData(uint8_t msb, uint8_t lsb, uint8_t *buffer){unsignedlong address;// GT20L16S1Y GB2312 地址计算公式:// BaseAddr + ((MSB - 0xB0) * 94 + (LSB - 0xA1)) * 32if (msb >= 0xA1 && msb <= 0xA3 && lsb >= 0xA1) { address = ((unsignedlong)(msb - 0xA1) * 94 + (lsb - 0xA1)) * 32; } elseif (msb >= 0xB0 && msb <= 0xF7 && lsb >= 0xA1) { address = ((unsignedlong)(msb - 0xB0) * 94 + (lsb - 0xA1) + 846) * 32; } elseif (msb == 0xA9 && lsb >= 0xA1) { address = (282 + (lsb - 0xA1)) * 32; } else { address = 0; }// 开始SPI事务读取字库 SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); // GT20L16S1Y支持高达30MHz+digitalWrite(PIN_FONT_CS, LOW);// 发送读取命令 0x03 SPI.transfer(0x03);// 发送地址 (24位地址,高位在前) SPI.transfer((address >> 16) & 0xFF); SPI.transfer((address >> 8) & 0xFF); SPI.transfer(address & 0xFF);// 读取32个字节的点阵数据for (int i = 0; i < 32; i++) { buffer[i] = SPI.transfer(0x00); }digitalWrite(PIN_FONT_CS, HIGH); SPI.endTransaction();}// 从GT20L16S1Y读取ASCII8x16点阵数据voidreadASCIIData(uint8_t asciichar, uint8_t *buffer){unsignedlong address = (asciichar-0x20)*16 + 0x3cf80;// 开始SPI事务读取字库 SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0)); // GT20L16S1Y支持高达30MHz+digitalWrite(PIN_FONT_CS, LOW);// 发送读取命令 0x03 SPI.transfer(0x03);// 发送地址 (24位地址,高位在前) SPI.transfer((address >> 16) & 0xFF); SPI.transfer((address >> 8) & 0xFF); SPI.transfer(address & 0xFF);// 读取32个字节的点阵数据for (int i = 0; i < 16; i++) { buffer[i] = SPI.transfer(0x00); }digitalWrite(PIN_FONT_CS, HIGH); SPI.endTransaction();}// 手动打点绘制汉字voiddrawChineseChar(int x, int y, uint8_t msb, uint8_t lsb){readFontData(msb, lsb, fontBuffer);for (int i = 0; i < 32; i++) {uint8_t byteData = fontBuffer[i];for (int bit = 0; bit < 8; bit++) {if (byteData & (0x01 << bit)) {// 根据具体的排列方式计算 x, y u8g2.drawPixel(x + (i % 16) , y + (i / 16) * 8 + bit); } } }}// 手动打点绘制ascii字符voiddrawASCIIChar(int x, int y, uint8_t asciichar){readASCIIData(asciichar, asciiBuffer);for (int i = 0; i < 16; i++) {uint8_t byteData = asciiBuffer[i];for (int bit = 0; bit < 8; bit++) {if (byteData & (0x01 << bit)) {// 根据具体的排列方式计算 x, y u8g2.drawPixel(x + (i % 8) , y + (i / 8) * 8 + bit); } } }}voiddrawExternalFontString(int x, int y, constuint8_t *str){int cursorX = x;while (*str) {if (*str < 128) {// ASCII// 英文字体向下压2个像素,与汉字基本取齐。drawASCIIChar(cursorX, y + 2 , *str); cursorX += 8; str++; } else {// 中文uint8_t msb = *str;uint8_t lsb = *(str + 1);if (lsb == 0) break;drawChineseChar(cursorX, y, msb, lsb); cursorX += 16; str += 2; } }}voidloop(){ u8g2.firstPage();do {// 由于 Arduino IDE 是 UTF-8,我们不能直接写 "你好World"。// 我们需要用 16进制 来表示 GB2312 编码。constuint8_t textCN[] = {0xB5, 0xB7, 0xB9, 0xC4, 0xD2, 0xD7, 0xD7, 0xE5, 0x00}; //捣鼓易族constuint8_t textMix[] = {'H', 'e', 'l', 'l', 'o', 0xCA, 0xC0, 0xBD, 0xE7, 0xA1, 0xA3, 0x00}; //Hello世界// 显示drawExternalFontString(0, 0, textCN);drawExternalFontString(0, 20, textMix); } while (u8g2.nextPage());delay(1000);}
运行效果如下。
评论区
登录后即可参与讨论
立即登录