参考博客
https://blog.csdn.net/dingyc_ee/article/details/100746406
https://blog.csdn.net/dingyc_ee/article/details/102651664
之前写了关机计算机字符编码、液晶显示字符串原理的知识,以及如何利用PCtoLCD生成中英文字库数据,接下来分析如何利用代码来驱动液晶屏显示中英文。
英文显示
由于英文字符比较少,可以直接通过 const 关键字,字库本质上就是一个uint8_t类型的大数组,将字库数据存储到stm32的内部Flash中。我们提前制作了好几种不同大小的英文字库(8*16,16*24,24*32),下面为16*8字库数组:
/*
* 常用ASCII表,偏移量32,大小:16(高度)* 8 (宽度)
*/
//@conslons字体,阴码点阵格式,逐行顺向取摸
const uint8_t ASCII8x16_Table [ ] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x08,0x00,0x08,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x34,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x16,0x24,0x7f,0x24,0x24,0x24,0x7e,0x24,0x24,0x00,0x00,0x00,
0x00,0x00,0x00,0x08,0x3e,0x68,0x48,0x68,0x1c,0x16,0x12,0x12,0x7c,0x10,0x10,0x00,
0x00,0x00,0x00,0x61,0xd2,0x96,0x74,0x08,0x10,0x16,0x29,0x49,0xc6,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x64,0x64,0x38,0x72,0x4a,0xce,0x46,0x7f,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x04,0x08,0x18,0x10,0x30,0x30,0x30,0x30,0x10,0x10,0x18,0x0c,0x04,
0x00,0x00,0x00,0x20,0x10,0x08,0x08,0x0c,0x04,0x04,0x04,0x0c,0x08,0x18,0x10,0x20,
0x00,0x00,0x00,0x08,0x0a,0x34,0x1c,0x6a,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x7f,0x18,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x08,0x30,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x06,0x04,0x0c,0x08,0x08,0x10,0x10,0x20,0x20,0x40,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x66,0x42,0x47,0x5b,0x73,0x42,0x66,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x18,0x78,0x48,0x08,0x08,0x08,0x08,0x08,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x46,0x06,0x06,0x04,0x08,0x10,0x20,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x06,0x06,0x04,0x3c,0x02,0x02,0x06,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x0c,0x1c,0x14,0x24,0x64,0x44,0xff,0x04,0x04,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x60,0x60,0x60,0x7e,0x02,0x02,0x06,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1e,0x30,0x60,0x48,0x76,0x42,0x42,0x62,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x02,0x06,0x04,0x0c,0x08,0x18,0x10,0x30,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x62,0x42,0x36,0x1c,0x66,0x42,0x42,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x66,0x42,0x42,0x66,0x1a,0x02,0x04,0x78,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x08,0x30,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x18,0x30,0x60,0x10,0x0c,0x06,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x00,0x7e,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x18,0x04,0x06,0x0c,0x10,0x20,0x00,0x00,0x00,
0x00,0x00,0x00,0x30,0x1c,0x06,0x06,0x06,0x18,0x10,0x00,0x10,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x1c,0x22,0x41,0x41,0xdd,0xb5,0xa5,0xa5,0xaf,0x94,0xc0,0x40,0x3c,
0x00,0x00,0x00,0x00,0x18,0x1c,0x34,0x24,0x26,0x62,0x7e,0x43,0xc1,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x46,0x42,0x46,0x7c,0x42,0x42,0x42,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1e,0x20,0x40,0x40,0x40,0x40,0x40,0x60,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x46,0x42,0x43,0x43,0x43,0x42,0x46,0x78,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x60,0x60,0x60,0x7e,0x60,0x60,0x60,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x60,0x60,0x60,0x7e,0x60,0x60,0x60,0x60,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x1e,0x60,0x40,0x40,0xce,0x42,0x42,0x62,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x7e,0x42,0x42,0x42,0x42,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x04,0x04,0x04,0x04,0x04,0x04,0x44,0x78,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x42,0x44,0x48,0x50,0x70,0x58,0x4c,0x44,0x42,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x62,0x66,0x67,0x5f,0x5b,0x5b,0xc1,0xc1,0xc1,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x62,0x62,0x72,0x52,0x5a,0x4a,0x4e,0x46,0x46,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x62,0x43,0xc3,0xc3,0xc3,0x43,0x62,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7c,0x46,0x42,0x42,0x46,0x78,0x40,0x40,0x40,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3c,0x62,0x43,0xc3,0xc3,0xc3,0x43,0x62,0x3c,0x18,0x0f,0x00,
0x00,0x00,0x00,0x00,0x7c,0x66,0x62,0x66,0x7c,0x6c,0x64,0x66,0x62,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x3e,0x60,0x40,0x60,0x1c,0x06,0x02,0x02,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7f,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x62,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xc1,0x43,0x42,0x62,0x26,0x24,0x34,0x1c,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xc1,0xc1,0x41,0x49,0x5b,0x5b,0x76,0x66,0x66,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x43,0x66,0x34,0x18,0x18,0x1c,0x24,0x66,0xc3,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xc1,0x42,0x66,0x34,0x1c,0x18,0x18,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x7e,0x02,0x04,0x0c,0x18,0x10,0x20,0x60,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x1c,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x1c,
0x00,0x00,0x00,0x40,0x20,0x20,0x10,0x10,0x08,0x08,0x0c,0x04,0x06,0x02,0x00,0x00,
0x00,0x00,0x00,0x3c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x0c,0x3c,
0x00,0x00,0x00,0x00,0x18,0x1c,0x24,0x62,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,
0x00,0x00,0x00,0x20,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x06,0x02,0x3e,0x42,0x46,0x7a,0x00,0x00,0x00,
0x00,0x00,0x00,0x40,0x40,0x40,0x5c,0x62,0x42,0x42,0x42,0x42,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x1e,0x20,0x60,0x40,0x60,0x20,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x02,0x02,0x02,0x3e,0x62,0x42,0x42,0x42,0x66,0x3a,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x62,0x42,0x7e,0x40,0x60,0x3e,0x00,0x00,0x00,
0x00,0x00,0x00,0x0f,0x18,0x10,0x10,0x7e,0x10,0x10,0x10,0x10,0x10,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0x66,0x42,0x66,0x58,0x40,0x3e,0x43,0x42,0x3c,
0x00,0x00,0x00,0x40,0x40,0x40,0x5c,0x62,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00,
0x00,0x00,0x00,0x18,0x18,0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x04,0x0c,0x00,0x7c,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x0c,0x78,
0x00,0x00,0x00,0x60,0x60,0x60,0x62,0x6c,0x78,0x70,0x68,0x64,0x62,0x00,0x00,0x00,
0x00,0x00,0x00,0x78,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x76,0x4b,0x4b,0x4b,0x4b,0x4b,0x4b,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x62,0x42,0x42,0x42,0x42,0x42,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3c,0x62,0x42,0x43,0x42,0x62,0x3c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x5c,0x62,0x42,0x42,0x42,0x42,0x7c,0x40,0x40,0x40,
0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x62,0x42,0x42,0x42,0x66,0x3a,0x02,0x02,0x02,
0x00,0x00,0x00,0x00,0x00,0x00,0x6e,0x72,0x63,0x60,0x60,0x60,0x60,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x3e,0x20,0x20,0x3c,0x06,0x02,0x7c,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x10,0x10,0xfe,0x10,0x10,0x10,0x10,0x10,0x1e,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x42,0x42,0x42,0x42,0x66,0x3a,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x42,0x66,0x24,0x34,0x18,0x18,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0xc1,0xc1,0x5b,0x5a,0x5e,0x66,0x66,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x62,0x26,0x1c,0x18,0x1c,0x26,0x62,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x43,0x42,0x66,0x24,0x34,0x1c,0x18,0x18,0x30,0xe0,
0x00,0x00,0x00,0x00,0x00,0x00,0x7e,0x06,0x0c,0x18,0x10,0x20,0x7e,0x00,0x00,0x00,
0x00,0x00,0x00,0x0e,0x18,0x10,0x10,0x10,0x30,0x70,0x10,0x10,0x10,0x10,0x18,0x0e,
0x00,0x00,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,0x08,
0x00,0x00,0x00,0x30,0x18,0x08,0x08,0x08,0x0c,0x0e,0x08,0x08,0x08,0x08,0x18,0x30,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x71,0x4b,0x06,0x00,0x00,0x00,0x00,0x00,
};
有了字库数据后,可以通过定义结构体,存储不同字体信息的结构体变量(数组指针、宽度、高度):
定义结构体类型:
typedef struct _tFont
{
const uint8_t *table; /* 字体数组指针 */
uint16_t Width;
uint16_t Height;
} sFONT;
然后定义定义3个结构体变量,分别保存 3 种不同尺寸字模的信息:
sFONT Font8x16 = {
ASCII8x16_Table,
8, /* Width */
16, /* Height */
};
sFONT Font16x24 = {
ASCII16x24_Table,
16, /* Width */
24, /* Height */
};
sFONT Font24x32 = {
ASCII24x32_Table,
24, /* Width */
32, /* Height */
};
这个结构体类型定义了三个变量,第一个是指向字模数据的指针,即前面提到的 C 语言数组,每二、三个变量存储了该字模单个字符的像素宽度和高度。利用这个类型定义了Font8x16、Font16x24之类的变量,方便显示时寻址。
切换字体:
static sFONT *LCD_Currentfonts = &Font8x16; //英文字体
/**
* @brief 设置英文字体类型
* @param fonts: 指定要选择的字体
* 参数为以下值之一
* @arg:Font24x32;
* @arg:Font16x24;
* @arg:Font8x16;
* @retval None
*/
void LCD_SetFont(sFONT *fonts)
{
LCD_Currentfonts = fonts;
}
显示单个英文字符:
/**
* @brief 在 ILI9341 显示器上显示一个英文字符
* @param usX :在特定扫描方向下字符的起始X坐标
* @param usY :在特定扫描方向下该点的起始Y坐标
* @param cChar :要显示的英文字符
* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
* @retval 无
*/
void ILI9341_DispChar_EN ( uint16_t usX, uint16_t usY, const char cChar )
{
uint8_t byteCount, bitCount,fontLength;
uint16_t ucRelativePositon;
uint8_t *Pfont;
//对ascii码表偏移(字模表不包含ASCII表的前32个非图形符号)
ucRelativePositon = cChar - ' ';
//每个字模的字节数
fontLength = (LCD_Currentfonts->Width * LCD_Currentfonts->Height) / 8;
//字模首地址
/*ascii码表偏移值乘以每个字模的字节数,求出字模的偏移位置*/
Pfont = (uint8_t *)&LCD_Currentfonts->table[ucRelativePositon * fontLength];
//设置显示窗口
ILI9341_OpenWindow ( usX, usY, LCD_Currentfonts->Width, LCD_Currentfonts->Height);
ILI9341_Write_Cmd ( CMD_SetPixel );
//按字节读取字模数据
//由于前面直接设置了显示窗口,显示数据会自动换行
for (byteCount = 0; byteCount < fontLength; byteCount++)
{
// 一位一位处理要显示的颜色
for (bitCount = 0; bitCount < 8; bitCount++)
{
if (Pfont[byteCount] & (0x80 >> bitCount))
{
ILI9341_Write_Data (CurrentTextColor);
}
else
{
ILI9341_Write_Data (CurrentBackColor);
}
}
}
}
因为我们制作的字模从空格“ ”开始,所以要先求字符相对于空格的偏移,然后 偏移 * 字符大小 求得数组元素偏移,然后将指针指向 待显示字符 的起始位置,此时已经找到了字模数据。然后开窗(开窗的起始X Y 坐标由函数传入,开窗的宽度和高度跟字体保持一致),然后根据字模数据,设置像素点写入前景色or背景色。
显示字符串:
/**
* @brief 在 ILI9341 显示器上显示英文字符串
* @param usX :在特定扫描方向下字符的起始X坐标
* @param usY :在特定扫描方向下字符的起始Y坐标
* @param pStr :要显示的英文字符串的首地址
* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
* @retval 无
*/
void ILI9341_DispString_EN ( uint16_t usX ,uint16_t usY, char * pStr )
{
while ( * pStr != '\0' )
{
/* 如果X方向显示超出,则切换到下一行显示(X回0位,Y加字模高度) */
if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
usY += LCD_Currentfonts->Height;
}
/* 如果Y方向超出,重新回到起点显示 */
if ( ( usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
usY = ILI9341_DispWindow_Y_Star;
}
ILI9341_DispChar_EN ( usX, usY, * pStr);
pStr ++;
usX += LCD_Currentfonts->Width;
}
}
这个显示字符串的函数,其实是封装了上一个显示单个字符的函数。通过while循环检测字符串的结尾,然后利用ILI9341_DispChar_EN函数不断的显示字符。第一个if语句,表示如果当前的字符 X方向 起始位置超出了LCD的X范围,那么切换到下一行显示(X坐标回到起始位置,Y坐标 + 字符高度);第二个if语句,如果当前Y方向坐标超出了LCD的Y范围,则直接回到液晶屏的起始处显示。
既然有了显示字符串的函数,更进一步的,我们希望可以直接将字符串显示到某一行,如:
ILI9341_DispStringLine_EN(LINE(4),"Draw line:");
这里,实际上是封装了一个LINE的宏,这个宏根据输入的行号和字体高度,计算实际上的 Y方向坐标,然后显示。
#define LINE(x) ((x) * (((sFONT *)LCD_GetFont())->Height))
/**
* @brief 在 ILI9341 显示器上显示英文字符串
* @param line :在特定扫描方向下字符串的起始Y坐标
* 本参数可使用宏LINE(0)、LINE(1)等方式指定文字坐标,
* 宏LINE(x)会根据当前选择的字体来计算Y坐标值。
* 显示中文且使用LINE宏时,需要把英文字体设置成Font8x16
* @param pStr :要显示的英文字符串的首地址
* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
* @retval 无
*/
void ILI9341_DispStringLine_EN ( uint16_t line, char * pStr )
{
uint16_t usX = 0;
while ( * pStr != '\0' )
{
if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
line += LCD_Currentfonts->Height;
}
if ( ( line - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
line = ILI9341_DispWindow_Y_Star;
}
ILI9341_DispChar_EN ( usX, line, * pStr);
pStr ++;
usX += LCD_Currentfonts->Width;
}
}
以特定颜色,清除屏幕的某一区域(其实就是开窗,填充颜色):
/**
* @brief 在ILI9341显示器上以某一颜色填充像素点
* @param ulAmout_Point :要填充颜色的像素点的总数目
* @param usColor :颜色
* @retval 无
*/
static __inline void ILI9341_FillColor ( uint32_t ulAmout_Point, uint16_t usColor )
{
uint32_t i = 0;
/* memory write */
ILI9341_Write_Cmd ( CMD_SetPixel );
for ( i = 0; i < ulAmout_Point; i ++ )
ILI9341_Write_Data ( usColor );
}
/**
* @brief 对ILI9341显示器的某一窗口以某种颜色进行清屏
* @param usX :在特定扫描方向下窗口的起点X坐标
* @param usY :在特定扫描方向下窗口的起点Y坐标
* @param usWidth :窗口的宽度
* @param usHeight :窗口的高度
* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
* @retval 无
*/
void ILI9341_Clear ( uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight )
{
ILI9341_OpenWindow ( usX, usY, usWidth, usHeight );
ILI9341_FillColor ( usWidth * usHeight, CurrentBackColor );
}
清除某一行的文本:
/**
* @brief 清除某行文字
* @param Line: 指定要删除的行
* 本参数可使用宏LINE(0)、LINE(1)等方式指定要删除的行,
* 宏LINE(x)会根据当前选择的字体来计算Y坐标值,并删除当前字体高度的第x行。
* @retval None
*/
void LCD_ClearLine(uint16_t Line)
{
ILI9341_Clear(0,Line,LCD_X_LENGTH,((sFONT *)LCD_GetFont())->Height); /* 清屏,显示全黑 */
}
显示字符串的代码测试:
/*用于测试各种液晶的函数*/
void LCD_Test(void)
{
/*演示显示变量*/
static uint8_t testCNT = 0;
char dispBuff[100];
testCNT++;
LCD_SetFont(&Font8x16);
LCD_SetColors(RED,BLACK);
ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH); /* 清屏,显示全黑 */
/********显示字符串示例*******/
ILI9341_DispStringLine_EN(LINE(0),"BH 3.2 inch LCD para:");
ILI9341_DispStringLine_EN(LINE(1),"Image resolution:240x320 px");
ILI9341_DispStringLine_EN(LINE(2),"ILI9341 LCD driver");
ILI9341_DispStringLine_EN(LINE(3),"XPT2046 Touch Pad driver");
/********显示变量示例*******/
LCD_SetFont(&Font16x24);
LCD_SetTextColor(GREEN);
/*使用c标准库把变量转化成字符串*/
sprintf(dispBuff,"Count : %d ",testCNT);
LCD_ClearLine(LINE(4)); /* 清除单行文字 */
/*然后显示该字符串即可,其它变量也是这样处理*/
ILI9341_DispStringLine_EN(LINE(4),dispBuff);
ILI9341_Clear(0,16*8,LCD_X_LENGTH,LCD_Y_LENGTH-16*8); /* 清屏,显示全黑 */
}
其中,sprintf函数,可以用来将变量转换成字符串,并保存在字符数组中,然后就可以调用ILI9341_DispStringLine_EN显示。
/*使用c标准库把变量转化成字符串*/
sprintf(dispBuff,"Count : %d ",testCNT);
LCD_ClearLine(LINE(4)); /* 清除单行文字 */
/*然后显示该字符串即可,其它变量也是这样处理*/
ILI9341_DispStringLine_EN(LINE(4),dispBuff);
sprintf函数的使用:
中文显示
显示单个中文字符:
/**
* @brief 在 ILI9341 显示器上显示一个中文字符
* @param usX :在特定扫描方向下字符的起始X坐标
* @param usY :在特定扫描方向下字符的起始Y坐标
* @param usChar :要显示的中文字符(国标码)
* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
* @retval 无
*/
void ILI9341_DispChar_CH ( uint16_t usX, uint16_t usY, uint16_t usChar )
{
uint8_t rowCount, bitCount;
uint8_t ucBuffer [ WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8 ];
uint16_t usTemp;
//设置显示窗口
ILI9341_OpenWindow ( usX, usY, WIDTH_CH_CHAR, HEIGHT_CH_CHAR );
ILI9341_Write_Cmd ( CMD_SetPixel );
//取字模数据,保存在ucBuffer数组中
GetGBKCode ( ucBuffer, usChar );
for ( rowCount = 0; rowCount < HEIGHT_CH_CHAR; rowCount++ )
{
/* 取出两个字节的数据,在lcd上即是一个汉字的一行 */
// 汉字点阵为16*16,每行2字节
usTemp = ucBuffer [ rowCount * 2 ];
usTemp = ( usTemp << 8 );
usTemp |= ucBuffer [ rowCount * 2 + 1 ];
for ( bitCount = 0; bitCount < WIDTH_CH_CHAR; bitCount ++ )
{
if ( usTemp & ( 0x8000 >> bitCount ) ) //高位在前
ILI9341_Write_Data ( CurrentTextColor );
else
ILI9341_Write_Data ( CurrentBackColor );
}
}
}
这个显示GB2312汉字编码的函数,与之前显示ASCII英文字符编码的非常类似。它的输入参数有 usX,usY 及 usChar。其中 usX 和 usY 用于设定字符的显示位置,usChar 是字符的编码,这是一个 16 位的变量,因为 GB2312编码中每个字符是 2 个字节的。函数的执行流程如下:
(1)使用 ILI9341_OpenWindow 和 ILI9341_Write_Cmd 来设置开窗并发送显示像素命令;
(2)使用量 macGetGBKCode 函数获取字模数据,向该函数输入 usChar 参数(字符的编码),它会从外部 SPI-FLASH 芯片或
SD 卡中读取该字符的字模数据,读取得的数据被存储到数组 ucBuffer中;
(3)遍历像素点。这个代码在遍历时还使用了 usTemp 变量用来缓存一行的字模数据(本字模一行有 2 个字节),然后一位一位
地判断这些数据,数据位为 1 的时候,像素点就显示字体颜色,否则显示背景颜色。原理是跟 ASCII 字符显示一样的;
根据GB2312编码,获取字模数据的函数封装:
/*使用FLASH字模*/
/*中文字库存储在FLASH的起始地址*/
/*FLASH*/
#define GBKCODE_START_ADDRESS 387*4096
/*获取字库的函数*/
//定义获取中文字符字模数组的函数名,ucBuffer为存放字模数组名,usChar为中文字符(国标码)
#define GetGBKCode(ucBuffer, usChar) GetGBKCode_from_EXFlash( ucBuffer, usChar )
int GetGBKCode_from_EXFlash( uint8_t * pBuffer, uint16_t c);
/*使用FLASH字模*/
//字模GB2312_H1616配套的函数
//中文字库存储在FLASH的起始地址 :
//GBKCODE_START_ADDRESS 在fonts.h文件定义
/**
* @brief 获取FLASH中文显示字库数据
* @param pBuffer:存储字库矩阵的缓冲区
* @param c : 要获取的文字
* @retval None.
*/
int GetGBKCode_from_EXFlash( uint8_t * pBuffer, uint16_t c)
{
unsigned char High8bit,Low8bit;
unsigned int pos;
static uint8_t everRead=0;
/*第一次使用,初始化FLASH*/
if(everRead == 0)
{
SPI_FLASH_Init();
everRead = 1;
}
/* 参数c 为GB2312编码,获取 高8位 和 低8位 */
High8bit= c >> 8; /* 取高8位数据 */
Low8bit= c & 0x00FF; /* 取低8位数据 */
/* GB2312 公式,计算区位码的偏移,再乘以字模字节数 */
pos = ((High8bit-0xa1)*94+Low8bit-0xa1)*WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8;
//读取字库数据
SPI_FLASH_BufferRead(pBuffer,GBKCODE_START_ADDRESS+pos,WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8);
return 0;
}
这个函数起始也很简单,具体执行流程分析如下:
显示中文字符串(只能中文,不能中英文混合):
/**
* @brief 在 ILI9341 显示器上显示中文字符串
* @param line :在特定扫描方向下字符串的起始Y坐标
* 本参数可使用宏LINE(0)、LINE(1)等方式指定文字坐标,
* 宏LINE(x)会根据当前选择的字体来计算Y坐标值。
* 显示中文且使用LINE宏时,需要把英文字体设置成Font8x16
* @param pStr :要显示的英文字符串的首地址
* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
* @retval 无
*/
void ILI9341_DispString_CH ( uint16_t usX , uint16_t usY, char * pStr )
{
uint16_t usCh;
while( * pStr != '\0' )
{
if ( ( usX - ILI9341_DispWindow_X_Star + WIDTH_CH_CHAR ) > LCD_X_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
usY += HEIGHT_CH_CHAR;
}
if ( ( usY - ILI9341_DispWindow_Y_Star + HEIGHT_CH_CHAR ) > LCD_Y_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
usY = ILI9341_DispWindow_Y_Star;
}
usCh = * ( uint16_t * ) pStr;
usCh = ( usCh << 8 ) + ( usCh >> 8 );
ILI9341_DispChar_CH ( usX, usY, usCh );
usX += WIDTH_CH_CHAR;
pStr += 2; //一个汉字两个字节
}
}
这个函数,跟之前的显示英文字符串的函数一样,唯一的区别就是,这个函数一次读取两个字节(GB2312编码)。
显示任意字符串(中英文混合):
/**
* @brief 在 ILI9341 显示器上显示中英文字符串
* @param usX :在特定扫描方向下字符的起始X坐标
* @param usY :在特定扫描方向下字符的起始Y坐标
* @param pStr :要显示的字符串的首地址
* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
* @retval 无
*/
void ILI9341_DispString_EN_CH ( uint16_t usX , uint16_t usY, char * pStr )
{
uint16_t usCh;
while( * pStr != '\0' )
{
if ( * pStr <= 126 ) //英文字符
{
if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
usY += LCD_Currentfonts->Height;
}
if ( ( usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
usY = ILI9341_DispWindow_Y_Star;
}
ILI9341_DispChar_EN ( usX, usY, * pStr );
usX += LCD_Currentfonts->Width;
pStr ++;
}
else //汉字字符
{
if ( ( usX - ILI9341_DispWindow_X_Star + WIDTH_CH_CHAR ) > LCD_X_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
usY += HEIGHT_CH_CHAR;
}
if ( ( usY - ILI9341_DispWindow_Y_Star + HEIGHT_CH_CHAR ) > LCD_Y_LENGTH )
{
usX = ILI9341_DispWindow_X_Star;
usY = ILI9341_DispWindow_Y_Star;
}
usCh = * ( uint16_t * ) pStr;
usCh = ( usCh << 8 ) + ( usCh >> 8 );
ILI9341_DispChar_CH ( usX, usY, usCh );
usX += WIDTH_CH_CHAR;
pStr += 2; //一个汉字两个字节
}
}
}
任意显示中英文字符的原理,起始就是之前讲到的GB2312兼容ASCII编码。读取一个字节,如果编码值<=126,则是ASCII编码,直接调用单个英文字符的打印函数;否则为GB2312编码,连续读取两个字节,并调用中文单字打印的函数。