在esp32(esp8266) 提供软字库显示中文的解决方案

news2024/11/24 19:34:01

本方案已经开源到了 https://github.com/StarCompute/tftziku ,详细内容请访问Github.

本方案在esp32 下经过测试在tft屏幕上可以正常输出文字,也就是说经过了验证。

目录

说明

缘起

系统结构

软字库的创建

软字库包含的内容:

软字库的格式

字模的格式

软字库在单片机中的使用

在终端输出

通过单片机在tft屏幕显示


说明

本项目是为了在各种单片机使用中创建更方便易用的字库,配合使用了  ``TFT_eSPI`` 进行显示使用,实际上可以用于其他任何点阵屏。

缘起

我们都知道,要在单片机上使用汉字输出,都必须汉字点阵化,然后再集成到单片机中进行输出;然而这里有个弊病,就是你输出的汉字每次都必须使用类似于 PCtoLCD2018 这样的软件来处理,极其不方便;而如果单片机要同上位机进行文字通信的时候,上位机的文字其实不受限的,这个时候采取预处理文字的方式就不行了,虽然我自己采用过像素化进行通信,但是始终觉得非常不便。 事实上,文字的调整是个高频的事情,如果每次使用 PCtoLCD2018 来处理实在太繁琐了,因此就产生了一个基本问题:重复修改字体数据,这也同时提出了一个需求:使用软字库。 如果时光倒退无数年,会有专门卖 硬件字库 的,以及PC上类似于 UCDOS 这样软字库的东西。 单片机上各种中文的显示,大家常见的是U8G2这种东西,但是它的汉字非常不全面,基本用不起来。在使用 Tft_eSPI 的字库工具包 processing 过程中,网上有些教程误导我们先用 processing 创建vlw文件,再去转换成.h文件,最后编译进项目里面去。 这是一种完全的误导: - vlw 文件是可以被 tft_espi 项目直接使用的; - 无论是vlw还是.h格式的文件,如果是个别中文的处理毫无意义,而如果是完全的字符(类似于GB2312),这个vlw和.h文件都是非常巨大的,在我的esp32上是无法上传到flash空间中。

基于经验的积累和对于 tft_espi 的部分学习,尝试用自己的方式来创建包含 gb2312 字符集的字库,经过测试后发觉:自己创建的16号字体 GB2312 字符集整体只有507k,这个比vlw文件少了一半的空间占用。

并且, tft_espi 装载自己的vlw字库需要2秒,然后显示对应文字需要0.1x秒左右,而使用我自己创建字库利用tft_espi驱动显示同样的文字只需要0.28秒左右,整体性能提升已经达到了一个相对很高的程度。

从空间占用和显示速度上都b表现出了更优,为了方便大家更方便的进行单片机,所以把这个项目进行开源。

系统结构

软字库的创建

软字库包含的内容:

软字体用 python 进行创建,在本项目中是 getunicode.py ,它是把绝大部分能够显示出来的GB2312字符集包含进来了,然后包括进来了常见的大小写英文字母和字符(从chr(33)=chr(128)),由于 GB18030 的字库太大,所以是不可能使用 GB18030 ,使用了 GB2312 ,我们平常使用的文字基本都在这个字库中,例如“饕餮”这两个字都在GB2312中。

软字库的格式

  • 软字体以x.font方式进行命名,采用纯文本进行存储。
  • x.font文件被分成了4个部分:
  • 前6位16进制表示总共存储了多少字符;
  • 7-8位用10进制表示存储的是多少号字体,
  • 9-xxxx*5位存储的是字符的unicode编码,为了节省存储空间,一个汉字采取的是u+4位unicode编码;例如"u3001u3002u30fbu02c9u02c7" 是“、。・ˉˇ”对应的存储;每个GB2312字符转化为5个字符进行存储。
  • xxxx*5+1至xxxx*8存储的是每个字符对应的取字模数据的16进制编码

举例来说,假设我们的字库只有一个 “ “ 字,用16号字体存储,那么它的整体内容如下:

00000116u597d100010fc10041008fc102420242025fe24204820282010202820442084a00040

如果用12好字体存储,那么存储内容如下::

00000112u597d200027c02040f880490049004fe091005100210051008b00

对比16号和12号字体::

000001  16  u597d   100010fc10041008fc102420242025fe24204820282010202820442084a00040
000001  12  u597d   200027c02040f880490049004fe091005100210051008b00

000001 表示 总共有1个字符 16和12表示存储的字号 u597d 是"好”字的unicode编码 再后面分别对应着

100010fc10041008fc102420242025fe24204820282010202820442084a00040

对应

{0x10,0x00,0x10,0xFC,0x10,0x04,0x10,0x08,0xFC,0x10,0x24,0x20,0x24,0x20,0x25,0xFE},
{0x24,0x20,0x48,0x20,0x28,0x20,0x10,0x20,0x28,0x20,0x44,0x20,0x84,0xA0,0x00,0x40},/*"好",0*/

200027c02040f880490049004fe091005100210051008b00

对应

{0x20,0x00,0x27,0xC0,0x20,0x40,0xF8,0x80,0x49,0x00,0x49,0x00,0x4F,0xE0,0x91,0x00},
{0x51,0x00,0x21,0x00,0x51,0x00,0x8B,0x00},/*"好",0*/

为了压缩存储内容,把0x10,0x00, 这种直接转化成了1000,这样的化,存储的内容就只有标志16进制格式的五分之二。

如果,这个字库存储的字符是 “你真好看啊!” ,它的整体内容如下::

00000612u4f60u771fu597du770bu554au00211400140027e024206940a10025402520252029202100230004007fc004003f8020803f8020803f802080ffe011002080200027c02040f880490049004fe091005100210051008b0003c07c0004007fc00800ffe020407fc0a0403fc020403fc00000eee0aa40abc0ad40ad40ab40abc0ea40ac40084008c0000000002000200020002000200000000000200000000000

经过整理后如下::

000006  12  u4f60   u771f   u597d   u770b   u554a   u0021   1400140027e024206940a10025402520252029202100230004007fc004003f8020803f8020803f802080ffe011002080200027c02040f880490049004fe091005100210051008b0003c07c0004007fc00800ffe020407fc0a0403fc020403fc00000eee0aa40abc0ad40ad40ab40abc0ea40ac40084008c0000000002000200020002000200000000000200000000000

掌握了这种格式的存储,就知道了如何获取到对应的内容,值得特别说明的是,为了方便计算,字模的16进制数据采取的是8位一个存储,12号字体其实可以认为是12*12个像素,但是存储的时候为了某种方便采取了16*12这种方式;所以一定程度来讲,这个字库还有压缩和提升性能的潜力可以挖掘;

在创建字库的时候,如果字符集里面有英文字母,将对英文字母补00进行操作,例如上面的"!" 它的unicode编码系统生产的是"u21",把它补0转换后就是"u0021". 字库中,字符的存储使用 ``u `` 一方面表示这是unicode 编码,另外一方面这个u也骑着分割符的重要作用,它能保证,这段编码被检索的时候不会重复,因为unicode编码不会一样,而如果没有使用 ``u `` ,只是存储 编码数字的话肯定会出现某个编码互相组合出现重复这种情况。

字模的格式

经过学习发现 TFT_eSPI 使用的vlw格式字库文件,其实是一种组合式的图片文件,而TFT_eSPI对于每个字符的显示其实就是动态取模。 本字库是提前对于字符取模,它采取把对应的字符画到图片上,然后获取每个位置的像素,每8个模 编码为16进制。取模顺序是从左到右,从上到下

软字库在单片机中的使用

字体文件在单片机中的使用,其实是一个逆向过程:

  • 上传生成的字库到单片机中
  • 输入要显示的汉字
  • 读取x.font文件,读取前6位,获得总共有多少个字符;
  • 再读取2位,确定字体对应的字号;
  • 读取unicode字符集,判断是否同输入汉字的unicode匹配
  • 利用匹配到的顺序,计算出字模的位置,依照字号获取对应长度的数据
  • 把字模的16进制编码重新编码为二进制
  • 利用TFT_eSPI 的 drawpix 方法把汉字输出到屏幕上(这里会有个方法计算能够显示多少汉字)
  • 字库调用完成
.. 注意:: 英文字符的特殊性暂未处理。

    由于英文基本都是半角符号,中文是全角符号,理论上英文的输出只有中文的一半,但是本字库暂时未处理英文的半角输出问题,全部是全角输出,后续再进行整理。

在终端输出

   String strBinDisplay = getPixBinStrFromString("这是一个软字体的显示你看看再多如何显示出来啊!你说你项羽突然的自我伍佰向天再借五百年");

    // 下面代码在终端输出文字点阵。
    Serial.println(strBinDisplay.length());
    for (int i = 0; i < strBinDisplay.length(); i++)
    {
        if (i % 16 == 0)
        Serial.print("\r\n");
        if (strBinDisplay[i] == '0')
        Serial.print(' ');
        if (strBinDisplay[i] == '1')
        Serial.print(strBinDisplay[i]);
    }

终端显示如下:::

   

           

           1

           1    111111  

           1         1  

           1        1  

        111111     1

          1  1    1

          1  1    1

          1  1 11111111

          1  1    1    

         1  1     1

          1 1     1

           1      1

          1 1     1

         1   1    1

        1    1  1 1

             1

           1     1

           1     1

           1     1      

        1111111  11111

          1     1    1

          1 1   1   1

         1  1  1  1

         111111   1

            1     1

            1    1 1

            111  1 1

        11111    1 1

         1  1   1   1

            1   1   1

            1  1     1

            1 1       1



 

通过单片机在tft屏幕显示


    // 下面代码在TFT屏幕输出文字
    int pX = 16;
    int pY = 0;
    int fontsize=16; //字号
    int amountDisplay=10; //每行显示多少汉字
    int singleStrPixsAmount=fontsize*fontsize;
    for (int i = 0; i < strBinDisplay.length(); i++)
    {
        // 这里必须有特别的说明,每个字符的像素点总数是singleStrPixsAmount=fontsize*fontsize,如果是16号字体就是256个;
        // 每行显示10个字,那么他们到一点阶段就必须换行,x坐标归0,y坐标必须加上字体对应的像素
        // 对于pX,每显示fontsize个像素后就必须字体归到起始点,注意每显示n字符后,这个起始点就必须加上fontsize*n这个起始值
        // 同时对于换行也必须处理。

        pX=int(i%fontsize)+int(i/(singleStrPixsAmount))*fontsize-int(i/(singleStrPixsAmount*amountDisplay))*fontsize*amountDisplay;

        // 对于pY,每fontsize个像素后+1,每singleStrPixsAmount个像素后归0,同时每换一行,pY要加上fontsize个像素;
        pY =int((i-int(i/singleStrPixsAmount)*singleStrPixsAmount)/fontsize)+int(i/(singleStrPixsAmount*amountDisplay))*fontsize;

        if (strBinDisplay[i] == '1')
        {
        tft.drawPixel(pX, pY, TFT_GREEN);
        }
    }

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/539502.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用 Android Studio 打包 uni-app 的安卓apk;手把手教程、巨详细避坑

Uni-app 离线打包 apk 1. Android Studio 下载 Android Studio官网 2. HBuilderX下载 HBuilderX下载 3. App离线SDK下载 Android 离线SDK - 正式版 下载后解压文件&#xff0c;将 HBuilder-Integrate-AS 重命名 build-template 并拷贝到一个专门打包用的文件夹下作为打包…

DETR类环境快速搭建

DINO下载地址&#xff1a; git clone https://github.com/IDEA-Research/DINO.gitconda create -n detr python3.8 -y修改写入权限 sudo chmod aw /home/ubuntu/.conda/激活环境 source activate detr安装pytorch conda install pytorch1.12.1 torchvision0.13.1 torchaudio…

OpenHarmony Docker移植实践

Docker简介 从操作系统诞生之日起&#xff0c;虚拟化技术就不断的演进与发展&#xff0c;结合目前云原生的发展态势&#xff0c;容器无疑是其中的重要一环。 Docker是一个开源的软件项目&#xff0c;可以在Linux操作系统上提供一层额外的抽象&#xff0c;让用户程序部署在一个相…

React面试题汇总 ---1

1.React的严格模式如何使用&#xff0c;有什么用处&#xff1f; React中StrictMode严格模式_react.strictmode_前端精髓的博客-CSDN博客当我们使用 npx create-react-app my-app 创建一个项目的时候。项目中有一段如下所示的代码&#xff1a;ReactDOM.render( <React.Stric…

SCADA数据采集与监控系统在制药生产过程中的应用

01 应用背景 制药行业关乎大众生命健康&#xff0c;在生产过程中各方面都要求遵循质量规范。制药行业虽然是一种流程化行业&#xff0c;但是和石油、化工等流程行业不同&#xff0c;行业特点决定了它的特殊性。根据质量规范要求&#xff0c;制药行业的SCADA需要满足国内GMP、欧…

David Silver Lecture 8: Integrating Learning and Planning

1 Introduction 1.1 Model based Reinforcement Learning 1.2 model based and model free RL 2 Model-Based Reinforcement Learning 2.1 outline 2.2 Learning a model 2.2.1 what is a model model主要是指&#xff0c;state transitions和相应的reward。 2.2.2 Model…

Fabric 超级账本学习【12】Hyperledger Fabric 2.4+Gin框架+Gateway 读取/写入账本数据 (Go版本)

文章目录 Fabric2.4Gin框架Gateway 读取/写入账本数据Gin框架优点Fabric-GatewayGateway搭建客户端我们需要准备哪些文件Gateway Client 为什么整个过程没有指定过背书节点?&#xff08;请求背书原理&#xff09;安装Gin前提条件成功部署Fabric2.4&#xff08;或其他版本的&am…

Qt 自定义窗口的标题栏,重写鼠标事件实现,隐藏窗口,最大化/最小化窗口,关闭窗口

Qt 自定义窗口的标题栏&#xff0c;重写鼠标事件实现&#xff0c;隐藏窗口&#xff0c;最大化/最小化窗口&#xff0c;关闭窗口 1、main.cpp #include "widget.h"#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widg…

ArcGis教程-画一幅城市的shp地图

怎样使用ArcGis10.6得到这么一幅shp地图呢&#xff1f; 首先打开ArcGis10.6&#xff0c;点击带黄底的小加号&#xff0c;添加底图。 可以选择中国地图彩色版&#xff0c;然后双击&#xff0c;转动鼠标滑轮找到属于自己的城市。 点击-目录&#xff0c;在新建的文件夹里右击-新建…

TS:如何判断联合类型变量的具体类型?

一 表示一个值可以是几种类型之一&#xff1a;联合类型 在TS中我们常会遇到这样一个问题。 一个变量&#xff0c;即可能是这种类型&#xff0c;也可能是那种类型&#xff0c;然后根据传入的类型的不同进行不同的操作。 比如下面这种情况&#xff1a; if (pet.name fish) {p…

三种灰狼优化算法(Grey Wolf Optimization)及仿真实验——附代码Matalb

目录 摘要&#xff1a; 灰狼算法原理&#xff1a; 灰狼算法流程&#xff1a; 改进的灰狼算法&#xff1a; 多目标的灰狼算法&#xff1a; 三种灰狼算法运行效果&#xff1a; &#xff08;1&#xff09;GWO &#xff08;2&#xff09;I-GWO &#xff08;3&#xff09;M…

Windows Server 2016 中文版、英文版下载 (updated May 2023)

Windows Server 2016 中文版、英文版下载 (updated May 2023) Windows Server 2016 Version 1607&#xff0c;2023 年 5 月更新 请访问原文链接&#xff1a;https://sysin.org/blog/windows-server-2016/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者…

4.7 树的实现(上)

树 树&#xff08;Tree&#xff09;是n&#xff08;n≥0&#xff09;个节点的有限集合T&#xff0c;它满足两个条件 &#xff1a; 有且仅有一个特定的称为根&#xff08;Root&#xff09;的节点&#xff1b; 其余的节点可以分为m&#xff08;m≥0&#xff09;个互不相交的有…

电子企业WMS仓储管理系统解决方案

随着科技的飞速发展&#xff0c;电子制造行业对仓储管理系统的需求也越来越高。电子企业需要一种能够规划、执行和优化仓库货物流通的IT解决方案&#xff0c;以实现自动化操作和提高效率。本文将探讨电子企业WMS仓储管理系统解决方案&#xff0c;从需求分析、系统设计、实施与运…

在Windows系统中安装Wireshark(图文)

1.打开Wireshark官网后&#xff0c;点Get Acquainted->Download后进入到下载界面&#xff0c;在Stable Release中选择下载Windows 64位的安装包&#xff0c;单击Windows Installer(64-bit) 下载。 2.双击下载的安装包&#xff0c;如下图&#xff0c;点击Next。 3.点Noted&am…

ELK的安装部署与使用

ELK的安装与使用 安装部署 部署环境&#xff1a;Elasticsearch-7.17.3 Logstash-7.17.3 Kibana-7.17.3 一、安装部署Elasticsearch 解压目录&#xff0c;进入conf目录下编辑elasticsearch.yml文件&#xff0c;输入以下内容并保存 network.host: 127.0.0.1 http.port: 9200…

基于相似加权自组装框架的低质量少样本MRI脑卒中病变分割

文章目录 Stroke Lesion Segmentation from Low-Quality and Few-Shot MRIs via Similarity-Weighted Self-ensembling Framework摘要本文方法Soft Distribution-aware Updating (SDU) 实验结果 Stroke Lesion Segmentation from Low-Quality and Few-Shot MRIs via Similarity…

蓝桥杯模块学习5——按键

第一章 硬件部分 1.1 电路的组成部分 1.1.1 按键电路 原理图&#xff1a; 功能&#xff1a; &#xff08;1&#xff09; J5&#xff1a;当1和2相接&#xff0c;电路就变成一个4*4的矩阵键盘电路&#xff1b;当2和3相接时&#xff0c;电路变成了一个S4-S7的独立按键&#xf…

平板触控笔要原装的吗?苹果平替笔性价比高的推荐

与苹果的电容笔不同&#xff0c;市场上的电容笔只会给人一种倾斜的压感&#xff0c;并不会像苹果的电容笔那样&#xff0c;可以给人一种重力的压感。不过&#xff0c;如果你不一定要画画&#xff0c;那你就不用花很多钱去买一支苹果的原装电容笔了&#xff0c;只需一支平替电容…

ss命令使用详解

ss是Socket Statistics的缩写。顾名思义&#xff0c;ss命令可以用来获取socket统计信息&#xff0c;它可以显示和netstat类似的内容。ss的优势在于它能够显示更多更详细的有关TCP和连接状态的信息&#xff0c;而且比netstat更快速更高效。 当服务器的socket连接数量变得非常大…