【LCD】液晶显示中英文实验系列文章

【LCD】液晶显示中英文实验(1)
【LCD】液晶显示中英文实验(2)
【LCD】液晶显示中英文实验(3)
【LCD】液晶显示中英文实验(4)
【LCD】液晶显示中英文实验(5)


前言

显示 ASCII 编码比较简单,由于字库文件小,甚至都不需要使用外部的存储器,而显示汉字时,由于我们的字库是存储到外部存储器上的,这涉及到额外的获取字模数据的操作。同时,本文我们将使用两种方式进行存储字模数据显示中英文,第一种是存储在外部Flash,第二种是存储在SD卡里面,接下来我们就来做一下这两个实验显示GB2312编码格式的字符。这两个工程使用的字
库文件内容相同,只是字库存储的位置不一样,工程中我们把获取字库数据相关的函数代码写在“fonts.c”及“fonts.h”文件中,字符显示的函数仍存储在 LCD 驱动文件“bsp_ili9806g_lcd.c”及“bsp_ili9806g_lcd.h”中。


一、硬件设计

  • 获取字模数据
  • 根据字模格式,编写液晶显示函数
  • 编写测试程序,控制液晶显示汉字

二、代码分析

显示汉字字符:
该函数接收中文字符显示的起始坐标 (usX, usY) 和字符的国标码 usChar,先划定显示窗口,再通过 GetGBKCode 读取该字符的 32×32 点阵字模数据,最后逐行解析字模数据(每行 4 字节 = 32 位),逐位绘制前景色 / 背景色,最终在屏幕上显示出 32×32 尺寸的中文字符。

/*******************中文********** 在显示屏上显示的字符大小 ***************************/
#define      WIDTH_CH_CHAR		                32	    //中文字符宽度 
#define      HEIGHT_CH_CHAR		              	32		  //中文字符高度 

//缓存读取回来的字模数据
static uint8_t ucBuffer [ WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8 ];	


/**
 * @brief  在 ILI9806G 显示器上显示一个中文字符
 * @param  usX :在特定扫描方向下字符的起始X坐标
 * @param  usY :在特定扫描方向下字符的起始Y坐标
 * @param  usChar :要显示的中文字符(国标码)
 * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
 * @retval 无
 */ 
void ILI9806G_DispChar_CH ( uint16_t usX, uint16_t usY, uint16_t usChar )
{
	uint8_t rowCount, bitCount;
  uint32_t usTemp; 
	
//	占用空间太大,改成全局变量 
//	uint8_t ucBuffer [ WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8 ];	
	
	//设置显示窗口
	ILI9806G_OpenWindow ( usX, usY, WIDTH_CH_CHAR, HEIGHT_CH_CHAR );
	
	ILI9806G_Write_Cmd ( CMD_SetPixel );
	
	//取字模数据  
  GetGBKCode ( ucBuffer, usChar );	
	
	for ( rowCount = 0; rowCount < HEIGHT_CH_CHAR; rowCount++ )
	{
    /* 取出四个字节的数据,在lcd上即是一个汉字的一行 */
		usTemp = ucBuffer [ rowCount * 4 ];
		usTemp = ( usTemp << 8 );
		usTemp |= ucBuffer [ rowCount * 4 + 1 ];
		usTemp = ( usTemp << 8 );
		usTemp |= ucBuffer [ rowCount * 4 + 2 ];
		usTemp = ( usTemp << 8 );
		usTemp |= ucBuffer [ rowCount * 4 + 3 ];
		
		for ( bitCount = 0; bitCount < WIDTH_CH_CHAR; bitCount ++ )
		{			
			if ( usTemp & ( 0x80000000 >> bitCount ) )  //高位在前 
			  ILI9806G_Write_Data ( CurrentTextColor );				
			else
				ILI9806G_Write_Data ( CurrentBackColor );			
		}		
	}
	
}

执行示例:
在这里插入图片描述

显示中英文字符串:
该函数接收字符串起始坐标 (usX, usY) 和字符串首地址 pStr,循环遍历字符串:

  • 若为英文字符(ASCII ≤ 126):调用 ILI9806G_DispChar_EN 显示,按当前英文字体尺寸偏移坐标;
  • 若为中文字符(ASCII > 126):解析双字节 GBK 编码,调用 ILI9806G_DispChar_CH 显示,按 32×32 尺寸偏移坐标;
  • 全程检测屏幕边界,超出宽度则换行,超出高度则回到屏幕顶部,保证字符串不越界。
/**
 * @brief  在 ILI9806G 显示器上显示中英文字符串
 * @param  usX :在特定扫描方向下字符的起始X坐标
 * @param  usY :在特定扫描方向下字符的起始Y坐标
 * @param  pStr :要显示的字符串的首地址
 * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
 * @retval 无
 */
void ILI9806G_DispString_EN_CH ( 	uint16_t usX , uint16_t usY, char * pStr )
{
	uint16_t usCh;
	
	while( * pStr != '\0' )
	{
		if ( * pStr <= 126 )	           	//英文字符
		{
			if ( ( usX - ILI9806G_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH )
			{
				usX = ILI9806G_DispWindow_X_Star;
				usY += LCD_Currentfonts->Height;
			}
			
			if ( ( usY - ILI9806G_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH )
			{
				usX = ILI9806G_DispWindow_X_Star;
				usY = ILI9806G_DispWindow_Y_Star;
			}			
		
		  ILI9806G_DispChar_EN ( usX, usY, * pStr );
			
			usX +=  LCD_Currentfonts->Width;
		
		  pStr ++;

		}
		
		else	                            //汉字字符
		{
			if ( ( usX - ILI9806G_DispWindow_X_Star + WIDTH_CH_CHAR ) > LCD_X_LENGTH )
			{
				usX = ILI9806G_DispWindow_X_Star;
				usY += HEIGHT_CH_CHAR;
			}
			
			if ( ( usY - ILI9806G_DispWindow_Y_Star + HEIGHT_CH_CHAR ) > LCD_Y_LENGTH )
			{
				usX = ILI9806G_DispWindow_X_Star;
				usY = ILI9806G_DispWindow_Y_Star;
			}	
			
			usCh = * ( uint16_t * ) pStr;	
			
			usCh = ( usCh << 8 ) + ( usCh >> 8 );		

			ILI9806G_DispChar_CH ( usX, usY, usCh );
			
			usX += WIDTH_CH_CHAR;
			
			pStr += 2;           //一个汉字两个字节 
		
    }
		
  }	
} 

获取 SPI-FLASH 中的字模数据:
这段代码是用于从外部 FLASH 存储器中读取 GB2312/GBK 编码中文字符对应的点阵字模数据的核心函数,主要功能是根据中文字符的国标码计算其在 FLASH 中的存储位置,并读取对应的字模数据到指定缓冲区。

/*使用FLASH字模*/
/*中文字库存储在FLASH的起始地址*/
/*FLASH*/
#define GBKCODE_START_ADDRESS   1254*4096
/*获取字库的函数*/
//定义获取中文字符字模数组的函数名,ucBuffer为存放字模数组名,usChar为中文字符(国标码)
#define      GetGBKCode( ucBuffer, usChar )  GetGBKCode_from_EXFlash( ucBuffer, usChar )  
int GetGBKCode_from_EXFlash( uint8_t * pBuffer, uint16_t c);

/*使用FLASH字模*/
//字模GB2312_H3232配套的函数

//中文字库存储在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;
		}
	
	  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); //读取字库数据  
//	  printf ( "%02x %02x %02x %02x\n", pBuffer[0],pBuffer[1],pBuffer[2],pBuffer[3]);
	
		return 0;  
     
}

获取 SD 卡中的字模数据:
这段代码是从 SD 卡中读取 GB2312 编码的 32x32 点阵中文字模数据的核心实现,和之前的 FLASH 版本逻辑一致,但存储介质换成了 SD 卡,使用 FatFs 文件系统进行操作。

/*使用SD字模*/
/*SD卡字模路径*/
#define GBKCODE_FILE_NAME			"0:/srcdata/GB2312_H3232.FON"
/*获取字库的函数*/
//定义获取中文字符字模数组的函数名,ucBuffer为存放字模数组名,usChar为中文字符(国标码)
#define GetGBKCode( ucBuffer, usChar )  GetGBKCode_from_sd( ucBuffer, usChar )
int GetGBKCode_from_sd ( uint8_t * pBuffer, uint16_t c);


/*使用SD字模*/

static FIL fnew;													/* file objects */
static FATFS fs;													/* Work area (file system object) for logical drives */
static FRESULT res_sd; 
static UINT br;            					/* File R/W count */

//字库文件存储位置,fonts.h中的宏:
//#define GBKCODE_FILE_NAME			"0:/Font/GB2312_H3232.FON"

/**
  * @brief  获取SD卡中文显示字库数据
	* @param  pBuffer:存储字库矩阵的缓冲区
	* @param  c : 要获取的文字
  * @retval None.
  */
int GetGBKCode_from_sd ( uint8_t * pBuffer, uint16_t c)
{ 
    unsigned char High8bit,Low8bit;
    unsigned int pos;
		
		static uint8_t everRead = 0;
	
    High8bit= c >> 8;     /* 取高8位数据 */
    Low8bit= c & 0x00FF;  /* 取低8位数据 */
		
    pos = ((High8bit-0xa1)*94+Low8bit-0xa1)*WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8;
	
		/*第一次使用,挂载文件系统,初始化sd*/
		if(everRead == 0)
		{
			res_sd = f_mount(&fs,"0:",1);
			everRead = 1;

		}
		
    res_sd = f_open(&fnew , GBKCODE_FILE_NAME, FA_OPEN_EXISTING | FA_READ);
    
    if ( res_sd == FR_OK ) 
    {
        f_lseek (&fnew, pos);		//指针偏移
			
				//32*32大小的汉字 其字模 占用32*32/8个字节
        res_sd = f_read( &fnew, pBuffer, WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8, &br );		 
        
        f_close(&fnew);
        
        return 0;  
    }    
    else
        return -1;    
}

显示 GB2312 字符示例:
这段代码是整个液晶屏中文显示程序的主函数入口,核心功能是完成硬件初始化、打印提示信息、设置液晶显示方向,并进入循环执行 LCD 测试逻辑。


int main(void)
{	
	//LCD 初始化
	ILI9806G_Init ();         

	/* USART config */
	Debug_USART_Config();		

	
	printf("\r\n ********** 液晶屏中文显示程序(字模文件在SD卡)*********** \r\n"); 
	printf("\r\n  实验前请阅读工程中的readme.txt文件说明,存储字模数据到SD卡\r\n"); 
	
	
 //其中0、3、5、6 模式适合从左至右显示文字,
 //不推荐使用其它模式显示文字	其它模式显示文字会有镜像效果			
 //其中 6 模式为大部分液晶例程的默认显示方向  
	ILI9806G_GramScan ( 6 );
	
	Printf_Charater();
	
	while ( 1 )
	{
		LCD_Test();
	}
	
	
}

测试函数
这是一个完整的液晶屏功能测试函数,核心作用是循环演示 ILI9806G 液晶屏的各类显示能力 —— 包括中英文文字显示、变量动态显示,以及直线、矩形、圆形等基本图形绘制,每个演示环节都有清晰的视觉区分和延时效果


/*用于测试各种液晶的函数*/
void LCD_Test(void)
{
	/*演示显示变量*/
	static uint8_t testCNT = 0;	
	char dispBuff[100];
	
	testCNT++;	
	
	LCD_SetFont(&Font16x32);
	LCD_SetColors(RED,BLACK);

  ILI9806G_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH);	/* 清屏,显示全黑 */
	/********显示字符串示例*******/ 
  ILI9806G_DispStringLine_EN_CH(LINE(0),"野火4.3寸LCD参数:");
  ILI9806G_DispStringLine_EN_CH(LINE(2),"分辨率:480x800 px");
  ILI9806G_DispStringLine_EN_CH(LINE(3),"ILI9806G液晶驱动");
  ILI9806G_DispStringLine_EN_CH(LINE(4),"GT911触摸屏驱动");

	/********显示变量示例*******/
	LCD_SetTextColor(GREEN);

	/*使用c标准库把变量转化成字符串*/
	sprintf(dispBuff,"显示变量计数 : %d ",testCNT);
  ILI9806G_ClearLine(LINE(7));	/* 清除单行文字 */
	
	/*然后显示该字符串即可,其它变量也是这样处理*/
	ILI9806G_DispStringLine_EN(LINE(7),dispBuff);

	/*******显示图形示例******/
  /* 画直线 */
  
  ILI9806G_ClearLine(LINE(7));/* 清除单行文字 */
	LCD_SetTextColor(BLUE);

  ILI9806G_DispStringLine_EN_CH(LINE(7),"画直线:");
  
	LCD_SetTextColor(RED);
  ILI9806G_DrawLine(50,270,420,275);  
  ILI9806G_DrawLine(50,300,420,375);
  
	LCD_SetTextColor(GREEN);
  ILI9806G_DrawLine(50,370,420,475);  
  ILI9806G_DrawLine(50,400,420,475);
	
	LCD_SetTextColor(BLUE);
  ILI9806G_DrawLine(50,420,420,325);  
  ILI9806G_DrawLine(50,450,420,395);
  
  Delay(0x2FFFFFF);
  
  ILI9806G_Clear(0,32*7,LCD_X_LENGTH,LCD_Y_LENGTH-32*7);	/* 清屏,显示全黑 */
  
  
  /*画矩形*/

  ILI9806G_ClearLine(LINE(7));	/* 清除单行文字 */
	LCD_SetTextColor(BLUE);

  ILI9806G_DispStringLine_EN_CH(LINE(7),"画矩形:");

	LCD_SetTextColor(RED);
  ILI9806G_DrawRectangle(50,300,200,100,1);
	
	LCD_SetTextColor(GREEN);
  ILI9806G_DrawRectangle(100,300,200,120,0);
	
	LCD_SetTextColor(BLUE);
  ILI9806G_DrawRectangle(250,300,200,150,1);
  
  
  Delay(0x2FFFFFF);
	
	ILI9806G_Clear(0,32*7,LCD_X_LENGTH,LCD_Y_LENGTH-32*7);	/* 清屏,显示全黑 */

  /* 画圆 */
  ILI9806G_ClearLine(LINE(7));	/* 清除单行文字 */
	LCD_SetTextColor(BLUE);
	
  ILI9806G_DispStringLine_EN_CH(LINE(7),"画圆:");

	LCD_SetTextColor(RED);
	ILI9806G_DrawCircle(150,400,60,1);

	LCD_SetTextColor(GREEN);
	ILI9806G_DrawCircle(250,400,60,0);

	LCD_SetTextColor(BLUE);
	ILI9806G_DrawCircle(350,400,60,1);

  Delay(0x2FFFFFF);
  
  ILI9806G_Clear(0,32*7,LCD_X_LENGTH,LCD_Y_LENGTH-32*7);	/* 清屏,显示全黑 */

}
Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐