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.43tikaflow/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 * fontSizeuint32_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 GB2312const 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 问题就迎刃而解了。
如果解决了你的问题希望给个关注,谢谢。
相关文章:
esp32驱动带字库芯片TFT屏幕
前言 学习esp32单片机开发,前段时间在网上买了一块2.0寸TFT屏幕。 长这个样子,这个屏幕带汉字字库的硬件模块。我仔细看了一下这个字库模块上面写的字是25Q32FVSIG 1336 文档 卖家也发来了开发文档,是个doc文档,张这个样子。 开…...
为AI聊天工具添加一个知识系统 之138 设计重审 之2 文章学 引言之2 附加符号学附属诠释学附随工程学(联系)
本文要点 要点 符号学大局观: 诠释学(当代 加成[0]:“预期”和“预设” 两者的 不期而遇 。“邂逅”) 我们在文章学工具设计中 以全局观考虑:嵌入编程工具的逻辑性底( 哲学诠释 下确界) 并…...
java环境部署
java环境部署 一、准备工作 jrejdkeclipse jdk下载:21和1.8-----官网:Oracle:Java 下载 |神谕 该处选择要依据自身的系统类型选择下载 idea的下载安装:IntelliJ IDEA | Other Versions 二、安装 三、环境配置 四、使用 五、i…...
正点原子[第三期]Arm(iMX6U)Linux移植学习笔记-2.1 uboot简介
前言: 本文是根据哔哩哔哩网站上“Arm(iMX6U)Linux系统移植和根文件系统构键篇”视频的学习笔记,在这里会记录下正点原子 I.MX6ULL 开发板的配套视频教程所作的实验和学习笔记内容。本文大量引用了正点原子教学视频和链接中的内容。 引用: …...
CentOS 7.9 安装 ClickHouse 文档
1. 环境准备 确保系统为 CentOS 7.9,并已安装 Docker。如果未安装 Docker,请先安装 Docker。 安装 Docker # 卸载旧版本 Docker(如果有) sudo yum remove -y docker docker-client docker-client-latest docker-common docker-…...
高考數學。。。
2024上 具体来说,直线的参数方程可以写为: x1t y−t z1t 二、简答题(本大题共5小题,每小题7分,共35分。) 12.数学学习评价不仅要关注结果评价,也要关注过程评价。简要说明过程评价应关注哪几个方面。…...
使用GitLink个人建站服务部署Allure在线测试报告
更多技术文章,访问软件测试社区 文章目录 🚀前言🔑开通GitLink个人建站服务1. 前提条件2. 登录GitLink平台(https://www.gitlink.org.cn/login)3. 进入设置>个人建站>我的站点4. 新建站点5. 去仓部进行部署6. 安…...
Linux 上离线安装 python3
在Linux系统上进行离线安装 Python3,通常是因为目标机器没有网络连接。以下是一个通用的步骤指南,帮助你在这种情况下成功安装Python 3: 下载安装包 选择一台有网络连接的机器:这台机器的操作系统应该尽可能与目标机器相同或相似…...
js操作字符串的常用方法
1. 查找和截取 1.1 indexOf 作用:查找子字符串在字符串中首次出现的位置。 是否改变原字符串:不会改变原字符串。 返回值:如果找到子字符串,返回其起始索引(从 0 开始);如果未…...
自动化学习-使用git进行版本管理
目录 一、为什么要学习git 二、git是什么 三、git如何使用 1、git的下载安装和配置 2、git常用的命令 3、gitee远程仓库的使用 (1)注册 (2)创建仓库 (3)配置公钥(建立电脑和git…...
GCC RISCV 后端 -- GCC Passes 注释
在前面文章提到,当GCC 前端完成对C源代码解析完成后,就会使用 处理过程(Passes)机制,通过一系列的处理过程,将 GENERIC IR 表示的C程序 转步转换成 目标机器的汇编语言。过程描述如下图所示: 此…...
Ollama存在安全风险的情况通报及解决方案
据清华大学网络空间测绘联合研究中心分析,开源跨平台大模型工具Ollama默认配置存在未授权访问与模型窃取等安全隐患。鉴于目前DeepSeek等大模型的研究部署和应用非常广泛,多数用户使用Ollama私有化部署且未修改默认配置,存在数据泄露、算力盗…...
IDEA Generate POJOs.groovy 踩坑小计 | 生成实体 |groovy报错
一、无法生成注释或生成的注释是null 问题可能的原因: 1.没有从表里提取注释信息,修改def calcFields(table)方法即可 def calcFields(table) {DasUtil.getColumns(table).reduce([]) { fields, col ->def spec Case.LOWER.apply(col.getDataType().…...
阿里云云监控资源告警常用模板
阿里云云监控资源告警常用模板 {"HostAvailabilityTemplate": [],"Description": "","SystemEventTemplates": [],"AlertTemplatesJson": {"kvstore_standard": [{"displayName": "Connection usa…...
Tailwind CSS 问题:npm error could not determine executable to run
问题与处理策略 问题描述 npx tailwindcss init -p在使用 Tailwind CSS 的前端项目中,执行上述指令,即初始化 Tailwind CSS 时,报如下错误 npm error could not determine executable to run# 报错npm 错误无法确定要运行的可执行文件问题…...
vue基本功
watchEffect和watch watchEffect默认 immdiate 是 true,而且自动收集依赖 watch需要手动写依赖,immdiate 默认是 false toRef和toRefs toRef: 复制 reactive 里的单个属性并转成 ref toRefs: 复制 reactive 里的所有属性并转成 ref vue3中使用vuex import { useStore } f…...
.NET10 - 预览版1新功能体验(一)
.NET 10 首个预览版已经在前两天发布,该版本在 .NET Runtime、SDK、libraries、C#、ASP.NET Core、Blazor 和 .NET MAUI 等多个方面都有重大改进和增强。其中C# 14 预览版也伴随着.NET 10预览版一起发布了,今天就和大家一起体验一下.NET 10 和 C# 14 。 …...
java下载多个网络文件并压缩成压缩包保存到本地
背景 开发票的时候远程会返回发票的url,现在客户端需要下载发票;因为一个订单可能不止一张发票,因此需要通过网络把远程的文件下载回来并压缩成压缩文件进行返回。 实现 本文的例子直接基于java.net包下面的类实现。(因为是基于…...
23种设计模式之单例模式(Singleton Pattern)【设计模式】
文章目录 一、简介二、关键点三、实现单例模式的步骤四、C#示例4.1 简单的单例模式4.2 线程安全的单例模式(双重检查锁定)4.3 静态初始化单例模式 五、单例模式优缺点5.1 优点5.2 缺点 六、适用场景七、示例的现实应用 一、简介 单例模式(Si…...
[项目]基于FreeRTOS的STM32四轴飞行器: 四.LED控制
基于FreeRTOS的STM32四轴飞行器: 四.LED控制 一.配置Com层二.编写驱动 一.配置Com层 先在Com_Config.h中定义灯位置的枚举类型: 之后定义Led的结构体: 定义飞行器状态: 在Com_Config.c中初始化四个灯: 在Com_Config.h外部声明…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
Chrome 浏览器前端与客户端双向通信实战
Chrome 前端(即页面 JS / Web UI)与客户端(C 后端)的交互机制,是 Chromium 架构中非常核心的一环。下面我将按常见场景,从通道、流程、技术栈几个角度做一套完整的分析,特别适合你这种在分析和改…...
WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...
GB/T 43887-2024 核级柔性石墨板材检测
核级柔性石墨板材是指以可膨胀石墨为原料、未经改性和增强、用于核工业的核级柔性石墨板材。 GB/T 43887-2024核级柔性石墨板材检测检测指标: 测试项目 测试标准 外观 GB/T 43887 尺寸偏差 GB/T 43887 化学成分 GB/T 43887 密度偏差 GB/T 43887 拉伸强度…...
CentOS 7.9安装Nginx1.24.0时报 checking for LuaJIT 2.x ... not found
Nginx1.24编译时,报LuaJIT2.x错误, configuring additional modules adding module in /www/server/nginx/src/ngx_devel_kit ngx_devel_kit was configured adding module in /www/server/nginx/src/lua_nginx_module checking for LuaJIT 2.x ... not…...
Spring是如何实现无代理对象的循环依赖
无代理对象的循环依赖 什么是循环依赖解决方案实现方式测试验证 引入代理对象的影响创建代理对象问题分析 源码见:mini-spring 什么是循环依赖 循环依赖是指在对象创建过程中,两个或多个对象相互依赖,导致创建过程陷入死循环。以下通过一个简…...


