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个字节表示字符说明
0x680x69hi两个字节的值都小于127(0x7f),使用ASCII解码
0xb00xa1两个字节的值都大于127(0x7f),使用GB2312解码

GBK编码

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

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

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

0xb0

0xa10x68啊h第1、2个字节使用GBK解码,第3个字节使用ASCII解码
0xb00x560x68癡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编码
A0x410x0000 0041大端格式:0x0000 0041
0xB0A10x0000 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);	/* 清中下屏,显示全黑 */
}

实验现象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/103883.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[AutoSar NVM] 存储架构

依AutoSAR及公开知识辛苦整理&#xff0c;禁止转载。 专栏 《深入浅出AutoSAR》&#xff0c; 全文 2900 字. 图片来源&#xff1a; 知乎 汽车的ECU内存中有很多不同类型的变量&#xff0c;这些变量包括了车辆各个系统和功能所需的数据。大部分变量在ECU掉电后就会丢失&#x…

AI的Prompt是什么

一.AI的Prompt的作用 在人工智能&#xff08;AI&#xff09;中&#xff0c;"Prompt"通常指的是向AI系统提供的输入或指令&#xff0c;用于引导AI进行特定的操作或生成特定的输出。例如&#xff0c;在一个对话型AI系统中&#xff0c;用户输入的问题就是一个prompt&…

高校教务系统登录页面JS分析——西安科技大学

高校教务系统密码加密逻辑及JS逆向 本文将介绍高校教务系统的密码加密逻辑以及使用JavaScript进行逆向分析的过程。通过本文&#xff0c;你将了解到密码加密的基本概念、常用加密算法以及如何通过逆向分析来破解密码。 本文仅供交流学习&#xff0c;勿用于非法用途。 一、密码加…

《数字图像处理》作业一:题目+学习笔记

Hi,学习进步,共同加油💪 1、选择题 (每小题3分,总计24分) (1)下列哪种图像属于数字图像( ) A、电影胶片;B、普通照片;C、手机拍照;D、眼前看到的景物 数字图像是由离散的像素点组成的图像,可以通过数值表示。根据选项,可以排除A(电影胶片)和B(普通…

Unity中Shader的ShaderLOD

文章目录 前言一、ShaderLOD的使用步骤1、ShaderLOD使用在不同的SubShader中&#xff0c;用于区分SubShader所对应的配置2、在 C# 中使用 Shader.globalMaximumLOD 赋值来选择不同的 SubShader,以达到修改配置对应Shader的效果3、在设置LOD时&#xff0c;是需要和程序讨论统一 …

Git简明教程

1.Git的定位 在我们自己开发项目的过程中&#xff0c;经常会遇到这样的情况&#xff0c;为了防止代码丢失&#xff0c;或者新变更的代码影响到原有的代码功能&#xff0c;为了在失误后能恢复到原来的版本&#xff0c;不得不复制出一个副本,比如&#xff1a;“坦克大战1.0”“坦…

创建 Edge 浏览器扩展教程(下)

创建 Edge 浏览器扩展教程&#xff08;下&#xff09; 创建扩展教程&#xff0c;第 2 部分1&#xff1a;更新弹出窗口.html以包含按钮2&#xff1a;更新弹出窗口.html在浏览器选项卡顶部显示图像3&#xff1a;创建弹出式 JavaScript 以发送消息4&#xff1a;从任何浏览器选项卡…

react createElement 和 cloneElement 有什么区别?

前言 什么是react React是一个用于构建用户界面的JavaScript库。它旨在帮助开发人员构建可维护、高性能的应用程序界面。React的核心思想是组件化&#xff0c;它允许开发人员将用户界面划分为小块组件&#xff0c;每个组件负责自己的渲染和行为。这种组件化的方法使得代码更容易…

k8s集群镜像下载加gradana监控加elk日志收集加devops加秒杀项目

展示 1.配套资料2.devops 3.elk日志收集 4.grafana监控 5.dashboard![在这里插入图片描述](https://img-blog.csdnimg.cn/bf294f9fd98e4c038858a6bf5c34dbdc.png 目的 学习k8s来来回回折腾很久了&#xff0c;光搭个环境就能折腾几天。这次工作需要终于静下心来好好学习了一…

经管博士科研基础【26】海塞矩阵

1. 海塞矩阵 海塞矩阵是一个由多变量实值函数的所有二阶偏导数组成的方块矩阵。 一元函数就是二阶导,多元函数就是二阶偏导组成的矩阵。求向量函数最小值时可以使用,矩阵正定是最小值存在的充分条件。经济学中常常遇到求最优的问题,目标函数是多元非线性函数的极值问题,尚…

Warning: ‘Destination Folder‘ contains 1 space.【Anaconda安装】

报错内容如下&#xff1a; 意思就是说你的安装路径下不要有空格哈哈&#xff0c;有空格就不行&#xff0c;比如&#xff1a; "D:\Program Files\Anaconda3"中间就有空格&#xff0c;Program与Files之间。 换个路径&#xff0c;例如&#xff1a; 就可以了。

【技能树笔记】网络篇——练习题解析(九)

目录 前言 一、OSPF双栈 1.1 OSPFv3 LSA 1.2 OSPFv3 二、ISIS双栈 2.1 ISISv6 2.2 ISIS高级特性 三、BGP双栈 四、PIM双栈 总结 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filot…

python—openpyxl操作excel详解

前言 openpyxl属于第三方模块&#xff0c;在python中用来处理excel文件。 可以对excel进行的操作有&#xff1a;读写、修改、调整样式及插入图片等。 但只能用来处理【 .xlsx】 后缀的excel文件。 使用前需要先安装&#xff0c;安装方法&#xff1a; pip install openpyxl…

Hadoop3教程(二十七):(生产调优篇)HDFS读写压测

文章目录 &#xff08;146&#xff09;HDFS压测环境准备&#xff08;147&#xff09;HDFS读写压测写压测读压测 参考文献 &#xff08;146&#xff09;HDFS压测环境准备 对开发人员来讲&#xff0c;压测这个技能很重要。 假设你刚搭建好一个集群&#xff0c;就可以直接投入生…

华为数通方向HCIP-DataCom H12-831题库(多选题:61-80)

第61题 在MPLS VPN中,为了区分使用相同地址空间的IPV4前缀,将IPV4的地址增加了RD值,下列选项描述正确的是: A、在PE设备上,每一个VPN实例都对应一个RD值,同一PE设备上,必须保证RD值唯一 B、RD可用于来控制VPN路由信息的发布 C、RD在传递过程中作为BGP的扩展团体性封装在…

Docker镜像仓库

Docker镜像仓库 一、Docker镜像的创建1.1、基于已有镜像创建1.2、基于本地模板创建1.3、基于Dockerfile创建&#xff08;使用最广泛&#xff09;1.3.1、联合文件系统&#xff08;UnionFS&#xff09;1.3.2、镜像加载原理1.3.3、Dockerfile1.3.4、Docker 镜像结构的分层 二、如何…

【JavaScript】深入浅出理解事件循环

1. 浏览器的进程模型 1.1 进程 程序运行需要有它自己专属的内存空间&#xff0c;可以把这块内存空间简单的理解为进程。 每个应用至少有一个进程&#xff0c;进程之间相互独立&#xff0c;即使要通信&#xff0c;也需要双方同意。 1.2 线程 有了进程后&#xff0c;就可以运…

uniapp: 本应用使用HBuilderX x.x.xx 或对应的cli版本编译,而手机端SDK版本是 x.x.xx。不匹配的版本可能造成应用异常。

文章目录 前言一、原因分析二、解决方案2.1、方案一&#xff1a;更新HbuilderX版本2.2、方案二&#xff1a;设置固定的版本2.3、方案三&#xff1a;忽略版本&#xff08;不推荐&#xff09; 三、总结四、感谢 前言 项目场景&#xff1a;示例&#xff1a;通过使用HbuilderX打包…

idea 设置serlvet 类模板(快捷生成servlet类)

我的版本是idea2020.3.4&#xff0c;博客中有相应安装教程&#xff0c;其他版本设置类似&#xff1a; 1.选择文件-->设置 2.选择编辑器-->文件和代码模板-->其他 3.选择Web-->Servlet Annotated Class.java-->复制相应模板&#xff0c;下面顺便设置了注释模板 …