STM32-LCD中英文显示及应用实例详解

目录

字符编码

ASCII码(8位)

中文编码(16位)

GB2312标准

GBK编码

GB18030标准(32位)

Big5编码

Unicode字符集和编码

UTF-32(32位)

UTF-16(16位/32位,变长编码方式)

UTF-8(8位/16位/24位/32位,变长编码方式)

实验环节1:LCD显示中英文(字库存储在外部Flash)

存储在外部Flash的字模(GB2312)

显示中文字符

显示中文字符串

显示中英文字符串

实验测试

实验现象

实验环节2:LCD显示中英文(任意大小、任何类型、居中显示)

缩放字模

缩放字模

缩放字模后显示字符

缩放字符后显示字符串

实验测试

实验现象


字符编码

由于计算机只能识别0和1,所以文字需要以0和1的形式在计算机内继续存储,故需要对文字进行编码。最简单的编码就是ASCII码。

ASCII码(8位)

ASCII码分两部分:

0~31:控制字符或通讯字符。没有特定的图形显示,但会根据不同应用程序而对文本显示有不同的影响。

32~127:空格、阿拉伯数字、标点符号、大小写英文字母和DEL。除了DEL符号外,其余的都能以图形显示。

后来,引入其他国家时需要扩展新的符号,所以从128~255都用来使用作为ASCII扩展字符集

中文编码(16位)

GB2312标准

它把ASCII码表的0~127编号保留,ASCII扩展字符集全部取消。

当2个编号大于127的字符连在一起时,就表示一个汉字,第一个字节和第二个字节都使用0xA1~0xFE编码。

第1个字节 第2个字节 表示字符 说明
0x68 0x69 hi 两个字节的值都小于127(0x7f),使用ASCII解码
0xb0 0xa1 两个字节的值都大于127(0x7f),使用GB2312解码
GBK编码

在GB2312标准的基础上,再增加许多汉字。

具体是只要第一个字节大于127(0x7F),就表示汉字的开始。

第1个字节 第1个字节 第1个字节 表示字符 说明
0x68 0xb0 0xa1 h啊 第1个字节使用ASCII解码,第2、3个字节使用GBK解码

0xb0

0xa1 0x68 啊h 第1、2个字节使用GBK解码,第3个字节使用ASCII解码
0xb0 0x56 0x68 癡h 第1、2个字节使用GBK解码,第3个字节使用ASCII解码
GB18030标准(32位)

在GBK编码之后再扩展。目前主流是GBK编码,但国家要求一些产品必须支持GB18030标准。

Big5编码

在台湾、香港等地区使用较多,因为主要特点是收录了繁体字。但GBK编码已经把Big5的所有汉字都收录进编码了(两者编码也不相同)。

Unicode字符集和编码

兼容ASCII码的字符编号,统一对符号的编号(即符号的顺序),但没对编码有要求,于是产生了几种Unicode编码方案。

UTF-32(32位)

直接将字符对应的编号数字转换为4字节的二进制数。不兼容ASCII码(因为使用的是4字节)。

特点:编码简单,解码方便,但浪费存储空间,而且存储时需要指定字节顺序(大端/小端格式)。

字符 GBK编码 Unicode编号 UTF-32编码
A 0x41 0x0000 0041 大端格式:0x0000 0041
0xB0A1 0x0000 554A 大端格式:0x0000 554A
UTF-16(16位/32位,变长编码方式)

对Unicode字符编号在0~65535的统一用2个字节表示,即0x0000~0xFFFF。而由于Unicode字符集在0xD800~0xDBFF是没有表示任何字符的,UTF-16利用这个空间对Unicode字符编号超出0xFFFF的字符建立映射关系。

特点:相对于UTF-32节省了存储空间,但存储时需要指定字节顺序(大端/小端格式),且仍不兼容ASCII码。

UTF-8(8位/16位/24位/32位,变长编码方式)

目前Unicode字符集中使用最广泛的编码方式,目前大部分网页文件都使用UTF-8编码。

实验环节1:LCD显示中英文(字库存储在外部Flash)

继承上篇液晶显示实验的函数内容,额外增加了显示中文的函数。

存储在外部Flash的字模(GB2312)

#define WIDTH_CH_CHAR	16	//中文字符宽度 
#define HEIGHT_CH_CHAR	16	//中文字符高度 

#define GBKCODE_START_ADDRESS    387*4096    // 外部Flash的存储字库的起始地址

#define GetGBKCode( ucBuffer, usChar )  GetGBKCode_from_EXFlash( ucBuffer, usChar )  
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); //读取字库数据

    return 0;
}

显示中文字符

/**
 * @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);

    //取字模数据
    GetGBKCode(ucBuffer, usChar);

    for (rowCount = 0; rowCount < HEIGHT_CH_CHAR; rowCount++)
    {
        /* 取出两个字节的数据,在lcd上即是一个汉字的一行 */
        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);
            }
        }
    }
}

显示中文字符串

/**
 * @brief  在 ILI9341 显示器上显示中文字符串
 * @param  usX :在特定扫描方向下字符的起始X坐标
 * @param  usY :在特定扫描方向下字符的起始Y坐标
 * @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;           //一个汉字两个字节
    }
}

/**
 * @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_CH(uint16_t line, char *pStr)
{
    uint16_t usCh;
    uint16_t usX = 0;

    while (* pStr != '\0')
    {
        if (* pStr <= 126)	           	//英文字符
        {
            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);
            usX +=  LCD_Currentfonts->Width;
            pStr ++;
        }
        else	                            //汉字字符
        {
            if ((usX - ILI9341_DispWindow_X_Star + WIDTH_CH_CHAR) > LCD_X_LENGTH)
            {
                usX = ILI9341_DispWindow_X_Star;
                line += HEIGHT_CH_CHAR;
            }

            if ((line - ILI9341_DispWindow_Y_Star + HEIGHT_CH_CHAR) > LCD_Y_LENGTH)
            {
                usX = ILI9341_DispWindow_X_Star;
                line = ILI9341_DispWindow_Y_Star;
            }

            usCh = * (uint16_t *) pStr;
            usCh = (usCh << 8) + (usCh >> 8);
            ILI9341_DispChar_CH(usX, line, usCh);
            usX += WIDTH_CH_CHAR;
            pStr += 2;           //一个汉字两个字节
        }
    }
}

显示中英文字符串

/**
 * @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;           //一个汉字两个字节
        }
    }
}

/**
 * @brief  在 ILI9341 显示器上显示中英文字符串(沿Y轴方向)
 * @param  usX :在特定扫描方向下字符的起始X坐标
 * @param  usY :在特定扫描方向下字符的起始Y坐标
 * @param  pStr :要显示的中英文字符串的首地址
 * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
 * @retval 无
 */
void ILI9341_DispString_EN_CH_YDir(uint16_t usX, uint16_t usY, char *pStr)
{
    uint16_t usCh;

    while (* pStr != '\0')
    {
        //统一使用汉字的宽高来计算换行
        if ((usY - ILI9341_DispWindow_Y_Star + HEIGHT_CH_CHAR) > LCD_Y_LENGTH)
        {
            usY = ILI9341_DispWindow_Y_Star;
            usX += WIDTH_CH_CHAR;
        }

        if ((usX - ILI9341_DispWindow_X_Star + WIDTH_CH_CHAR) >  LCD_X_LENGTH)
        {
            usX = ILI9341_DispWindow_X_Star;
            usY = ILI9341_DispWindow_Y_Star;
        }

        //显示
        if (* pStr <= 126)	           	//英文字符
        {
            ILI9341_DispChar_EN(usX, usY, * pStr);

            pStr ++;

            usY += HEIGHT_CH_CHAR;
        }
        else	                            //汉字字符
        {
            usCh = * (uint16_t *) pStr;
            usCh = (usCh << 8) + (usCh >> 8);
            ILI9341_DispChar_CH(usX, usY, usCh);
            usY += HEIGHT_CH_CHAR;
            pStr += 2;           //一个汉字两个字节
        }
    }
}

实验测试

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

    testCNT++;

    LCD_SetFont(&Font8x16);								// 设置字体类型:8*16,16*24,24*32
    LCD_SetColors(RED, BLACK);                          // 设置前景和背景色
    ILI9341_Clear(0, 0, LCD_X_LENGTH, LCD_Y_LENGTH);	// 清屏,显示全黑
	
    /********显示字符串示例*******/
    ILI9341_DispString_EN_CH(24, 0,   "  爱爱           爱爱");
    ILI9341_DispString_EN_CH(24, 16,  " 爱爱爱         爱爱爱");
	ILI9341_DispString_EN_CH(24, 32,  "爱爱爱爱爱   爱爱爱爱爱");
	ILI9341_DispString_EN_CH(24, 48,  " 爱爱爱         爱爱爱");
	ILI9341_DispString_EN_CH(24, 64,  "  爱爱爱       爱爱爱");
	ILI9341_DispString_EN_CH(24, 80,  "   爱爱爱     爱爱爱");
	ILI9341_DispString_EN_CH(24, 96,  "    爱爱爱   爱爱爱");
	ILI9341_DispString_EN_CH(24, 112, "     爱爱爱 爱爱爱");
	ILI9341_DispString_EN_CH(24, 128, "      爱爱^_^爱爱");
	
    /********显示变量示例*******/
    sprintf(dispBuff, "%04d ", testCNT);
	ILI9341_DispString_EN(104, 48, dispBuff);

    /*******显示图形示例******/
	LCD_SetFont(&Font24x32);
	
    /* 画直线 */
	LCD_ClearLine(LINE(5));		/* LINE4 = 32*5 = 160,清除单行文字 */
    LCD_SetTextColor(BLUE);
    ILI9341_DispStringLine_EN_CH(LINE(5), "画直线:");

    LCD_SetTextColor(RED);
    ILI9341_DrawLine(0, 176, 239, 319);
    ILI9341_DrawLine(239, 176, 0, 319);

    LCD_SetTextColor(YELLOW);
    ILI9341_DrawLine(0, 200, 239, 200);
    ILI9341_DrawLine(0, 300, 239, 300);

    LCD_SetTextColor(BLUE);
    ILI9341_DrawLine(20, 176, 20, 319);
    ILI9341_DrawLine(220, 176, 220, 319);

	HAL_Delay(2000);
    ILI9341_Clear(0, 16 * 11, LCD_X_LENGTH, LCD_Y_LENGTH - 16 * 11);	/* 清中下屏,显示全黑 */

    /*画矩形*/
	LCD_ClearLine(LINE(5));		/* LINE4 = 32*5 = 160,清除单行文字 */
    LCD_SetTextColor(BLUE);
    ILI9341_DispStringLine_EN_CH(LINE(5), "画矩形:");

    LCD_SetTextColor(RED);
    ILI9341_DrawRectangle(0, 176, 240, 144, 1);

    LCD_SetTextColor(YELLOW);
    ILI9341_DrawRectangle(80, 200, 120, 100, 0);

    LCD_SetTextColor(BLUE);
    ILI9341_DrawRectangle(120, 190, 100, 50, 1);

    HAL_Delay(2000);
    ILI9341_Clear(0, 16 * 11, LCD_X_LENGTH, LCD_Y_LENGTH - 16 * 11);	/* 清中下屏,显示全黑 */

    /* 画圆 */
    LCD_ClearLine(LINE(5));		/* LINE4 = 32*5 = 160,清除单行文字 */
    LCD_SetTextColor(BLUE);
    ILI9341_DispStringLine_EN_CH(LINE(5), "画圆:");

    LCD_SetTextColor(RED);
    ILI9341_DrawCircle(120, 250, 50, 0);

    LCD_SetTextColor(YELLOW);
    ILI9341_DrawCircle(120, 250, 30, 1);

    LCD_SetTextColor(BLUE);
    ILI9341_DrawCircle(120, 250, 10, 1);
	
    HAL_Delay(2000);
    ILI9341_Clear(0, 16 * 11, LCD_X_LENGTH, LCD_Y_LENGTH - 16 * 11);	/* 清中下屏,显示全黑 */
}

实验现象

实验环节2:LCD显示中英文(任意大小、任何类型、居中显示)

缩放字模

缩放字模
#define ZOOMMAXBUFF 16384
uint8_t zoomBuff[ZOOMMAXBUFF] = {0};	//用于缩放的缓存,最大支持到128*128
uint8_t zoomTempBuff[1024] = {0};

/**
 * @brief  缩放字模,缩放后的字模由1个像素点由8个数据位来表示
										0x01表示笔迹,0x00表示空白区
 * @param  in_width :原始字符宽度
 * @param  in_heig :原始字符高度
 * @param  out_width :缩放后的字符宽度
 * @param  out_heig:缩放后的字符高度
 * @param  in_ptr :字库输入指针		  注意:1pixel 1bit
 * @param  out_ptr :缩放后的字符输出指针 注意: 1pixel 8bit
 *		   out_ptr实际上没有正常输出,改成了直接输出到全局指针zoomBuff中
 * @param  en_cn :0为英文,1为中文
 * @retval 无
 */
void ILI9341_zoomChar(uint16_t in_width,	//原始字符宽度
                      uint16_t in_heig,		//原始字符高度
                      uint16_t out_width,	//缩放后的字符宽度
                      uint16_t out_heig,	//缩放后的字符高度
                      uint8_t *in_ptr,		//字库输入指针	注意:1pixel 1bit
                      uint8_t *out_ptr, 	//缩放后的字符输出指针 注意: 1pixel 8bit
                      uint8_t en_cn)		//0为英文,1为中文
{
    uint8_t *pts, *ots;
    //根据源字模及目标字模大小,设定运算比例因子,左移16是为了把浮点运算转成定点运算
    unsigned int xrIntFloat_16 = (in_width << 16) / out_width + 1;
    unsigned int yrIntFloat_16 = (in_heig << 16) / out_heig + 1;

    unsigned int srcy_16 = 0;
    unsigned int y, x;
    uint8_t *pSrcLine;

    uint16_t byteCount, bitCount;

    //检查参数是否合法
    if (in_width >= 32)
    {
        return;    //字库不允许超过32像素
    }

    if (in_width * in_heig == 0)
    {
        return;
    }

    if (in_width * in_heig >= 1024)
    {
        return;    //限制输入最大 32*32
    }

    if (out_width * out_heig == 0)
    {
        return;
    }

    if (out_width * out_heig >= ZOOMMAXBUFF)
    {
        return;    //限制最大缩放 128*128
    }

    pts = (uint8_t *)&zoomTempBuff;

    //为方便运算,字库的数据由1 pixel/1bit 映射到1pixel/8bit
    //0x01表示笔迹,0x00表示空白区
    if (en_cn == 0x00) //英文
    {
        //英文和中文字库上下边界不对,可在此处调整。需要注意tempBuff防止溢出
        for (byteCount = 0; byteCount < in_heig * in_width / 8; byteCount++)
        {
            for (bitCount = 0; bitCount < 8; bitCount++)
            {
                //把源字模数据由位映射到字节
                //in_ptr里bitX为1,则pts里整个字节值为1
                //in_ptr里bitX为0,则pts里整个字节值为0
                *pts++ = (in_ptr[byteCount] & (0x80 >> bitCount)) ? 1 : 0;
            }
        }
    }
    else //中文
    {
        for (byteCount = 0; byteCount < in_heig * in_width / 8; byteCount++)
        {
            for (bitCount = 0; bitCount < 8; bitCount++)
            {
                //把源字模数据由位映射到字节
                //in_ptr里bitX为1,则pts里整个字节值为1
                //in_ptr里bitX为0,则pts里整个字节值为0
                *pts++ = (in_ptr[byteCount] & (0x80 >> bitCount)) ? 1 : 0;
            }
        }
    }

    //zoom过程
    pts = (uint8_t *)&zoomTempBuff;	//映射后的源数据指针
    ots = (uint8_t *)&zoomBuff;		//输出数据的指针

    for (y = 0; y < out_heig; y++)	/*行遍历*/
    {
        unsigned int srcx_16 = 0;
        pSrcLine = pts + in_width * (srcy_16 >> 16);

        for (x = 0; x < out_width; x++) 		/*行内像素遍历*/
        {
            ots[x] = pSrcLine[srcx_16 >> 16]; 	//把源字模数据复制到目标指针中
            srcx_16 += xrIntFloat_16;			//按比例偏移源像素点
        }

        srcy_16 += yrIntFloat_16;				//按比例偏移源像素点
        ots += out_width;
    }

    /*!!!缩放后的字模数据直接存储到全局指针zoomBuff里了*/
    out_ptr = (uint8_t *)&zoomBuff;	//out_ptr没有正确传出,后面调用直接改成了全局变量指针!

    /*实际中如果使用out_ptr不需要下面这一句!!!只是因为out_ptr没有使用,会导致warning。强迫症*/
    out_ptr++;
}

缩放字模后显示字符
/**
 * @brief  利用缩放后的字模显示字符
 * @param  Xpos :字符显示位置x
 * @param  Ypos :字符显示位置y
 * @param  Font_width :字符宽度
 * @param  Font_Heig:字符高度
 * @param  c :要显示的字模数据
 * @param  DrawModel :是否反色显示
 * @retval 无
 */
void ILI9341_DrawChar_Ex(uint16_t usX, 			//字符显示位置x
                         uint16_t usY, 			//字符显示位置y
                         uint16_t Font_width, 	//字符宽度
                         uint16_t Font_Height,  //字符高度
                         uint8_t *c,			//字模数据
                         uint16_t DrawModel)	//是否反色显示
{
    uint32_t index = 0, counter = 0;

    //设置显示窗口
    ILI9341_OpenWindow(usX, usY, Font_width, Font_Height);

    ILI9341_Write_Cmd(CMD_SetPixel);

    //按字节读取字模数据
    //由于前面直接设置了显示窗口,显示数据会自动换行
    for (index = 0; index < Font_Height; index++)
    {
        //一位一位处理要显示的颜色
        for (counter = 0; counter < Font_width; counter++)
        {
            //缩放后的字模数据,以一个字节表示一个像素位
            //整个字节值为1表示该像素为笔迹
            //整个字节值为0表示该像素为背景
            if (*c++ == DrawModel)
            {
                ILI9341_Write_Data(CurrentBackColor);
            }
            else
            {
                ILI9341_Write_Data(CurrentTextColor);
            }
        }
    }
}

缩放字符后显示字符串
/**
 * @brief  利用缩放后的字模显示字符串
 * @param  Xpos :字符显示位置x
 * @param  Ypos :字符显示位置y
 * @param  Font_width :字符宽度,英文字符在此基础上/2。注意为偶数
 * @param  Font_Heig:字符高度,注意为偶数
 * @param  c :要显示的字符串
 * @param  DrawModel :是否反色显示
 * @retval 无
 */
void ILI9341_DisplayStringEx(uint16_t x, 		    //字符显示位置x
                             uint16_t y, 			//字符显示位置y
                             uint16_t Font_width,	//要显示的字体宽度,英文字符在此基础上/2。注意为偶数
                             uint16_t Font_Height,	//要显示的字体高度,注意为偶数
                             uint8_t *ptr,			//显示的字符内容
                             uint16_t DrawModel)    //是否反色显示


{
    uint16_t Charwidth = Font_width; //默认为Font_width,英文宽度为中文宽度的一半
    uint8_t *psr;
    uint8_t Ascii;	//英文
    uint16_t usCh;  //中文
    uint8_t ucBuffer [ WIDTH_CH_CHAR * HEIGHT_CH_CHAR / 8 ];

    while (*ptr != '\0')
    {
        /****处理换行*****/
        if ((x - ILI9341_DispWindow_X_Star + Charwidth) > LCD_X_LENGTH)
        {
            x = ILI9341_DispWindow_X_Star;
            y += Font_Height;
        }

        if ((y - ILI9341_DispWindow_Y_Star + Font_Height) > LCD_Y_LENGTH)
        {
            x = ILI9341_DispWindow_X_Star;
            y = ILI9341_DispWindow_Y_Star;
        }

        if (*ptr > 0x80) //如果是中文
        {
            Charwidth = Font_width;
            usCh = * (uint16_t *) ptr;
            usCh = (usCh << 8) + (usCh >> 8);
            GetGBKCode(ucBuffer, usCh);	//取字模数据
            //缩放字模数据,源字模为16*16
            ILI9341_zoomChar(WIDTH_CH_CHAR, HEIGHT_CH_CHAR, Charwidth, Font_Height, (uint8_t *)&ucBuffer, psr, 1);
            //显示单个字符
            ILI9341_DrawChar_Ex(x, y, Charwidth, Font_Height, (uint8_t *)&zoomBuff, DrawModel);
            x += Charwidth;
            ptr += 2;
        }
        else
        {
            Charwidth = Font_width / 2;
            Ascii = *ptr - 32;
            //使用16*24字体缩放字模数据
            ILI9341_zoomChar(16, 24, Charwidth, Font_Height,
                             (uint8_t *)&Font16x24.table[Ascii * Font16x24.Height * Font16x24.Width / 8], psr, 0);
            //显示单个字符
            ILI9341_DrawChar_Ex(x, y, Charwidth, Font_Height, (uint8_t *)&zoomBuff, DrawModel);
            x += Charwidth;
            ptr++;
        }
    }
}

/**
 * @brief  利用缩放后的字模显示字符串(沿Y轴方向)
 * @param  Xpos :字符显示位置x
 * @param  Ypos :字符显示位置y
 * @param  Font_width :字符宽度,英文字符在此基础上/2。注意为偶数
 * @param  Font_Heig:字符高度,注意为偶数
 * @param  c :要显示的字符串
 * @param  DrawModel :是否反色显示
 * @retval 无
 */
void ILI9341_DisplayStringEx_YDir(uint16_t x, 		//字符显示位置x
                                  uint16_t y, 				//字符显示位置y
                                  uint16_t Font_width,	//要显示的字体宽度,英文字符在此基础上/2。注意为偶数
                                  uint16_t Font_Height,	//要显示的字体高度,注意为偶数
                                  uint8_t *ptr,					//显示的字符内容
                                  uint16_t DrawModel)  //是否反色显示
{
    uint16_t Charwidth = Font_width; //默认为Font_width,英文宽度为中文宽度的一半
    uint8_t *psr;
    uint8_t Ascii;	//英文
    uint16_t usCh;  //中文
    uint8_t ucBuffer [ WIDTH_CH_CHAR * HEIGHT_CH_CHAR / 8 ];

    while (*ptr != '\0')
    {
        //统一使用汉字的宽高来计算换行
        if ((y - ILI9341_DispWindow_X_Star + Font_width) > LCD_X_LENGTH)
        {
            y = ILI9341_DispWindow_X_Star;
            x += Font_width;
        }

        if ((x - ILI9341_DispWindow_Y_Star + Font_Height) > LCD_Y_LENGTH)
        {
            y = ILI9341_DispWindow_X_Star;
            x = ILI9341_DispWindow_Y_Star;
        }

        if (*ptr > 0x80) //如果是中文
        {
            Charwidth = Font_width;
            usCh = * (uint16_t *) ptr;
            usCh = (usCh << 8) + (usCh >> 8);
            GetGBKCode(ucBuffer, usCh);	//取字模数据
            //缩放字模数据,源字模为16*16
            ILI9341_zoomChar(WIDTH_CH_CHAR, HEIGHT_CH_CHAR, Charwidth, Font_Height, (uint8_t *)&ucBuffer, psr, 1);
            //显示单个字符
            ILI9341_DrawChar_Ex(x, y, Charwidth, Font_Height, (uint8_t *)&zoomBuff, DrawModel);
            y += Font_Height;
            ptr += 2;
        }
        else
        {
            Charwidth = Font_width / 2;
            Ascii = *ptr - 32;
            //使用16*24字体缩放字模数据
            ILI9341_zoomChar(16, 24, Charwidth, Font_Height,
                             (uint8_t *)&Font16x24.table[Ascii * Font16x24.Height * Font16x24.Width / 8], psr, 0);
            //显示单个字符
            ILI9341_DrawChar_Ex(x, y, Charwidth, Font_Height, (uint8_t *)&zoomBuff, DrawModel);
            y += Font_Height;
            ptr++;
        }
    }
}

实验测试

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

/*用于测试各种液晶的函数*/
void LCD_Test(void)
{
    /*演示显示变量*/
    static uint8_t testCNT = 0;
	static float testFloatCNT = 0;	
	char dispBuff[100];
	char *pStr = 0;

    testCNT++;
	testFloatCNT += 0.1;
	
    LCD_SetFont(&Font8x16);                             // 设置字体类型:8*16,16*24,24*32
    LCD_SetColors(RED, BLACK);                          // 设置前景和背景色
    ILI9341_Clear(0, 0, LCD_X_LENGTH, LCD_Y_LENGTH);	// 清屏,显示全黑
	
    //显示指定大小的字符
    ILI9341_DisplayStringEx(0, 0, 48, 48, (uint8_t *)"博客:", 0);
	ILI9341_DisplayStringEx(120, 0, 24, 24, (uint8_t *)"couvrir", 0);
	
	/********显示字符串示例*******/
    ILI9341_DispString_EN_CH (120, 24, "洪荒猛兽");
	
    /********显示变量示例*******/
    LCD_SetTextColor(GREEN);

    /*使用c标准库把变量转化成字符串*/
    sprintf(dispBuff, "显示变量: %d ", testCNT);
    LCD_ClearLine(LINE(3));
    ILI9341_DispStringLine_EN_CH(LINE(3), dispBuff);

	sprintf(dispBuff,"显示浮点型变量: %f ",testFloatCNT);
	LCD_ClearLine(LINE(4));
    ILI9341_DispStringLine_EN_CH(LINE(4), dispBuff);

	sprintf(dispBuff,"浮点型(保留2位小数): %.2f ",testFloatCNT);
	LCD_ClearLine(LINE(5));
    ILI9341_DispStringLine_EN_CH(LINE(5), dispBuff);

	/********居中显示示例*******/
	LCD_SetTextColor(YELLOW);

	pStr = "插入2个英文空格示例";
	//使用 %*c 在字符串前插入指定个数的英文空格
	sprintf(dispBuff, "%*c%s", 2, ' ', pStr);
	LCD_ClearLine(LINE(6));
	ILI9341_DispStringLine_EN_CH(LINE(6), dispBuff);

	ILI9341_DispStringLine_EN_CH(LINE(7), "居中示例:");
	pStr = "ABCDEF";
	//居中时,要插入的空格个数 = (液晶宽度/单个字体宽度 - 字符串长度)/2
	sprintf(dispBuff, "%*c%s", ( (LCD_X_LENGTH/(((sFONT *)LCD_GetFont())->Width) ) - strlen(pStr))/2, ' ', pStr);
	LCD_ClearLine(LINE(8));
	ILI9341_DispStringLine_EN_CH(LINE(8),dispBuff);

	pStr = "中文居中示例";
	//居中时,要插入的空格个数 = (液晶宽度/字体宽度 - 字符串长度)/2
	//strlen计算长度时,一个中文等于2个字节,即2个英文字符,而且插入的是英文空格
	//所以用(WIDTH_CH_CHAR/2)来计算字体宽度
	sprintf(dispBuff, "%*c%s", ( LCD_X_LENGTH/(WIDTH_CH_CHAR/2) - strlen(pStr))/2, ' ', pStr);
	LCD_ClearLine(LINE(9));
	ILI9341_DispStringLine_EN_CH(LINE(9),dispBuff);
	
    /*******显示图形示例******/
	LCD_SetFont(&Font24x32);
	
    /* 画直线 */
	LCD_ClearLine(LINE(5));		/* LINE4 = 32*5 = 160,清除单行文字 */
    LCD_SetTextColor(BLUE);
    ILI9341_DispStringLine_EN_CH(LINE(5), "画直线:");

    LCD_SetTextColor(RED);
    ILI9341_DrawLine(0, 176, 239, 319);
    ILI9341_DrawLine(239, 176, 0, 319);

    LCD_SetTextColor(YELLOW);
    ILI9341_DrawLine(0, 200, 239, 200);
    ILI9341_DrawLine(0, 300, 239, 300);

    LCD_SetTextColor(BLUE);
    ILI9341_DrawLine(20, 176, 20, 319);
    ILI9341_DrawLine(220, 176, 220, 319);

	HAL_Delay(2000);
    ILI9341_Clear(0, 16 * 11, LCD_X_LENGTH, LCD_Y_LENGTH - 16 * 11);	/* 清中下屏,显示全黑 */

    /*画矩形*/
	LCD_ClearLine(LINE(5));		/* LINE4 = 32*5 = 160,清除单行文字 */
    LCD_SetTextColor(BLUE);
    ILI9341_DispStringLine_EN_CH(LINE(5), "画矩形:");

    LCD_SetTextColor(RED);
    ILI9341_DrawRectangle(0, 176, 240, 144, 1);

    LCD_SetTextColor(YELLOW);
    ILI9341_DrawRectangle(80, 200, 120, 100, 0);

    LCD_SetTextColor(BLUE);
    ILI9341_DrawRectangle(120, 190, 100, 50, 1);

    HAL_Delay(2000);
    ILI9341_Clear(0, 16 * 11, LCD_X_LENGTH, LCD_Y_LENGTH - 16 * 11);	/* 清中下屏,显示全黑 */

    /* 画圆 */
    LCD_ClearLine(LINE(5));		/* LINE4 = 32*5 = 160,清除单行文字 */
    LCD_SetTextColor(BLUE);
    ILI9341_DispStringLine_EN_CH(LINE(5), "画圆:");

    LCD_SetTextColor(RED);
    ILI9341_DrawCircle(120, 250, 50, 0);

    LCD_SetTextColor(YELLOW);
    ILI9341_DrawCircle(120, 250, 30, 1);

    LCD_SetTextColor(BLUE);
    ILI9341_DrawCircle(120, 250, 10, 1);
	
    HAL_Delay(2000);
    ILI9341_Clear(0, 16 * 11, LCD_X_LENGTH, LCD_Y_LENGTH - 16 * 11);	/* 清中下屏,显示全黑 */
}

实验现象

作者:Couvrir洪荒猛兽

物联沃分享整理
物联沃-IOTWORD物联网 » STM32-LCD中英文显示及应用实例详解

发表评论