当前位置: 首页 > news >正文

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*32LCD_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 1bituint8_t *out_ptr, 	//缩放后的字符输出指针 注意: 1pixel 8bituint8_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, 			//字符显示位置xuint16_t usY, 			//字符显示位置yuint16_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, 		    //字符显示位置xuint16_t y, 			//字符显示位置yuint16_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*16ILI9341_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, 		//字符显示位置xuint16_t y, 				//字符显示位置yuint16_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*16ILI9341_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*32LCD_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";//居中时,要插入的空格个数 = (液晶宽度/单个字体宽度 - 字符串长度)/2sprintf(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);	/* 清中下屏,显示全黑 */
}

实验现象

相关文章:

STM32-LCD中英文显示及应用

目录 字符编码 ASCII码&#xff08;8位&#xff09; 中文编码&#xff08;16位&#xff09; GB2312标准 GBK编码 GB18030标准&#xff08;32位&#xff09; Big5编码 Unicode字符集和编码 UTF-32&#xff08;32位&#xff09; UTF-16&#xff08;16位/32位&#xff0…...

13.4web自动化测试(Selenium3+Java)

一.定义 用来做web自动化测试的框架. 二.特点 1.支持各种浏览器. 2.支持各种平台(操作系统). 3.支持各种编程语言. 4.有丰富的api. 三.工作原理 四.搭环境 1.对照Chrome浏览器版本号,下载ChromeDriver,配置环境变量,我直接把.exe文件放在了jdk安装路径的bin文件夹下了(j…...

P1966 [NOIP2013 提高组] 火柴排队

洛谷的一道原题&#xff0c;方法有很多&#xff0c;树状数组以及排序&#xff0c;对刚学树状数组的人来说用排序会比较好理解。 本题最重要的结论就是&#xff0c;要保证两个数组中相同位置的差最小&#xff0c;但是不一定两个数组中数值相同&#xff0c;所以只需要保证相同位…...

Linux文件I/O

下面的内容需要了解系统调用&#xff0c;可看下面的链接&#xff1a; 系统调用来龙去脉-CSDN博客 1.底层文件IO和标准IO 这里指的是操作系统提供的IO服务&#xff0c;不同于ANSI建立的标准IO。 底层IO和标准IO各自所使用的函数&#xff1a; 区别&#xff1a; 1.底层文件IO不…...

卡巴斯基2009杀毒软件

下载地址&#xff1a;https://user.qzone.qq.com/512526231/main https://user.qzone.qq.com/3503787372/main...

Docker 容器服务的注册、发现及Docker安全

目录 Docker容器服务的注册和发现 1、什么是服务注册与发现&#xff1f; 2、什么是consul consul的部署 1、环境准备 2、部署consul服务器 1&#xff09;建立 Consul 服务 2&#xff09;设置代理&#xff0c;在后台启动 consul 服务端 3&#xff09;查看集群信息 4&a…...

UE5 Blueprint发送http请求

一、下载插件HttpBlueprint、Json Blueprint Utilities两个插件是互相依赖的&#xff0c;启用&#xff0c;重启项目 目前两个是Beta的状态&#xff0c;如果你使用的平台支持就可以使用&#xff0c;我们的项目因为需要取Header的值&#xff0c;所有没法使用这两个插件&#xff0…...

SpringBoot 分布式验证码登录方案

前言 为了防止验证系统被暴力破解&#xff0c;很多系统都增加了验证码效验&#xff0c;比较常见的就是图片二维码&#xff0c;业内比较安全的是短信验证码&#xff0c;当然还有一些拼图验证码&#xff0c;加入人工智能的二维码等等&#xff0c;我们今天的主题就是前后端分离的…...

vite.config.js文件配置代理设置VITE_APP_BASE_API

.env.development文件 ENV development # base api VITE_APP_BASE_API /dev-api.env.production文件 ENV production # base api VITE_APP_BASE_API /apidefine: {process.env: {VITE_APP_BASE_API: https://xxx.com}},server: {hmr: true, // vue3 vite配置热更新不用手动…...

优橙内推海南专场——5G网络优化(中高级)工程师

可加入就业QQ群&#xff1a;801549240 联系老师内推简历投递邮箱&#xff1a;hrictyc.com 内推公司1&#xff1a;南京华苏科技有限公司 内推公司2&#xff1a;南京欣网通信股份有限公司 内推公司3&#xff1a;广东华讯工程有限公司 南京华苏科技有限公司 南京华苏科技有…...

5083: 【递推】走方格

题目描述 在平面上有一些二维的点阵。 这些点的编号就像二维数组的编号一样&#xff0c;从上到下依次为第 1 至第 n 行&#xff0c;从左到右依次为第 1 至第 m 列&#xff0c;每一个点可以用行号和列号来表示。 现在有个人站在第 1 行第 1 列&#xff0c;要走到第 n 行第 m …...

多种方式计算当天与另一天的间隔天数 Java实现

这里不会记录纯原生写法&#xff0c;因为现在基本都是被工具类封装好的&#xff0c;所以会记录好用的工具类来简化开发&#xff0c;当然自己可以研究写一个年月日各自做减法的纯原生工具类。 踩坑处(System.currentTimeMillis) 这里指的是使用System.currentTimeMillis()方法。…...

Python基础学习004——for循环与字符串

""" 1.for循环基本语法 2.做指定次数的循环,range()函数 3.continue的使用 4.字符串的定义与使用:转义符,原生字符 5.获取字符串长度,字符串索引的使用 6.切片,翻转字符串 7.字符串的查找find 8.字符串的替换replace 9.字符串的拆分split 10.字符串的链接join &…...

【发展史】鼠标的发展史

最早可以追溯到1952年&#xff0c;皇家加拿大海军将5针保龄球放在能够侦测球面转动的硬件上&#xff0c;这个硬件再将信息转化成光标在屏幕上移动&#xff0c;用作军事计算机输入。这是我们能够追溯到的最早的依靠手部运动进行光标移动的输入设备。但当时这个东西不叫鼠标&…...

ThinkPHP6 多应用模式之验证码模块的配置与验证

Thinphp6 官方的验证码模块的配置是有问题的&#xff0c;或者说需要手工配置。 在配置期间&#xff0c;我尝试了多种&#xff08;包括按照官方文档、路由等&#xff09;方法都验证失败。 存在2个问题&#xff1a; 1、多应用模式下&#xff0c;验证码的配置文件依然读取全局的…...

数据结构笔记——树和图(王道408)(持续更新)

文章目录 传送门前言树&#xff08;重点&#xff09;树的数据结构定义性质 二叉树的数据结构定义性质储存结构 二叉树算法先中后序遍历层次展开法递归模拟法 层次遍历遍历序列逆向构造二叉树 线索二叉树&#xff08;难点&#xff09;定义线索化的本质 二叉树线索化线索二叉树中…...

Redis 主从

目录 ​编辑一、构建主从架构 1、集群结构 2、准备实例和配置 &#xff08;1&#xff09;创建目录 &#xff08;2&#xff09;修改原始配置 &#xff08;3&#xff09;拷贝配置文件到每个实例目录 &#xff08;4&#xff09;修改每个实例的端口&#xff0c;工作目录 &a…...

嵌入式学习笔记(63)位操作实战

(1)给定一个整型数a&#xff0c;设置a的bit3&#xff0c;保证其他位不变。 a | (1<<3) (2)给定一个整形数a&#xff0c;设置a的bit3~bit7&#xff0c;保持其他位不变 a | (0x1f<<3) (3)给定一个整型数a&#xff0c;清除a的bit15&#xff0c;保证其他位不变。 a …...

8位机adc采样正弦波频率

相位/峰峰值高电平&#xff1f; 检 测峰值电压&#xff1f; y 开始计数 检测零电压 y 计数器值16ms/20ms 斩波开x关x延时 tt 频率 1/2t 电路 增减常数 aT...

react中使用监听

在 React 中&#xff0c;您可以使用 addEventListener 函数来监听事件。以下是一个示例&#xff1a; import React, { useRef, useEffect } from react;function App() {const inputRef useRef(null);useEffect(() > {inputRef.current.addEventListener(input, handleInp…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

C# 类和继承(抽象类)

抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

【生成模型】视频生成论文调研

工作清单 上游应用方向&#xff1a;控制、速度、时长、高动态、多主体驱动 类型工作基础模型WAN / WAN-VACE / HunyuanVideo控制条件轨迹控制ATI~镜头控制ReCamMaster~多主体驱动Phantom~音频驱动Let Them Talk: Audio-Driven Multi-Person Conversational Video Generation速…...

C++课设:简易日历程序(支持传统节假日 + 二十四节气 + 个人纪念日管理)

名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 专栏介绍:《编程项目实战》 目录 一、为什么要开发一个日历程序?1. 深入理解时间算法2. 练习面向对象设计3. 学习数据结构应用二、核心算法深度解析…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...

AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)

Name&#xff1a;3ddown Serial&#xff1a;FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名&#xff1a;Axure 序列号&#xff1a;8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...

如何通过git命令查看项目连接的仓库地址?

要通过 Git 命令查看项目连接的仓库地址&#xff0c;您可以使用以下几种方法&#xff1a; 1. 查看所有远程仓库地址 使用 git remote -v 命令&#xff0c;它会显示项目中配置的所有远程仓库及其对应的 URL&#xff1a; git remote -v输出示例&#xff1a; origin https://…...