[其他ST产品]

stm32+lcd显示汉字之GBK编码

[复制链接]
560|18
手机看帖
扫描二维码
随时随地手机跟帖
rzjvv|  楼主 | 2022-11-26 23:19 | 显示全部楼层 |阅读模式
最近在搞LCD显示汉字、特殊图形的问题。以前玩1602的时候自己做过字模,就是通过1602自带的用户DIY的一个存储点阵区CGROM,把做好的字模转化成点阵的数据存储在CGROM中,最后把汉字显示在1602上面。但是当时是用51做的,而且字模地址是固定存储在1602中的,我们不用去管。在stm32+TFTLCD显示汉字这个实验上面,我的思路还是这个样子,就是做好字模,然后根据地址找到对应汉字的点阵数据。那么问题来了,在1602中每个字模都有自己的显示编码,那么在stm32中,汉字有自己的显示编码吗?

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:21 | 显示全部楼层
数组和字符串的关系

在说汉字的显示编码之前,我想先讲一下数组和字符串的关系。字符串我们可以把它当成一种特殊的数组,编译器识别到字符串时,会自动把它的地址分配到stm32的Flash里面,这就意味着字符串本身就是一个常量。字符串的定义是用双引号括起来的一段字符数据,这段数据最后会自动加上一个空字符为结尾(‘\0’)。我们这里直接上程序:

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:22 | 显示全部楼层
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "string.h"

char arrBuf_1[3] = {'f','a','t'};
char arrBuf_2[4] = {'f','a','t','\0'};
char strBuf_1[]  = "fat";


int main(void)
{
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
        delay_init(168);  //初始化延时函数
        uart_init(115200);//初始化串口波特率为115200
       
        if(!strcmp(arrBuf_1,strBuf_1))
                {printf("arrBuf_1 与 strBuf_1 相等\r\n");}
        else if(!strcmp(arrBuf_2,strBuf_1))
                {printf("arrBuf_2 与 strBuf_1 相等\r\n");}
        else
                {printf("数组与字符串均不相等\r\n");}
               
        printf("arrBuf_1的地址为:0x%x\r\n",arrBuf_1);
        printf("arrBuf_2的地址为:0x%x\r\n",arrBuf_2);
        printf("strBuf_1的地址为:0x%x\r\n",strBuf_1);
       
        printf("arrBuf_1中'f'字符常量的地址为:0x%x\r\n",*arrBuf_1);
        printf("arrBuf_2中'f'字符常量的地址为:0x%x\r\n",*arrBuf_2);
        printf("strBuf_1中'f'字符常量的地址为:0x%x\r\n",*strBuf_1);
               
       
        while(1);
       
        return 0;
}

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:23 | 显示全部楼层
一个数组的数组名,就是指向该数组第一位成员的地址的指针,所以我们打印数组名,就是打印该数组第一个成员的地址,解除该指针则打印的是该地址里保存的值,对应程序而言就是’f’的ASCII码值,以16进制形式体现。

通过简单的比较我们可以看到,字符串就是把每个字符转化成单引号字符常量,存储在对应的数组成员中,且最后一位自动加入’\0’空字符表示结尾。上面三个数组的地址是不同的,但是每个数组中存储的单引号字符常量的值却是相同的,这就说明单引号字符常量在keil编译器下,被自动识别为对应的ASCII码值。ASCII码值我们大可以理解为每个字符的显示编码。

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:24 | 显示全部楼层
GBK码

keil这个编译器会自动把有ASCII码值的字符常量识别为对应的ASCII码值,没有对应ASCII码值的常量比如汉字日语等,我们也有一套特殊的编码来表示,这个编码就是GBK码。

GBK码有16位,两个字节组成。

1583463822f8f83afe.png

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:25 | 显示全部楼层
高字节的范围为:0x81~0xFE,每一位都称为一个区,总共有126个区。
低字节的范围为:0x40~0x7E , 0x80~0xFE,低字节总共由两部分构成,每一位都称为一个段,总共有190个段。

GBK码有126个区,190个段,每一个区的每一个段都可以表示一个汉字,那么GBK码总共可以表示126 * 190 = 23940 个汉字。足以满足我们大多数场景下的使用。在keil环境下,编译器自动的将汉字识别为对应的GBK码。

但是GBK码只是一个显示编码,每个显示编码对应的字模还是要由我们来做,做好以后我们把存储汉字字符的字模(点阵)的数组称为GBK库(这个有很多软件可以帮我们生成)。

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:26 | 显示全部楼层
但是要从这个库里找到对应的汉字,就需要知道每个汉字在这个库里的偏移量,通过每个汉字的GBK码,我们可以算出来对应的偏移量:
当GBKL < 0x7F时,HP = ((GBKH - 0x81)*190+GBKL-0x40) * (size * 2)
当GBKL > 0x7F时,HP = ((GBKH - 0x81)*190+GBKL-0x41) * (size * 2)
GBKH 为高字节,GBKL 为低字节,低字节的两部分中间有个断层0x7F,所以要分情况判断其偏移。HP即为求出的汉字显示编码在GBK库中的偏移量,size为显示汉字的大小。

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:27 | 显示全部楼层
我们这里举个例子,以字符串“你好啊”为例,分析每个汉字的GBK码:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "string.h"

char arrBuf_1[3] = {'f','a','t'};
char arrBuf_2[4] = {'f','a','t','\0'};
char strBuf_1[]  = "fat";
const char* strBuf_2 = "你好啊";

int main(void)
{
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
        delay_init(168);  //初始化延时函数
        uart_init(115200);//初始化串口波特率为115200
       
        if(!strcmp(arrBuf_1,strBuf_1))
                {printf("arrBuf_1 与 strBuf_1 相等\r\n");}
        else if(!strcmp(arrBuf_2,strBuf_1))
                {printf("arrBuf_2 与 strBuf_1 相等\r\n");}
        else
                {printf("数组与字符串均不相等\r\n");}
               
        printf("arrBuf_1的地址为:0x%x\r\n",arrBuf_1);
        printf("arrBuf_2的地址为:0x%x\r\n",arrBuf_2);
        printf("strBuf_1的地址为:0x%x\r\n",strBuf_1);
       
        printf("arrBuf_1中'f'字符常量的地址为:0x%x\r\n",*arrBuf_1);
        printf("arrBuf_2中'f'字符常量的地址为:0x%x\r\n",*arrBuf_2);
        printf("strBuf_1中'f'字符常量的地址为:0x%x\r\n",*strBuf_1);
               
        printf("strBuf_2汉字常量‘你’的GBK码高位码为:0x%x\r\n",*strBuf_2);
        printf("strBuf_2汉字常量‘你’的GBK码低位码为:0x%x\r\n",*(strBuf_2+1));
        printf("strBuf_2汉字常量‘好’的GBK码高位码为:0x%x\r\n",*(strBuf_2+2));
        printf("strBuf_2汉字常量‘好’的GBK码低位码为:0x%x\r\n",*(strBuf_2+3));
        printf("strBuf_2汉字常量‘啊’的GBK码高位码为:0x%x\r\n",*(strBuf_2+4));
        printf("strBuf_2汉字常量‘啊’的GBK码低位码为:0x%x\r\n",*(strBuf_2+5));
       
        while(1);
       
        return 0;
}

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:28 | 显示全部楼层
1876963823064b5f6c.png

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:28 | 显示全部楼层
strBuf_2为指针名(数组名),指向第一个成员的地址,解除运算以后就是第一个成员的值,对应汉字即为GBK码,因为GBK码为16位,所以我们连续打印6个字节的数据,每两个组合即为对应汉字的GBK码值。然后我们根据得到的GBK码值,带入上面的公式,算出来每个汉字在GBK库里的偏移量,根据每个汉字在GBK库中的偏移量,我们就可以定位到具体的汉字。

使用特权

评论回复
rzjvv|  楼主 | 2022-11-26 23:29 | 显示全部楼层
以上就是汉字显示的基本原理了,下一篇文章给大家介绍一下显示汉字的步骤,在EEPROM上建立自己的字库,以及如何在LCD上显示特殊图形(自己DIY)。

使用特权

评论回复
10299823| | 2022-12-14 10:48 | 显示全部楼层
搞LCD显示汉字,需要存储控件太大了。

使用特权

评论回复
sdlls| | 2022-12-15 16:04 | 显示全部楼层
GBK转unicode吗?              

使用特权

评论回复
mattlincoln| | 2022-12-15 20:02 | 显示全部楼层
这个字模存储在哪里呢?              

使用特权

评论回复
jtracy3| | 2022-12-17 12:17 | 显示全部楼层
汉字库的代码可以使用flash存储的吗?

使用特权

评论回复
pixhw| | 2022-12-17 14:36 | 显示全部楼层
感觉stm32驱动lcd的速度还是可以的。

使用特权

评论回复
Undshing| | 2022-12-17 16:22 | 显示全部楼层
这个字模存储在哪里?

使用特权

评论回复
jkl21| | 2022-12-17 20:30 | 显示全部楼层
这个是不是需要查表才能实现呢?              

使用特权

评论回复
AloneKaven| | 2022-12-18 18:24 | 显示全部楼层
字模存储在flash里啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

11

主题

97

帖子

0

粉丝