当前位置: 首页 > news >正文

esp32驱动带字库芯片TFT屏幕

前言

学习esp32单片机开发,前段时间在网上买了一块2.0寸TFT屏幕。

长这个样子,这个屏幕带汉字字库的硬件模块。我仔细看了一下这个字库模块上面写的字是25Q32FVSIG 1336

在这里插入图片描述在这里插入图片描述

文档

卖家也发来了开发文档,是个doc文档,张这个样子。

在这里插入图片描述
在这里插入图片描述

开发准备

下面开始根据文档进行开发,调用这个字库文件内的汉字,并且把它显示出来。
这个是我的接线,没有走硬件spi,这样直接插上去,就免去了接线线。
引脚对应

ST7789_GND GND
ST7789_VCC 15 VCC
ST7789_SCL 2  (SCLK)
ST7789_SDA 4  (MOSI)
ST7789_SDO 16  (MISO)
ST7789_RST 17
ST7789_DC 5
ST7789_CS 18
ST7789_CSF 19  
ST7789_BLK 21 VCC

在这里插入图片描述

创建工程 PlatformIO工程
配置和引用

[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
upload_speed = 921600
lib_deps = 
	bodmer/TFT_eSPI@^2.5.43
	tikaflow/UTF8ToGB2312@^1.1.52
1.引入TFT_eSPI.h 下载地址:https://github.com/Bodmer/TFT_eSPI
2.在User_Setup.h中
  放开注释: #define TFT_WIDTH  240
  放开注释: #define TFT_HEIGHT 320
  放开注释: #define ST7789_DRIVER 注释掉:默认的#define ILI9341_DRIVER

#define TFT_MOSI 4
#define TFT_SCLK 2
#define TFT_CS   18  // Chip select control pin
#define TFT_DC   5   // Data Command control pin
#define TFT_RST  17  // Reset pin (could connect to RST pin)
#define TFT_BL   21  // LED back-light

源码实现

根据上面文档,实现读取模块中汉字并且渲染到屏幕上。下面是源码

main.cpp

#include <Arduino.h>
#include <TFT_eSPI.h>
#include <SPI.h>
#include "UTF8ToGB2312.h"
TFT_eSPI tft;
// 字库芯片引脚
#define FLASH_CS 19
#define FLASH_MISO 16

// 字库结构体
struct FontInfo {
  uint8_t fontSize;      // 字号
  uint32_t byteSize;     // 字库占用字节数 实际占用是 byteSize * fontSize
  uint32_t addr;         // 字库偏移地址
};

// ASCII 字库信息
const FontInfo ASCII_FONTS[] = {
  {12, 1, 0X1000L},  // 6x12
  {14, 1, 0X1600L},  // 7x14
  {16, 1, 0X1D00L},  // 8x16
  {18, 2, 0X2500L},  // 9x18
  {20, 2, 0X3700L},  // 10x20
  {22, 2, 0X4B00L},  // 11x22
  {24, 2, 0X6100L},  // 12x24
  {26, 2, 0X7900L}   // 13x26
};

// GB2312 字库信息
const FontInfo GB2312_FONTS[] = {
  {12, 2, 0X9300L},     // 12x12
  {14, 2, 0X39300L},    // 14x14
  {16, 2, 0X71300L},    // 16x16
  {18, 3, 0XB1300L},    // 18x18
  {20, 3, 0X11D300L},   // 20x20
  {22, 3, 0X195300L},   // 22x22
  {24, 3, 0X219300L},   // 24x24
  {26, 4, 0X2A9300L}    // 26x26
};

// 初始化 SPI Flash
void initFlash() {
  pinMode(FLASH_CS, OUTPUT);
  digitalWrite(FLASH_CS, HIGH);
  SPI.begin(TFT_SCLK, FLASH_MISO, TFT_MOSI, FLASH_CS);
  SPI.setFrequency(1000000);
  SPI.setDataMode(SPI_MODE0);
}

// 读取字库数据
uint8_t readFontData(uint32_t addr) {
  uint8_t data;
  digitalWrite(FLASH_CS, LOW);
  SPI.transfer(0x03);
  SPI.transfer((addr >> 16) & 0xFF);
  SPI.transfer((addr >> 8) & 0xFF);
  SPI.transfer(addr & 0xFF);
  data = SPI.transfer(0x00);
  digitalWrite(FLASH_CS, HIGH);
  return data;
}

// 显示一个汉字 (GB2312)
void drawGB2312Char(uint16_t x, uint16_t y, uint16_t ch, uint16_t color, uint8_t fontSize) {
  if (fontSize < 12 || fontSize > 26 || (fontSize % 2) != 0) {
    return; // 无效的字体大小
  }
  const FontInfo& fontInfo = GB2312_FONTS[(fontSize - 12) / 2];
  uint32_t fontAddr = fontInfo.addr + (((ch >> 8) - 0xA1) * 94 + (ch & 0xFF) - 0xA1) * fontInfo.fontSize * fontInfo.byteSize;
  for (uint16_t i = 0; i < fontInfo.fontSize; i++) {
    for (uint16_t j = 0; j < fontInfo.byteSize; j++) {
      uint8_t data = readFontData(fontAddr + i * fontInfo.byteSize + j);
      for (uint8_t k = 0; k < 8; k++) {
        if (data & (0x80 >> k)) {
          tft.drawPixel(x + j * 8 + k, y + i, color);
        }
      }
    }
  }
}

// 显示一个 ASCII 字符
void drawASCIIChar(uint16_t x, uint16_t y, uint8_t ch, uint16_t color, uint8_t fontSize) {
  if (fontSize < 12 || fontSize > 26 || (fontSize % 2) != 0) {
    return; // 无效的字体大小
  }
  const FontInfo& fontInfo = ASCII_FONTS[(fontSize - 12) / 2];
  uint32_t fontAddr = fontInfo.addr + ch * fontInfo.byteSize * fontInfo.fontSize;
  for (uint16_t i = 0; i < fontInfo.fontSize; i++) {
    for (uint16_t j = 0; j < fontInfo.byteSize; j++) {
      uint8_t data = readFontData(fontAddr + i * fontInfo.byteSize + j);
      for (uint8_t k = 0; k < 8; k++) {
        if (data & (0x80 >> k)) {
          tft.drawPixel(x + j * 8 + k, y + i, color);
        }
      }
    }
  }
}

// 显示字符串 (兼容汉字、英文字符和数字)
void drawString(uint16_t x, uint16_t y, const char *str, uint16_t color, uint8_t fontSize = 16) {
  String gbStr = GB.get(str); // UTF-8 to GB2312
  const char *gbCharPtr = gbStr.c_str();
  uint16_t xPos = x;
  while (*gbCharPtr) {
    uint8_t ch = (uint8_t)gbCharPtr[0];
    if (ch >= 0xA1) { // 汉字
      uint16_t gbCh = (ch << 8) | (uint8_t)gbCharPtr[1];
      drawGB2312Char(xPos, y, gbCh, color, fontSize);
      xPos += fontSize;
      gbCharPtr += 2;
    } else if (ch >= 32 && ch <= 126) { // ASCII 字符
      drawASCIIChar(xPos, y, ch, color, fontSize);
      gbCharPtr++;
      xPos += fontSize / 2;
    } else { // 其他字符或错误处理
      gbCharPtr++; // 跳过未知字符
    }
  }
}

void setup() {
  Serial.begin(115200);
  pinMode(15, OUTPUT);
  pinMode(21, OUTPUT);
  digitalWrite(15, HIGH);
  digitalWrite(21, HIGH);

  tft.init();
  tft.fillScreen(TFT_BLACK);
  initFlash();

  drawString(0, 0, "12号:你好,世界!123abc", TFT_GREEN, 12);
  drawString(0, 12, "14号:你好,世界!123abc", TFT_GREEN, 14);
  drawString(0, 26, "16号:你好,世界!123abc", TFT_GREEN, 16);
  drawString(0, 42, "18号:你好,世界!123abc", TFT_GREEN, 18);
  drawString(0, 60, "20号:你好,世界!123abc", TFT_GREEN, 20);
  drawString(0, 80, "22号:你好,世界!123abc", TFT_GREEN, 22);
  drawString(0, 102, "24号:你好,世界!123abc", TFT_GREEN, 24);
  drawString(0, 126, "26号:你好,世界!123abc", TFT_GREEN, 26);
  drawString(0, 180, "CSDN关注:雨季余静", TFT_GREEN, 26);
}

void loop() {}

最终效果如下

在这里插入图片描述

总结

虽然源码没多少行,但是真的折腾了我一整天。

主要是这模块是gb2312的字库,然而程序代码中的汉字是UTF-8汉字。显示出来就是乱码,开始我还以为是我弄错了,后来才发现代码中的文字是UTF-8编码。引入了UTF8ToGB2312.h 问题就迎刃而解了。

如果解决了你的问题希望给个关注,谢谢。

相关文章:

  • Kimball维度建模技术解析:从业务需求到维度扩展
  • Java Spring Boot 外卖系统,构建便捷的本地生活服务
  • VS Code C++ 开发环境配置
  • Ollama 框架本地部署教程:开源定制,为AI 项目打造专属解决方案!
  • 最新的PyCharm及AI助手的安装和试用
  • H5DS编辑器是如何让企业快速构建动态页面
  • 一文读懂深度学习中的损失函数quantifying loss —— 作用、分类和示例代码
  • 权限管理Vue实现
  • CHAPTER 6 Object References, Mutability, and Recycling
  • 超越AI边界:智慧法务如何破解法律行业的“最后一公里“难题
  • ReconDreamer:通过在线恢复构建驾驶场景重建的世界模型
  • golang进阶知识专项-理解值传递
  • 记录一次Spring事务失效导致的生产问题
  • 第七节:基于Winform框架的串口助手小项目---协议解析《C#编程》
  • DeepSeek开源周:五大创新项目详解
  • 监听 RabbitMQ 延时交换机的消息数、OpenFeign 路径参数传入斜杠无法正确转义
  • Docker 部署开源项目HivisionIDPhotos详细教程
  • 【个人学习总结】反悔贪心:反悔堆+反悔自动机
  • SPL 和 SQL 能不能融合在一起?
  • 使用 marked.min.js 实现 Markdown 编辑器 —— 我的博客后台选择之旅
  • 哈尔滨服务专业的建站/百度指数的搜索指数代表什么
  • 为什么要立刻做网站/广州网络营销
  • 做网站用新域名还是老域名/产品市场推广方案
  • 网站权重转移做排名/百度一下知道首页
  • 嘉兴哪家公司做网站比较好的/廊坊seo整站优化软件
  • 手机移动网站设计/舆情优化公司