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*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码(8位) 中文编码(16位) GB2312标准 GBK编码 GB18030标准(32位) Big5编码 Unicode字符集和编码 UTF-32(32位) UTF-16(16位/32位࿰…...

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

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

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

卡巴斯基2009杀毒软件
下载地址:https://user.qzone.qq.com/512526231/main https://user.qzone.qq.com/3503787372/main...

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

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

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

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群:801549240 联系老师内推简历投递邮箱:hrictyc.com 内推公司1:南京华苏科技有限公司 内推公司2:南京欣网通信股份有限公司 内推公司3:广东华讯工程有限公司 南京华苏科技有限公司 南京华苏科技有…...

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

多种方式计算当天与另一天的间隔天数 Java实现
这里不会记录纯原生写法,因为现在基本都是被工具类封装好的,所以会记录好用的工具类来简化开发,当然自己可以研究写一个年月日各自做减法的纯原生工具类。 踩坑处(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年,皇家加拿大海军将5针保龄球放在能够侦测球面转动的硬件上,这个硬件再将信息转化成光标在屏幕上移动,用作军事计算机输入。这是我们能够追溯到的最早的依靠手部运动进行光标移动的输入设备。但当时这个东西不叫鼠标&…...

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

数据结构笔记——树和图(王道408)(持续更新)
文章目录 传送门前言树(重点)树的数据结构定义性质 二叉树的数据结构定义性质储存结构 二叉树算法先中后序遍历层次展开法递归模拟法 层次遍历遍历序列逆向构造二叉树 线索二叉树(难点)定义线索化的本质 二叉树线索化线索二叉树中…...

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

嵌入式学习笔记(63)位操作实战
(1)给定一个整型数a,设置a的bit3,保证其他位不变。 a | (1<<3) (2)给定一个整形数a,设置a的bit3~bit7,保持其他位不变 a | (0x1f<<3) (3)给定一个整型数a,清除a的bit15,保证其他位不变。 a …...

8位机adc采样正弦波频率
相位/峰峰值高电平? 检 测峰值电压? y 开始计数 检测零电压 y 计数器值16ms/20ms 斩波开x关x延时 tt 频率 1/2t 电路 增减常数 aT...

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

Java基础总结
0、Java语言 1.java和c 2.编译和解释 3.jre和jdk,jvm 简单来说,编译型语言是指编译器针对特定的操作系统将源代码一次性翻译成可被该平台执行的机器码;解释型语言是指解释器对源程序逐行解释成特定平台的机器码并立即执行。 Java 语言既具…...

基于SSM的OA办公系统
末尾获取源码 开发语言:Java Java开发工具:JDK1.8 后端框架:SSM 前端:Vue 数据库:MySQL5.7和Navicat管理工具结合 服务器:Tomcat8.5 开发软件:IDEA / Eclipse 是否Maven项目:是 目录…...

【第25例】IPD体系进阶:需求分析团队RAT
目录 简介 RAT CSDN学院相关内容推荐 作者简介 简介 RAT是英文Requirement Analysis Team英文首字母的简称,也即需求分析团队,每个产品线都需要设定对应的一个RAT的组织。 RAT主要负责产品领域内需求的分析活动,是RMT的支撑团队: 这个时候可以将RAT细化为PL-RAT团队,…...

5G与无人驾驶:引领未来交通的新潮流
5G与无人驾驶:引领未来交通的新潮流 随着5G技术的快速发展和普及,无人驾驶技术也日益受到人们的关注。5G技术为无人驾驶提供了更高效、更准确、更及时的通信方式,从而改变了我们对交通出行的认知和使用方式。本文将探讨5G技术在无人驾驶领域的…...

FreeRTOS学习2018.6.27
《FreeRTOS学习》 1.freeRTOS基本功能函数: 定义任务:ATaskFunction(); 创建任务:xTaskCreate(); 改优先级:vTaskPrioritySet(); 系统延时:vTaskDelay(); 精确延时:vTaskDelayUntil(); 空闲任务钩子函数&…...

【异常】理解Java中的异常处理机制
标题:理解Java中的异常处理机制 摘要: 异常处理是Java编程中的重要概念之一,它可以帮助开发者识别和处理程序运行过程中的错误和异常情况。本文将深入探讨Java中的异常处理机制,包括异常的分类、异常处理的语法和最佳实践。通过示…...

很久没写JAVA程序了,原来用GMAIL发送邮件这么简单
写完代码,配置了GMAIL,死活发布出去,碰到了错误535-5.7.8 Username and Password not accepted. 首先先写代码,然后配置GMAIL. 第一写代码: 当你需要在 Spring Boot 中实现邮件通知时,你可以使用 Spring 的 JavaMailSender 来发送电子邮件。首先,确保你的 Spring Boo…...

Spring Security获得认证流程解析(示意图)
建议先看完Spring Security总体架构介绍和Spring Security认证架构介绍,然后从FilterChainProxy的doFilterInternal函数开始,配合文章进行debug以理解Spring Security认证源码的执行流程。 在之前的Spring Security认证架构介绍中,我们已经知…...

scrapy typeerror: attrs() got an unexpected keyword argument ‘eq‘
问题: scrapy 爬虫程序报错 scrapy typeerror: attrs() got an unexpected keyword argument eq原因: Twisted 版本过高 解决方法: # 安装指定版本 pip install --index https://pypi.mirrors.ustc.edu.cn/simple/ Twisted21.7.0# 几个可…...

非侵入式负荷检测与分解:电力数据挖掘新视角
电力数据挖掘 概述案例背景分析目标分析过程数据准备数据探索缺失值处理 属性构造设备数据周波数据模型训练 性能度量推荐阅读 主页传送门:📀 传送 概述 摘要:本案例将根据已收集到的电力数据,深度挖掘各电力设备的电流、电压和功…...