TFT-LCD显示中英文
在前面编写了屏幕显示ASCII字符和字符串后,本次实现屏幕显示中文字符和中文字符串
中文字符取模
阴码,逐行式,逆向,十六进制数,C51格式,
输入要显示的中文字符,字体选择宋体,字宽x字高为16x16,也可以选择其他大一点的格式,字体大小不同,后续代码中要进行相应的修改
代码
font_CHN.h
用一个头文件存放字模数据,因为中文数据不同于ASCII码,ASCII码字符是有规律的,在代码中减去首个字符就能得到想要的ASCII码字符,但中文没有,所以要解决的就是当参数传入要显示的中文字符指针时,该怎么去字模数组中找到对应中文字符的字模数据
方法:定义一个结构体类型,里面有两个数组,第一个数组是中文字符的索引,后续代码中就通过这个索引查找中文字符的位置,第二个数组就是对应中文字符的字模数据,这个数组的大小要根据中文字符的字模数据的个数来定,比如16x16大小的字符的字模数据有32个(一个一个数),所以该数组大小就为32,如果是24x24的大小,则该数组大小要为72
用该结构体类型定义一个数组,存放字符索引和字模数据,用const修饰,放到芯片的内部Flash区
/**
* 16号中文字符集
* 宽x高:16x16
* 字体:宋体
* 逐行式(从第一行开始向右每取8个点作为一个字节,不足8个点就补0)
* 逆向(取模顺序从低到高,即第一个点作为最低位)
*/
typedef struct
{
uint8_t ucIndex[2];
uint8_t ucCHN_Code[32]; //该数组要根据一个中文字符的字模数据有多少个,来定义大小
}FONT_CHN16_t;
const FONT_CHN16_t ucCHN_CHN16[] = {
{{"时"},{0x00,0x10,0x00,0x10,0x3E,0x10,0x22,0x10,0xA2,0x7F,0x22,0x10,0x22,0x10,0x3E,0x10,0x22,0x11,0x22,0x12,0x22,0x12,0x22,0x10,0x3E,0x10,0x22,0x10,0x00,0x14,0x00,0x08}},/*"时",0*/
{{"间"},{0x04,0x00,0xC8,0x3F,0x08,0x20,0x02,0x20,0xE2,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0xE2,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0xE2,0x23,0x02,0x20,0x02,0x28,0x02,0x10}},/*"间",1*/
{{"不"},{0x00,0x00,0xFE,0x3F,0x00,0x01,0x00,0x01,0x80,0x00,0x80,0x00,0xC0,0x02,0xA0,0x04,0x90,0x08,0x88,0x10,0x84,0x20,0x82,0x20,0x81,0x00,0x80,0x00,0x80,0x00,0x80,0x00}},/*"不",2*/
{{"在"},{0x40,0x00,0x40,0x00,0x20,0x00,0xFF,0x7F,0x10,0x00,0x10,0x02,0x08,0x02,0x0C,0x02,0xEA,0x3F,0x09,0x02,0x08,0x02,0x08,0x02,0x08,0x02,0x08,0x02,0xF8,0x7F,0x08,0x00}},/*"在",3*/
{{"于"},{0x00,0x00,0xFC,0x1F,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xFF,0x7F,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0xA0,0x00,0x40,0x00}},/*"于",4*/
{{"你"},{0x10,0x01,0x10,0x01,0x10,0x01,0x88,0x7F,0x88,0x40,0x4C,0x20,0x2C,0x04,0x0A,0x04,0x89,0x14,0x88,0x24,0x48,0x24,0x48,0x44,0x28,0x44,0x08,0x04,0x08,0x05,0x08,0x02}},/*"你",5*/
{{"拥"},{0x04,0x00,0xE4,0x3F,0x24,0x22,0x24,0x22,0x3F,0x22,0xE4,0x3F,0x24,0x22,0x34,0x22,0x2C,0x22,0xE7,0x3F,0x24,0x22,0x24,0x22,0x24,0x22,0x14,0x22,0x15,0x2A,0x0A,0x10}},/*"拥",6*/
{{"有"},{0x40,0x00,0x40,0x00,0xFF,0x7F,0x20,0x00,0x20,0x00,0xF0,0x0F,0x10,0x08,0x18,0x08,0xF4,0x0F,0x12,0x08,0x11,0x08,0xF0,0x0F,0x10,0x08,0x10,0x08,0x10,0x0A,0x10,0x04}},/*"有",7*/
{{"多"},{0x40,0x00,0x40,0x00,0xE0,0x0F,0x10,0x04,0x1C,0x02,0x20,0x01,0xC0,0x02,0x30,0x01,0x8E,0x1F,0x40,0x10,0x30,0x08,0x4C,0x04,0x80,0x02,0x80,0x01,0x70,0x00,0x0E,0x00}},/*"多",8*/
{{"少"},{0x80,0x00,0x80,0x00,0x80,0x00,0x90,0x04,0x90,0x08,0x88,0x10,0x88,0x20,0x84,0x28,0x82,0x08,0x80,0x04,0x00,0x02,0x00,0x01,0x80,0x00,0x40,0x00,0x30,0x00,0x0E,0x00}},/*"少",9*/
{{"而"},{0x00,0x00,0xFE,0x3F,0x80,0x00,0x80,0x00,0x40,0x00,0xFC,0x1F,0x24,0x11,0x24,0x11,0x24,0x11,0x24,0x11,0x24,0x11,0x24,0x11,0x24,0x11,0x24,0x11,0x04,0x14,0x04,0x08}},/*"而",10*/
{{"怎"},{0x10,0x00,0x10,0x00,0xF0,0x3F,0x28,0x00,0x24,0x00,0xE2,0x0F,0x20,0x00,0x20,0x00,0xE0,0x1F,0x20,0x00,0x80,0x00,0x10,0x21,0x12,0x49,0x12,0x48,0xE1,0x0F,0x00,0x00}},/*"怎",11*/
{{"么"},{0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x20,0x02,0x10,0x02,0x08,0x01,0x04,0x01,0x82,0x00,0x40,0x00,0x20,0x04,0x10,0x08,0x08,0x10,0xFC,0x3F,0x08,0x20,0x00,0x00}},/*"么",12*/
{{"使"},{0x08,0x02,0x08,0x02,0xF8,0x7F,0x04,0x02,0x04,0x02,0xE6,0x3F,0x26,0x22,0x25,0x22,0xE4,0x3F,0x04,0x02,0x44,0x02,0x84,0x02,0x04,0x01,0x84,0x02,0x44,0x0C,0x34,0x70}},/*"使",13*/
{{"用"},{0x00,0x00,0xFC,0x1F,0x84,0x10,0x84,0x10,0x84,0x10,0xFC,0x1F,0x84,0x10,0x84,0x10,0x84,0x10,0xFC,0x1F,0x84,0x10,0x84,0x10,0x84,0x10,0x82,0x10,0x82,0x14,0x01,0x08}}/*"用",14*/
};
TFT_LCD.h
在LCD的头文件中定义中文字符大小的枚举类型
//定义汉字字体枚举类型
typedef enum
{
CHN_font_16 = 16,
CHN_font_24 = 24
}CHN_font_t;
//断言宏定义
#define IS_CHN_FONT(font) (((font) == CHN_font_16) || ((font) == CHN_font_24))
TFT_LCD.c
编写显示一个中文字符的函数,原理与显示一个ASCII码字符一样,都是找到对应的字符,然后遍历该字符的字模数据,为1则显示字体颜色,为0则显示背景颜色
/**
* @name LCD_ShowCHN
* @brief LCD屏幕显示一个中文字符
* @param usXstar:窗口起点x轴坐标
* usYstar:窗口起点y轴坐标
* pcStr:要显示的英文字符串
* usColor_Background:选择英文字符的背景色
* usColor_Foreground:选择英文字符的前景色
* font:字体选择 参数:CHN_font_16 :16号字体;CHN_font_24 :24号字体
* @retval None
*/
static void LCD_ShowCHN(uint16_t usXstar,
uint16_t usYstar,
const char* pcStr,
uint16_t usColor_Background,
uint16_t usColor_Foreground,
CHN_font_t font)
{
uint8_t ucTemp,ucPage,ucColumn;
uint16_t usIndex; //字库中汉字的索引
uint16_t usCHN_Num; //字库中汉字数量
//检查参数是否合法
assert_param(IS_CHN_FONT(font));
//判断字体-16号字体
if(font == CHN_font_16)
{
//统计汉字数量
usCHN_Num = sizeof(ucCHN_CHN16)/sizeof(FONT_CHN16_t); //字模数组大小除以结构体大小,得到汉字的个数
//for循环判断汉字位置
for(usIndex=0;usIndex<usCHN_Num;usIndex++)
{
//判断结构体数组的汉字索引数组是否与要显示的中文字符一致,中文字符占两个字节,先判断第一个字符,再判断第二个字符
if((ucCHN_CHN16[usIndex].ucIndex[0] == *pcStr)&&(ucCHN_CHN16[usIndex].ucIndex[1] == *(pcStr+1)))
{
//设置窗口,大小为16x16
LCD_SetWindows(usXstar,usYstar,16,16);
//逐行写入数据,共16行,每行16个像素点
for(ucPage=0;ucPage<32;ucPage++)
{
//从ASCII字符集数组获取像素数据
//像素点数据为1时,写入字符颜色,为0时,写入背景颜色
ucTemp = ucCHN_CHN16[usIndex].ucCHN_Code[ucPage];
for(ucColumn=0;ucColumn<8;ucColumn++)
{
if((ucTemp & BIT0) == BIT0)
{
LCD_WRITE_DATA(usColor_Foreground);
}
else
{
LCD_WRITE_DATA(usColor_Background);
}
ucTemp >>= 1;
}
}
break; //已经找到并显示了字符,退出循环
}
}
}
//判断字体-24号字体
if(font == CHN_font_24)
{
//统计汉字数量
usCHN_Num = sizeof(ucCHN_CHN24)/sizeof(FONT_CHN24_t); //字模数组大小除以结构体大小,得到汉字的个数
//for循环判断汉字位置
for(usIndex=0;usIndex<usCHN_Num;usIndex++)
{
//判断结构体数组的汉字索引数组是否与要显示的中文字符一致,中文字符占两个字节,先判断第一个字符,再判断第二个字符
if((ucCHN_CHN24[usIndex].ucIndex[0] == *pcStr)&&(ucCHN_CHN24[usIndex].ucIndex[1] == *(pcStr+1)))
{
//设置窗口,大小为24x24
LCD_SetWindows(usXstar,usYstar,24,24);
//逐行写入数据,共24行,每行72个像素点
for(ucPage=0;ucPage<72;ucPage++)
{
//从ASCII字符集数组获取像素数据
//像素点数据为1时,写入字符颜色,为0时,写入背景颜色
ucTemp = ucCHN_CHN24[usIndex].ucCHN_Code[ucPage];
for(ucColumn=0;ucColumn<8;ucColumn++)
{
if((ucTemp & BIT0) == BIT0)
{
LCD_WRITE_DATA(usColor_Foreground);
}
else
{
LCD_WRITE_DATA(usColor_Background);
}
ucTemp >>= 1;
}
}
break; //已经找到并显示了字符,退出循环
}
}
}
}
通过结构体类型的第一个索引数组找到对应的中文字符就是下面这一条语句
//判断结构体数组的汉字索引数组是否与要显示的中文字符一致,中文字符占两个字节,先判断第一个字符,再判断第二个字符
if((ucCHN_CHN24[usIndex].ucIndex[0] == *pcStr)&&(ucCHN_CHN24[usIndex].ucIndex[1] == *(pcStr+1)))
编写一个显示中英文字符串的函数
如何区分ASCII码字符和中文字符?
ASCII码取模范围一般是32 - 126,即空格到~,最后一个ASCII码字符为del,其十进制为127,所以编码在127之前的都属于ASCII码字符,汉字占两个字节,而汉字为了与ASCII码区分开,第一个字节的最高位是为1的,十进制肯定大于127,所以区分ASCII码和汉字就可以判断字符是否小于0x80,小于的就为ASCII码,大于或等于的就为汉字
/**
* @name LCD_ShowCHNandENGString
* @brief LCD屏幕显示中英文字符串
* @param usXstar:窗口起点x轴坐标
* usYstar:窗口起点y轴坐标
* pcStr:要显示的英文字符串
* usColor_Background:选择英文字符的背景色
* usColor_Foreground:选择英文字符的前景色
* CHN_font:中文字体 参数:CHN_font_16 :16号字体;CHN_font_24 :24号字体
* ASCII_font:英文字体 参数:ASCII_font_16 :16号字体;ASCII_font_24 :24号字体
* @retval None
*/
static void LCD_ShowCHNandENGString(uint16_t usXstar,
uint16_t usYstar,
const char* pcStr,
uint16_t usColor_Background,
uint16_t usColor_Foreground,
CHN_font_t CHN_font,
ASCII_font_t ASCII_font)
{
while(*pcStr != '\0')
{
//中文字符
if(*(pcStr) > 127)
{
//自动换行
if((usXstar+CHN_font) > LCD_WIGHT)
{
usXstar = 0;
usYstar += CHN_font;
}
//自动换页
if((usYstar+CHN_font) > LCD_HIGHT)
{
usXstar = 0;
usYstar = 0;
}
//显示中文字符
TFT_LCD.LCD_ShowCHN(usXstar,usYstar,pcStr,usColor_Background,usColor_Foreground,CHN_font);
//更新位置
pcStr += 2; //下一个中文字符
usXstar += CHN_font; //坐标位置加上一个字符间隔
}
//英文字符
else
{
if((*pcStr == '\r') || (*pcStr == '\n'))
{
//前面的字符为中文
if(*(pcStr-1) > 127)
{
//换行
usXstar = 0;
usYstar += CHN_font;
}
//前面的字符为英文
else
{
//换行
usXstar = 0;
usYstar += ASCII_font;
}
}
else
{
//自动换行
if((usXstar+ASCII_font/2) > LCD_WIGHT)
{
usXstar = 0;
usYstar += ASCII_font;
}
//自动换页
if((usYstar+ASCII_font) > LCD_HIGHT)
{
usXstar = 0;
usYstar = 0;
}
//显示英文字符
TFT_LCD.LCD_ShowChar(usXstar,usYstar,*pcStr,usColor_Background,usColor_Foreground,ASCII_font);
//更新位置
usXstar += ASCII_font/2; //坐标位置加上一个字符间隔
}
pcStr++; //指向下一个字符
}
}
}
System.c
系统运行函数中调用显示中英文字符串显示中文,这次并没有显示英文,而且中文字体大小为24x24
/*
* @name Run
* @brief 系统运行
* @param None
* @retval None
*/
static void Run()
{
TFT_LCD.LCD_ShowCHNandENGString(25,70,"时间",Color_BLACK,Color_WHITE,CHN_font_24,ASCII_font_16);
TFT_LCD.LCD_ShowCHNandENGString(25,120,"不在于你拥有多少",Color_BLACK,Color_WHITE,CHN_font_24,ASCII_font_16);
TFT_LCD.LCD_ShowCHNandENGString(25,170,"而在于你怎么使用",Color_BLACK,Color_WHITE,CHN_font_24,ASCII_font_16);
}