字符编码
字符编码及转换测试:http://www.qqxiuzi.cn/daohang.htm
这个网站可以查询汉字字符编码,如下图所示:
输入汉字,就可以查询字符编码:
ASCII 编码
ASCII编码(单字节),标准ASCII编码只使用了0 ~ 127,而128 ~ 255属于扩展编码,不属于标准ASCII。
不可见编码(0 ~ 31):
可见字符编码(32 ~ 127):
GB2312编码
全角和半角的区别(一般都使用半角,很少使用全角):
角就是字母和数字等与汉字占等宽位置的字。 半角就是ASCII方式的字符,在没有汉字输入法起作用的时候输入的字母数字和字符都是半角的。
例如,字符B,全角GB2312编码为A3C2,半角ASCII编码为0X42。
GB2312兼容ASCII编码:
区位码表示:
区位码转成GB2312(GB2312从160 = 0XA0开始编码),要把区号和位号都偏移160(即 + 0XA0),得到GB2312编码:
计算实例:
GB2312的部分区位表:
GBK编码
GBK编码,加入了更多的繁体字和生僻字,同时兼容了GB2312编码:
GB18030编码
Big5编码,港台地区使用
Unicode 字符集和编码
Unicode编码的出现,为了统一全世界不同的字符。Unicode把这些字符进行编号,而没有进行编码。
编号和编码的区别?
如字符 'A' ,在ASCII中为0X41 = 65,也就是说, 'A' 的编号是65,而ASCII的编码是一个字节0X41,也可以用两个字节表示
0X 00 41,或者三个字节表示 0X 00 00 41。编号就是 0 1 2 3这些简单的数字,而编码实际上是编成了计算机二进制码。编码要包含 (到底是一个字节表示,或者两个字节表示,或者数据大小端)等信息。
Unicode编号和GB2312汉字编码的区别:
Unicode 字符编码格式
不同风格的Unicode编码描述:
UTF-32(直接把编号和编码同等对应,使用4字节)
可以看到,UTF-32编码,对于使用英语地区的国家,实际上是非常不友好的,原来使用单字节能表示的字符,为了兼容Unicode,现在要使用4个字节存储,增加了3倍的存储空间。还有,Unicode产生之前的那些文件,就统统失效不能使用。所以,UTF-32根本无法推行。
注意,UTF-32并不兼容ASCII编码,如采用UTF-32,会使得原来老的文件全部乱码,所以无法推广。
UTF-16
UTF-8 编码
完全兼容了ASCII编码,也使用了变长编码,可以节省存储空间。但对于中文而言,GB2312编码使用2字节,而UTF-8平均要使用3字节,所以有些网站为了节省存储空间,还是采样了GB2312编码格式。
UTF-8编码思路:
BOM 编码格式
字模原理
字模的原理:
字模的构成:
如果采用的是 16*16 点阵显示,每个字模要占用32字节的空间。如果是英文,总共128个字符,占用的空间为 4KB。而常用的中文汉字有6000+,用字模表示,大概要占用200KB的空间,这对存储容量的要求是非常大的。
字模的生成(使用软件PCtoLCD2002):
生成的字模数据为:
{0x02,0x00,0x01,0x00,0x7F,0xFE,0x40,0x02,0x80,0x04,0x1F,0xE0,0x00,0x40,0x00,0x80,0x01,0x00,0xFF,0xFE,0x01,0x00,0x01,0x00},
{0x01,0x00,0x01,0x00,0x05,0x00,0x02,0x00},/*"字",0*/
根据生成的字模数据,我们利用串口打印来验证一下,是否图形显示正确:
/* 生成的字模数据 */
uint8_t test_module[] = {0x02,0x00,0x01,0x00,0x7F,0xFE,0x40,0x02,0x80,0x04,
0x1F,0xE0,0x00,0x40,0x00,0x80,0x01,0x00,0xFF,0xFE,0x01,0x00,0x01,0x00,
0x01,0x00,0x01,0x00,0x05,0x00,0x02,0x00}; /*"字",0*/
void Display_char_test(void)
{
uint8_t i = 0, j = 0, k = 0;
/* 字模数据有16行 */
for (i = 0; i < 16; i++)
{
/* 每行16列,2字节 */
for (j = 0; j < 2; j++)
{
/* 每个字节8位 */
for (k = 0; k < 8; k++)
{
/* 对每个数据字节从高位到低位进行遍历 */
if ((test_module[i * 2 + j] & (0X80 >> (k))) != 0)
{
printf("*");
}
else
{
printf(" ");
}
}
}
printf("\n");
}
}
串口打印结果如下:
联想到之前液晶显示的程序,液晶显示的原理就是开窗,然后不断的填入16位颜色数据(RGB565格式),如果按照串口输出的做法,在字模数据为为 1 处显示白色,为 0 处显示黑色,就可以打印字模对应的文字(黑底白字)。
/**
* @brief 画一个实心的矩形
*/
void ILI9341_Darw_Rec(void)
{
uint32_t i = 0;
ILI9341_Open_Window(10, 20, 50, 100);
ILI9341_Write_Cmd(CMD_SetPixel); // 填充像素
for (i = 0; i < 50 * 100; i++)
{
ILI9341_Write_Data(RGB888_TO_RGB565(0, 255, 0)); // 对应绿色
}
}
现在还剩下一个问题,如果我们希望在程序中直接给出一个字符串,液晶屏就能显示出来,怎么做?
一个能想到的处理方式就是,在数组中添加很多个字的字模,然后想要显示那个字,直接加上对应的偏移就可以,如下:
/* 生成的字模数据 */
uint8_t test_module[] = {
0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x3F,0xF8,0x21,
0x08,0x21,0x08,0x21,0x08,0x21,0x08,0x21,0x08,0x3F,0xF8,
0x21,0x08,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00, /* 中 */
0x00,0x00,0x7F,0xFC,0x40,0x04,0x40,0x04,0x5F,0xF4,0x41,
0x04,0x41,0x04,0x4F,0xE4,0x41,0x04,0x41,0x44,0x41,0x24,
0x5F,0xF4,0x40,0x04,0x40,0x04,0x7F,0xFC,0x40,0x04 /* 国 */
};
void Display_char_test(void)
{
uint8_t i = 0, j = 0, k = 0;
/* 字模数据有16行 */
for (i = 0; i < 16; i++)
{
/* 每行16列,2字节 */
for (j = 0; j < 2; j++)
{
/* 每个字节8位 */
for (k = 0; k < 8; k++)
{
/* 对每个数据字节从高位到低位进行遍历 */
if ((test_module[ 32 + i * 2 + j] & (0X80 >> (k))) != 0)
{
printf("*");
}
else
{
printf(" ");
}
}
}
printf("\n");
}
}
当使用偏移(+32)时,就可以显示第二个汉字,这样就可以打印多个文字。
如何制作字模
根据使用要求制作字模
如何建立映射关系?
比如GB2312汉字编码,如果每个字符是32字节(16*16点阵),如果想显示两个字,只要适当的安排偏移,每个汉字占的字模大小都是32字节,这样只需要算好偏移就可以。如果按照GB2312编码表来安排,如第 0 ~ 31字节存储“啊”,第 32 ~ 63字节存储“阿”,第64 ~ 95字节存储“埃”...,我们希望能制作出这样的字模,字模中包含我们需要的编码表的所有字符且有固定映射。
我们希望实现的函数:
ILI9341_DispStringLine_EN_CH(LINE(2),"ILI9341液晶驱动");
如果能把字符串对应的转换成字符编码,那么就能直接输入字符串,再调用lcd屏来显示。怎么把字符串转换成编码?这个和MDK软件的配置有关。按照GB2312的编码规则,像前面的ILI9341都是单字节编码,而汉字液晶驱动就会对应的转成双字节的GB2312编码。我们就可以直接通过字符串的形式,编写一个函数,根据他的编码,来找到字模数据。一旦找到字模数据,后面就好办了,直接根据之前的字模显示原理,打印出字模。
如何生成字库?
PCtoLCD软件的配置:
设置字模显示区域大小和字模大小:
字模寻址公式推导:
先看ASCII表的字模寻址,这个相对比较简单(每个字模固定16字节):
我们制作的字模数组,从空格开始,接下来的字符依次偏移 16 字节。所以,ASCII字库中,每个字符的起始索引计算:
索引下标计算公式:('A' - ' ') * 16 相对于空格的偏移 * 每个字符的大小。
GB2312字模(区位码):
每个字模的大小为:16 * 16 / 8 = 32字节
第 0 个字节存储的是空格,根据区号和位号,求出字符相对于空格的偏移,然后*字符大小,就能求出数组下标索引。
区位码转成GB2312(GB2312从160 = 0XA0开始编码),要把区号和位号都偏移160(即 + 0XA0),得到GB2312编码:
计算公式如下:
像这种字符串,编译器会根据mdk设置,把英文编译成ASCII编码,把中文编译成GB2312编码,如下:
ILI9341_DispStringLine_EN_CH(LINE(2),"ILI9341液晶驱动");