-
2019-10-25 19:13:47
前言
DOS功能调用
DOS利用软件中断方式提供系统功能。
中断调用指令是“INT N”,其中N表示调用的中断号、即中断0~中断255号。
DOS系统调用一般有如下4个步骤:
(1)在AH寄存器中设置系统功能调用号
(2)在指定寄存器中设置入口参数
(3)用中断调用指令(INT N)执行功能调用
(4)根据出口参数分析功能调用执行情况
DOS功能调用的中断号主要是21H,利用AH寄存器区别各个子功能。子功能号 功能 入口参数 出口参数 AH=01H 从标准输入设备输入一个字符 AL=输入字符的ASCII码 AH=02H 向标准输出设备输出一个字符 DL=字符的ASCII码 AH = 09H 显示字符串 DS:DX=缓冲区首址 AH = 4CH 带返回码的结束 AL=进程返回码 源代码
;显示字符串 .model small .stack .data msg db 'hello,Assembly!',13,10,'$';在dos需要利用'\r\n'使光标下一行首位置(回车换行) .code .startup mov dx,offset msg mov ah,9 ;//调用dos 9号功能号输出字符串,以$结束 int 21h .exit end
利用库函数
;利用库函数显示字符串 include io.inc .model small .stack .data msg db 'hello,Assembly!',13,10,0;在dos需要利用'\r\n'使光标下一行首位置(回车换行) .code .startup mov ax,offset msg call dispmsg ; 利用库函数字符串的结束符为0 .exit end
库函数实现
;自己实现函数显示字符串 .model small .stack .data msg db 'hello,Assembly!',13,10,0;在dos需要利用'\r\n'使光标下一行首位置(回车换行) .code .startup mov ax,offset msg call dispmsg ; .exit dispmsg proc ;定义过程 ;设置入口参数,以0结束 push ax push bx push dx ;保存寄存器的内容 mov bx,ax again:mov al,byte ptr [bx] Test al,al ;判断al是否为0 jz ex mov ah,2 mov dl,al int 21h inc bx jmp again ex: pop dx pop bx pop ax ret dispmsg endp;过程结束 end
更多相关内容 -
1602字符液晶显示
2019-12-19 14:44:04环境 软件 uVision V4.02 ISIS Professional 7.8 芯片 AT89C51 LM016L(LCD) 仿真图环境
软件
- uVision V4.02
- ISIS Professional 7.8
芯片
- AT89C51
- LM016L(LCD)
仿真图
实现效果
实现功能有四个
- 水平滚动显示字符串
- 带光标显示随机算术式
- 全码表字符显示
- CGRAM自定义字符显示
相关代码及资源
https://github.com/duganlx/DSP
操作小记
LCD1602相关函数编写
指令表
指令说明
上述表中,1为高电平、0为低电平
- 指令1:清显示:,光标复位到地址00H位置
- 指令2:光标返回:,光标返回到地址00H
- 指令3:光标和显示模式设置
- I/D:光标移动方向,1:右移,0:左移
- S:屏幕上所有文字是否左移动或右移:1:有效,0:无效
- 指令4:显示开关控制
- D:控制整体显示的开关,1:开显示,0:关显示
- C:控制光标的开关,1:有光标,0:无光标
- B:控制光标是否闪烁,1:闪烁,0:不闪烁
- 指令5:光标或显示移位S/C:1:移动显示的文字,0:移动光标
- 指令6:功能设置命令
- DL:1:4位总线,0:8位总线(有些模块反过来,比如这里所用的就是)
- N:0:单行显示,1:双行显示
- F:0: 5 ∗ 7 5*7 5∗7的点阵字符,1: 5 ∗ 10 5*10 5∗10的点阵字符
- 指令7:字符发生器RAM地址设置
- 指令8:DDRAM地址设置
- 指令9:读忙信号和光标地址
- BF:1:忙,此时模块不能接收命令或数据,0:不忙
- 指令10:写数据
- 指令11:读数据
其他说明
- 液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平(不忙),否则该指令失效
- 当显示字符时要先输入显示字符地址,以下是内部显示地址
所以若要写入字符到第二行第一个(40H),那么实际上写入的命令数据为C0H:0100_0000(40H)+1000_0000(80H)=1100_0000(C0H)
基本操作时序
说明下,RS为寄存器选择,高电平时选择寄存器,低电平时选择指令寄存器。RW为读写信号线,高电平时进行读操作,低电平时进行写操作。EN为使能端,当EN端由高电平跳变成低电平时,液晶模块执行命令。L表示低电平,H表示高电平。
- 读状态
- 输入:
RS=L; RW=H; E=H
- 输出:
D0~7=状态字
- 输入:
- 写指令
- 输入:
RS=L; RW=L; E=下降沿脉冲; D0~7=指令码
- 输出:
null
- 输入:
- 读数据
- 输入:
RS=H; RW=H; E=H
- 输出:
D0~7=数据
- 输入:
- 写数据
- 输入:
RS=H; RW=L; E=下降沿脉冲; D0~7=数据
- 输出:
null
- 输入:
时序图
时序参数
字符代码与字符图形对应关系
使用样例
比如要输出A,查询表可知对应代码为
0100_0001
,而后显示时模块把地址41H
中的点阵字符图形显示出来,我们就可以看到A头文件
#include<reg51.h> #include<intrins.h> //使用_nop_(); #include<string.h>
宏定义
// RS为寄存器选择,高电平时选择寄存器,低电平时选择指令寄存器 sbit RS = P2^0; // RW为读写信号线,高电平时进行读操作,低电平时进行写操作 sbit RW = P2^1; // EN为使能端,当EN端由高电平跳变成低电平时,液晶模块执行命令 sbit EN = P2^2;
初始化函数
/** * LCD初始化 * * @return */ void init() { /* 0011_1000 置功能 DL=1 --> 8位总线 N=0 --> 单行显示 F=0 --> 显示5x7的点阵字符 */ write_cmd(0x38); /* 0000_0001 清显示 指令码01H,光标复位到地址00H位置 */ write_cmd(0x01); /* 0000_0110 置输入模式 I/D=1 --> 光标右移 S=0 --> 屏幕上所有文字左移或右移 */ write_cmd(0x06); /* 0000_1100 显示开/关控制 D=1 --> 开显示 C=0 --> 无光标 B=0 --> 光标不闪烁 */ write_cmd(0x0C); }
检测BF(busy flag)位状态
/* * 检测BF(busy flag)位状态 * * @return */ void test_BF() { unsigned char LCD_status; do{ P0 = 0xFF; // LCD1602读取状态数据,必须有一个上拉电平 EN = 0; RS = 0; RW = 1; // RS为0时,P0的数据为命令 EN=1;// 让RS和RW设置有效 LCD_status = P0; _nop_(); _nop_(); EN = 0; }while(LCD_status&0x80); // 1000_0000 忙碌状态 }
写数据
/* * 写数据(一位一位的写) * * @param data8 八位数据 * @return */ void write_data(unsigned char data8) { test_BF(); EN = 0; RS = 1; RW = 0; P0 = data8; EN = 1; _nop_(); EN = 0; }
写命令
/* * 写命令 * * @param cmd8 八位命令 * @return */ void write_cmd(unsigned char cmd8) { test_BF(); EN = 0; RS = 0; RW = 0; P0 = cmd8; EN = 1; _nop_(); EN = 0; }
写字符串
/** * 写字符串 * * @param r row * @param c column * @param str 字符串 * @return */ void write_str(int r, int c, char *str) { int i=0; unsigned char Addressx[] = {0x80, 0xC0}; unsigned char StartAdd = (Addressx[r] | c);//按位或 write_cmd(StartAdd); for(i = 0; i < 16; i++){ if(str[i]==0) break; write_data(str[i]); } // 如果不够16位,用空格填充 for(;i < 16; i++){ write_data(' '); } }
主函数编写
头文件
#include<reg51.h> #include<intrins.h> #include<string.h> #include<stdlib.h> #include<stdio.h>
宏定义
sbit switch1 = P3^0; sbit switch2 = P3^1; sbit switch3 = P3^2; sbit switch4 = P3^3; unsigned char *strCode=" I Love You!";
引入外部函数
extern void delay_ms(int ms); extern void init(); extern void write_cmd(unsigned char cmd8); extern void write_str(int r, int c, char *str); extern void write_data(unsigned char data8);
功能1:水平滚动文字
void h_scroll_words() { int i; init(); write_str(0,0, " Example-1 "); while(1) { /* fun1 */ for(i = 0; i<strlen(strCode); i++) { write_str(1, 0, strCode + i); delay_ms(100); } if(switch1 != 0) break; } }
功能2:随机数相加
void random_words() { int a,b,i; unsigned char tempStr[17]; init(); write_cmd(0x0F); //0000_1111:显示开/关控制 write_str(0,0, " Example-2 "); while(1) { //srand(TH0); a = rand()%10; b = rand()%10; sprintf(tempStr, "%d+%d=%d", a, b, a+b); write_cmd(0xC0|0x05); //1100_0101 for(i = 0; i < 11; i++) { if(tempStr[i]) write_data(tempStr[i]); else write_data(' '); delay_ms(150); } write_str(1, 0, " "); delay_ms(150); if(switch2 != 0) break; } }
功能3:全码显示
void all_str_code() { int i,j; init(); write_cmd(0x0F);//0000_1111:显示开/关控制 write_str(0,0, " Example-3 "); while(1) { write_cmd(0xC0); for(i = 0x20; i <= 0xFF; i++) { if(switch3) return; if(i >= 0x80 && i < 0xa0) continue; if((++j) == 16) { write_str(1, 0, " "); j = 0; //如果命令让它从第二行写,就重置到第二行第一个地址 write_cmd(0xC0); } //if(i == 0xFF) i = 0x20; write_data(i); delay_ms(50); } } }
功能4:自定义字符显示
void character_str_code() { int i = 0; unsigned char CC[] = {0x1F,0x11,0x1F,0x11,0x1F,0x11,0x1F,0x00}; init(); write_cmd(0x0F); // 0000_1111:显示开关控制 write_str(0, 0, " Example-4 "); write_cmd(0x40); //0100_0000:置字符发生存贮器地址 for(i = 0; i < 8; i++) { // 通过上面write_LCD_CMD(0x40); 把数组写到CGRAM write_data(CC[i]); } while(1) { write_cmd(0xC0); for(i = 0; i < 16; i++) { if(switch4) return; write_data(0); delay_ms(50); } //当满行显示后清屏 write_str(1, 0, " "); delay_ms(150); } }
主函数
void main() { while(1) { if(switch1 == 0) { h_scroll_words(); } else if(switch2 == 0) { random_words(); } else if(switch3 == 0) { all_str_code(); } else if(switch4 == 0) { character_str_code(); } } }
-
【玩转嵌入式屏幕显示】(四)TFT-LCD屏幕显示英文字符(ASCII)和字符串
2019-11-23 22:08:501. 简单的显示测试程序 — 帮助理解 使用PCtoLCD对字符取模 无论什么屏幕,都是由一个个像素点组成的,所以...取模软件使用PCtoLCD2002完美版,附上下载链接。 取模软件中的设置如下: 生成数据:C51格式: 点阵格...1. 简单的显示测试程序 — 帮助理解
使用PCtoLCD对字符取模
无论什么屏幕,都是由一个个像素点组成的,所以显示英文字符’A’的原理如图:
显示一个字符需要确定字符的高度和宽度:
- 宽度的像素点是高度的一半;
- 高度是16/24/32个像素点,称为字号(上图中是16个像素点)
取模软件使用PCtoLCD2002完美版,附上下载链接。
取模软件中的设置如下:
- 生成数据:C51格式:
- 点阵格式:阴码(阴码是1显示,0不显示);
- 取模方式:逐行式
- 取模走向:顺向
- 其余设置:默认
这里我使用的屏幕分辨率240240,所以我们选择显示一个240120的字符’A’,在取模软件中设置大小:
生成的数据较多,点击保存到文件:
修改文件名为
font_A.h
,然后修改文件格式如下,便于后续使用:const char CH_A[] = { //生成的字符数据 };
编写程序显示字符
这个数组具有225行,每行16个字节的数据,每个字节对应该处的8个像素点是否显示,然后程序根据此数组判断是否要向像素点写入颜色。
简单的测试程序如下:
void LCD_ShowChar(uint16_t x, uint16_t y, char ch, uint16_t back_color, uint16_t font_color, uint8_t font_size) { int i = 0, j = 0; uint8_t temp = 0; LCD_Address_Set(x, y, x + font_size/2 - 1, y + font_size - 1);//(x,y,x+8-1,y+16-1) for(i = 0;i < 225*16; i++) { temp = CH_A[i]; for(j = 0; j < 8;j++) { //判断temp的最高位是否为1 if(temp & 0x80) { //最高位为1,显示该点,设置颜色为字体颜色 LCD_Write_2Byte(font_color); } else { //最高位为0,不显示该点,设置该点为背景色 LCD_Write_2Byte(back_color); } temp <<= 1; } } }
在mian.c中调用,如下:
int main(void) { HAL_Init(); SystemClock_Config(); LCD_Init(); LCD_ShowChar(60 ,0,'A',BLACK,YELLOW,240); while (1); }
显示结果
2. 使用英文字库文件"font.h"
font.h内容
当程序中只需要显示几个字符时,可以使用取模的方式,也非常节省内存,但是当我们程序中需要使用不确定的字符时或者大量字符时,逐个取模的方式显然不可行,需要使用一个已经将常用字符按常用大小曲目完成的字库文件,即
font.h
,文件详细内容见我的Github。基于font.h的任意字符显示函数
首先将字符文件包含进来:
#include "font.h"
然后在之前编写的函数上进行改进:
/** * @brief 显示一个ASCII码字符 * @param x,y 显示起始坐标 * @param ch 需要显示的字符 * @param size 字体大小(支持16/24/32号字体) * @return none * @note 需要font.h字库文件的支持 */ void LCD_ShowChar(uint16_t x, uint16_t y, char ch, uint16_t back_color, uint16_t font_color, uint8_t font_size) { int i = 0, j = 0; uint8_t temp = 0; uint8_t size = 0; uint8_t t = 0; /* 检测显示是否会越界 */ if((x > (LCD_Width - font_size / 2)) || (y > (LCD_Height - font_size))) return; /* 根据字符大小设置显存操作区域 */ LCD_Address_Set(x, y, x + font_size/2 - 1, y + font_size - 1); /* 计算字符在字库中的偏移值*/ ch = ch - ' '; /* 显示16号/32号字体 */ if((font_size == 16) || (font_size == 32) ) { /* 计算字体一个字符对应点阵集所占的字节数 */ size = (font_size / 8 + ((font_size % 8) ? 1 : 0)) * (font_size / 2); for(i = 0; i < size; i++) { if(font_size == 16) temp = asc2_1608[ch][i]; //调用1608字体 else if(font_size == 32) temp = asc2_3216[ch][i]; //调用3216字体 else return; //没有的字库 for(j = 0; j < 8; j++) { if(temp & 0x80) LCD_Write_2Byte(font_color); else LCD_Write_2Byte(back_color); temp <<= 1; } } } /* 显示12号字体 */ else if(font_size == 12) { /* 计算字体一个字符对应点阵集所占的字节数 */ size = (font_size / 8 + ((font_size % 8) ? 1 : 0)) * (font_size / 2); for(i = 0; i < size; i++) { temp = asc2_1206[ch][i]; for(j = 0; j < 6; j++) { if(temp & 0x80) LCD_Write_2Byte(font_color); else LCD_Write_2Byte(back_color); temp <<= 1; } } } /* 显示24号字体 */ else if(font_size == 24) { /* 计算字体一个字符对应点阵集所占的字节数 */ size = (font_size * 16) / 8; for(i = 0; i < size; i++) { temp = asc2_2412[ch][i]; if(i % 2 == 0) t = 8; else t = 4; for(j = 0; j < t; j++) { if(temp & 0x80) LCD_Write_2Byte(font_color); else LCD_Write_2Byte(back_color); temp <<= 1; } } } /* 其余字体 */ else return; }
测试4种字体的显示
int main(void) { HAL_Init(); SystemClock_Config(); LCD_Init(); LCD_ShowChar(0,0,'A',BLACK,BLUE,12); LCD_ShowChar(6,12,'B',BLACK,YELLOW,16); LCD_ShowChar(14,28,'C',BLACK,GREEN,24); LCD_ShowChar(26,52,'D',BLACK,PINK,32); while (1); }
测试结果
3. 字符串显示函数
/** * @brief 显示一个ASCII码字符串 * @param x,y 显示起始坐标 * @param str 需要显示的字符串 * @param size 字体大小(支持16/24/32号字体) * @return none * @note 1. 需要font.h字库文件的支持 * 2. 超过指定width不显示超过的字符 */ void LCD_ShowCharStr(uint16_t x, uint16_t y, uint8_t max_width, char* str, uint16_t back_color, uint16_t font_color, uint8_t font_size) { max_width += x; while((*str <= '~') && (*str >= ' ')) //判断是否非法字符 { if(x >= max_width) { //x方向越界,结束 break; } LCD_ShowChar(x,y,*str,back_color, font_color,font_size); x += font_size / 2; str++; } }
测试代码:
int main(void) { HAL_Init(); SystemClock_Config(); LCD_Init(); LCD_ShowChar(0,0,'A',BLACK,BLUE,12); LCD_ShowChar(6,12,'B',BLACK,YELLOW,16); LCD_ShowChar(14,28,'C',BLACK,GREEN,24); LCD_ShowChar(26,52,'D',BLACK,PINK,32); LCD_ShowCharStr(0,240-32,240,"Mculover666",BLACK,BLUE,32); while (1); }
测试结果:
-
【玩转嵌入式屏幕显示】(七)LCD中文字符显示机制
2021-07-24 08:29:57一、字符显示机制 1. 字符显示原理 LCD通过一个个像素点,要在LCD上显示一个字符,需要以下两步: ① 占据屏幕上的一块地方,大小由字体大小说了算; ② 在占据的地方上依次控制每个像素点是否显示。 比如中文字符...本文源码和工具开源地址:https://github.com/Mculover666/HAL_Driver_Lib。
一、字符显示机制
1. 字符显示原理
LCD通过一个个像素点,要在LCD上显示一个字符,需要以下两步:
- ① 占据屏幕上的一块地方,大小由字体大小说了算;
- ② 在占据的地方上依次控制每个像素点是否显示。
比如中文字符24×24字体大小表示水平需要24个像素点、垂直需要24个像素点。
在这块24×24的地盘上,每个像素点是否显示由字模说了算,字模中的每1位数据表示一个像素点,如果该位为0则表示此处像素点不显示、为1则表示显示(阴码规则)。
所以,字符显示的函数只需要基于打点函数实现即可。在程序中逐位读取字模,如果该位为0则该点写入背景颜色,如果该位为1则写入前景颜色。
2. 字模生成(点阵字体)
正因为LCD显示字符的机制,所以该种字体被称为点阵字体。
为了方便大家理解原理,这里我首先使用小工具生成字模。
设置工具的字模生成规则如下,阴码、逐行式、顺向取模、C51格式:
接着生成汉字的字模:
接着复制生成数据,在程序中定义为一个二维数组作为字库,第一个值表示字库中的元素个数,可以由编译器自行判断,第二个值是每个元素的大小,必须要指明,这样我们就可以用
hz_16x16[0]
来找到汉字 ”春”在字库中的位置:#ifndef _HZ_H_ #define _HZ_H_ const unsigned char hz_16x16[][32] = { {0x01,0x00,0x01,0x00,0x7F,0xFC,0x01,0x00,0x3F,0xF8,0x02,0x00,0xFF,0xFE,0x08,0x20, 0x10,0x10,0x2F,0xE8,0xC8,0x26,0x08,0x20,0x0F,0xE0,0x08,0x20,0x08,0x20,0x0F,0xE0},/*"春",0*/ /* (16 X 16 , 宋体 )*/ }; #endif /* _HZ_H_*/
我们选择的字体是16x16,所以:
- 水平方向有16个像素点,每个像素点占1位,需要16bit,两个字节来表示一行;
- 垂直方向有16行,所以整体有2*16=32个字节;
此处需要注意,软件每16个字节生成一对花括号,这会影响二维数组取值,需要将中间多余的花括号去除。
二、如何将字符显示到LCD
1. 打点函数支持
字符显示需要打点函数的支持,这里我使用RGB-LCD的打点函数:
void lcd_draw_point(uint16_t x, uint16_t y, uint16_t color);
2. 字库支持
引入刚刚我们创建二维数组的头文件:
#include "hz.h"
2. 读取字模显示
void lcd_show_chinese(uint16_t x, uint16_t y, char ch, uint16_t back_color, uint16_t font_color, uint8_t font_size) { uint16_t i, j; uint16_t x_pos, y_pos, size, font_width, font_height; uint8_t *font_ptr; uint8_t bit_width, temp; if((x > (LCD_WIDTH - font_size)) || (y > (LCD_HEIGHT - font_size))) { return; } x_pos = x; y_pos = y; font_height = font_size; font_width = font_size; bit_width = 8; size = (font_width / 8 + ((font_width % 8) ? 1 : 0)) * font_height; font_ptr = (uint8_t*)&hz_16x16[ch]; for (i = 0; i < size; i++) { temp = *(font_ptr + i); for (j = 0; j < bit_width; j++) { if(temp & 0x80){ lcd_draw_point(x_pos, y_pos, font_color); } else { lcd_draw_point(x_pos, y_pos, back_color); } temp <<= 1; x_pos++; } if (x_pos >= (x + font_width)) { y_pos++; x_pos = x; } } }
实现之后记得声明:
/** * @brief Show a chinese char. * @param[in] x1 horizontal start position. * @param[in] y1 vertical start position. * @param[in] x2 horizontal end position. * @param[in] y2 vertical end position. * @param[in] ch offset in hz library. * @param[in] back_color rgb565 * @param[in] font_color rgb565 * @param[in] font_size support 16. * @return None * @note This function need hz library. */ void lcd_show_chinese(uint16_t x, uint16_t y, char ch, uint16_t back_color, uint16_t font_color, uint8_t font_size);
3. 测试显示
在main函数中调用:
lcd_show_chinese(0, 0, 0, BLACK, GREEN, 16);
编译、下载即可看到效果:
三、小字库的使用
1. 制作小字库
在项目中,我们需要显示一些中文,但也没必要将整个汉字库包含进来,所以经常是制作本项目专属小字库。
这里取模工具使用安富莱电子的MakeDot,非常方便:
这里选择了输入文字重排,可以去除重复汉字,减少字库体积。将生成的整个数组复制作为之前我们创建数组
hz_16x16
的内容:#ifndef _HZ_H_ #define _HZ_H_ const unsigned char hz_16x16[][32] = { {0x00,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x00,// ! // 0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00,0x10,0x00,0x10,0x00,0x00,0x00,0x00,0x00}, {0x00,0x00,0x20,0x00,0x17,0xFE,0x10,0x08,0x80,0x08,0x43,0xC8,0x42,0x48,0x12,0x48,// 河 // 0x12,0x48,0x22,0x48,0xE3,0xC8,0x22,0x48,0x20,0x08,0x20,0x08,0x20,0x28,0x00,0x10}, {0x10,0x00,0x10,0x00,0x10,0x00,0x10,0x7C,0xFE,0x44,0x12,0x44,0x12,0x44,0x12,0x44,// 加 // 0x12,0x44,0x12,0x44,0x12,0x44,0x12,0x44,0x22,0x44,0x22,0x7C,0x4A,0x44,0x84,0x00}, {0x01,0x00,0x01,0x00,0xFF,0xFE,0x01,0x00,0x01,0x00,0x7F,0xFC,0x48,0x24,0x44,0x44,// 南 // 0x4F,0xE4,0x41,0x04,0x41,0x04,0x5F,0xF4,0x41,0x04,0x41,0x04,0x41,0x14,0x40,0x08}, {0x00,0x40,0x20,0x40,0x10,0x40,0x10,0x40,0x87,0xFC,0x44,0x44,0x44,0x44,0x14,0x44,// 油 // 0x14,0x44,0x27,0xFC,0xE4,0x44,0x24,0x44,0x24,0x44,0x24,0x44,0x27,0xFC,0x04,0x04}, }; #endif /* _HZ_H_*/
这样就完成了我们整个项目小字库的制作,同样的方法,我们再制作出hz_24x24字库,hz_32x32字库。
const unsigned char hz_24x24[][72] = { //... }; const unsigned char hz_32x32[][128] = { };
2. 使用小字库
进一步完善中文显示函数,找到获取字模数据的代码:
font_ptr = (uint8_t*)&hz_16x16[ch]
优化为:
switch (font_size) { case 16: font_ptr = (uint8_t*)&hz_16x16[ch]; break; case 24: font_ptr = (uint8_t*)&hz_24x24[ch]; break; case 32: font_ptr = (uint8_t*)&hz_32x32[ch]; break; default: return; }
在main函数中进一步添加测试程序:
lcd_show_chinese(0, 0, 1, BLACK, RED, 16); // 河 lcd_show_chinese(16, 0, 3, BLACK, RED, 16); // 南 lcd_show_chinese(32, 0, 2, BLACK, RED, 16); // 加 lcd_show_chinese(48, 0, 4, BLACK, RED, 16); // 油 lcd_show_chinese(64, 0, 0, BLACK, RED, 16); // ! lcd_show_chinese(0, 20, 1, BLACK, RED, 24); lcd_show_chinese(24, 20, 3, BLACK, RED, 24); lcd_show_chinese(48, 20, 2, BLACK, RED, 24); lcd_show_chinese(72, 20, 4, BLACK, RED, 24); lcd_show_chinese(96, 20, 0, BLACK, RED, 24); lcd_show_chinese(0, 60, 1, BLACK, RED, 32); lcd_show_chinese(32, 60, 3, BLACK, RED, 32); lcd_show_chinese(64, 60, 2, BLACK, RED, 32); lcd_show_chinese(96, 60, 4, BLACK, RED, 32); lcd_show_chinese(128, 60, 0, BLACK, RED, 32);
显示效果如下:
四、进一步的优化
本文中讲述的仅仅是最基本的中文显示方法,还可以进一步进行优化。
① 字符偏移优化
这里使用小字库不太方便的点是,字符在字库中的偏移位置需要自己控制,如果想自动控制就涉及编码问题,实现后可以直接写汉字字符串来显示。
② 字库优化
项目中比较稳妥的办法是使用全字库,片内Flash肯定不够用,通常的做法是外挂一片SPI Flash,将整个全字库文件烧写到Flash里,使用的时候读出来即可。
③ 字体优化
本文中我们取模时都使用的是宋体,好不容易建立的字库,可能某天老板突然过来说要换成什么奇奇怪怪的字体,那不是完蛋了~
所以在实现的时候我们要考虑在SPI Flash上建立文件系统,直接使用文件,方便字库文件替换。
后续这些优化点我也会写文章分享,这个周末要出去逛吃逛吃啦~
-
分析wireshark中无法正确显示字符的原因
2017-04-22 11:34:47分析wireshark中无法正确显示字符的原因 -
【笔记】I2C接口OLED显示屏——显示字符以及字符串
2020-03-04 17:13:39ASCII字符的字体大小是可以通过取模软件自定的,但常用的字体大小是8×16和6×12这两种,因为字体太小会看不清,字体太大的话就太占空间,下面以8×16的字体来举例。 一个8×16大小的字体需要占用8×16个bit的空间... -
win10中特殊字符显示为方框的解决办法
2020-08-21 16:29:20开始 设置 进入windows设置 在搜索框中输入添加可选功能 点击添加功能 把 其他几种字体安装 -
单片机学习(三)8位数码管显示8个字符的程序及详解
2021-08-11 10:49:338位数码管逐位显示8个字符的程序及详解 1.(现象) 8位数码管从最低位开始到最高位,逐位显示字符0.1.2.3.4.5.6.7,并且不断循环显示 2.(程序说明) 程序在运行时,单片机从WMtable表格中选择第一个位码(i=0时... -
LCD12864(ST7565P)字符汉字显示(STM32F103)
2021-02-03 23:19:42一、 LCD12864(ST7565P)简介 LCD12864是一种具有4位/8位并行、...可以显示8×4行16×16点阵的汉字,也可完成图形显示。 二、实验材料 1、stm32最小系统。 2、LCD12864液晶屏。 3、杜邦线若干。 三、程序代码 1、 ... -
CRT连接工具中中文字符显示乱码的解决办法
2020-07-24 13:34:18首先,要查看数据库中的字符集是否支持中文,如果不支持,是无法存储中文数据的,哪怕在linux中能显示出来,也无法存入到数据库中。 查询数据库中的字符集类型: SELECT * FROM NLS_DATABASE_PARAMETERS where ... -
文件下载时,文件名为中文和含有特殊字符的综合解决方案
2019-12-23 17:03:14文件下载时,文件名为中文和含有特殊字符的综合解决方案 先来分析这个问题: 文件名中含有特殊字符 文件名含有中文 文件名中含有特殊字符 分析: 含有英文逗号,导致下载链接失效 含有特殊符号(< &... -
【王爽汇编】实验10 编写子程序之“显示字符串”
2022-03-22 20:26:05前言:因为最近在准备中国软件杯的比赛,所以暂时暂停了对8086汇编的学习,拿出更多的时间去肝前后端、计算机视觉、数据处理等。花在汇编上的时间变少了,所以我之前以理论知识为主,打算只会再把这本书留下来的启发... -
FPGA实现VGA显示(三)——————单个字符显示
2019-02-13 12:37:23字符显示只修改vga_display模块,其他模块参考FPGA实现VGA显示(二)——————color_bar显示及方框移动(参考开拓者FPGA开发指南) 字符显示相对较简单,主要是控制每一个像素点的黑白,... -
使用扫描软件扫描含有中文字符的二维码显示乱码?
2018-06-05 11:00:50在使用中琅领跑条码标签打印软件制作并打印二维码时,有些朋友也会遇到这种问题:使用扫描软件扫描含有中文字符的二维码时,扫描界面显示为一串问号(即乱码)。是什么原因造成扫描中文乱码的呢?又该如何解决呢?今天... -
ASCII控制字符和ASCII可显示字符
2018-07-03 17:29:22ASCII控制字符和ASCII可显示字符 ASCII控制字符 二进制 十进制 十六进制 缩写 可以显示的表示法 名称/意义 00000000 0 00 NUL ␀ 空字符(Null) 000000... -
NJUPT 微机 中断系统 日时钟中断之替换1CH实现字符串动态显示
2015-11-30 12:58:27如果要显示彩色字符串,用bios调用即可 13h显示字符串 ;lea dx,mesg mov ax,1301h mov bh,0 mov bl,01001111B mov cx,LL mov dh,10 sub dh,count; 行数 mov dl,0h lea bp,mesg int 10h ;int 21h exit: ... -
好玩!C语言打印彩色字符,还能闪烁!
2020-04-10 15:31:491. ANSI escape code 最近在研究日志打印组件easylogger,玩转...escape sequence code 全称叫做 escape sequence code,即 Escape 序列屏幕控制码,其实就是一些特殊的字符,将这些字符加入到printf打印的内容中,... -
LCD1602模块如何显示自定义字符
2018-01-28 22:44:23假如现在我想显示某个温度值,需要标志出温度符号”°C”,现在你去字库表里面查找,发现根本找不到这个符号,那怎么办?下面我们就来就来通过自定义字符解决这个问题。前面讲了,对于显示模块的控制,主要关注两个... -
汇编语言输入字符,统计英文字母,数字,空格和其他字符,并输出显示。
2018-11-28 22:51:52主要完成功能:输入随机个字符个数(最大98个,可调),统计字母,数字,空格,其他字符个数,统计好以后显示出来相应个数。 存在部分问题未找到解决办法,希望高人能请联系我,问题如下: 1.如果不输入任何字符,... -
51单片机教程:8*8 点阵显示字符、数字、简单汉字
2020-05-24 12:38:50点阵显示实验 一、什么是点阵? 我们用之前的方法一个IO口只能控制一个led,如果需要用更少的IO口控制更多的led怎么办呢,于是就有了点阵。 8X8点阵共由64个发光二极管组成,且每个发光二极管是放置在行线和列线的... -
secureCRT显示乱码/字符集设置
2018-03-21 17:49:37绝大部分企业级服务器以Unix或linux系统担当,所以在远程连接Unix系统时,楼主使用了VANDYKE公司的SecureCRT软件,下面就来介绍在连接中出现乱码怎么处理及设置。 1.首先,配置登录信息后,来连接进入远程服务器... -
ascii控制字符(不可见字符)和可打印字符(可见字符)------浪费15分钟的一次经历
2019-02-15 20:38:06ascii控制字符(不可见字符)和可打印字符(可见字符)------浪费15分钟的一次经历 -
FPGA实现VGA显示(六)——————多字符显示及基于fpga的“打字机”实现
2019-02-17 23:09:15前面笔者总结了如何显示单字符,设立通过一个简单的任务来总结如何实现vga多字符显示。 实验要求 基础: 由PC通过UART发送数据在VGA显示。数据可以为字母,数字,汉字(任选10个字),VGA分为左右两个区域,输入... -
FPGA驱动OLED动态显示(Verilog代码)——向OLED写数据(关键)——Part5
2017-10-23 10:38:13在每个字符显示完之后都要结束当前ROM占用,释放给下一个字符;字符的显示代码跟字符‘F’的代码除了高低地址不同,其他不变。 2.7、 当显示动态数字时有所变化。以显示个位为列,其他位置的数字显示跟个位显示相同... -
文件名的长度可达()个字符
2021-05-13 17:25:06[单选] 文件名的长度可达()个字符。A . 1B . 无数C . 255D . 10文件名的长度可长达255个字符。为了方便人们区分计算机中的不同文件,而给每个文件设定一个指定的名称。由文件主名和扩展名组成。为文件指定的名称。... -
浅谈java使用指定字符集编码,以及常见的字符集
2017-11-13 12:54:34问题的引入:在InputStreamReader(OutputStreamWriter)的构造方法中,有指定字符集编码,那么什么是字符集?有哪些常用的字符集?怎么用字符集进行编码? 一 什么是字符集? 字符:字符(Char)是各种文字... -
c#中出现输入字符串格式不正确
2017-08-17 09:09:25Message=输入字符串的格式不正确。 Source=mscorlib StackTrace: 在 System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args) 在 System.String.... -
SPSS读取数据出现中文字符显示乱码的解决方案
2022-01-27 21:42:12如何解决SPSS数据文件中中文字符乱码 -
ASCII码不可见字符过滤处理
2018-04-19 10:46:27Function/Control Code/Character in ASCIIVersion: 2011-02-15Author: green-waste (at) 163.com【什么是 Function Code 功能码或 Function Character...128 个字符。其中前 32 个, 0-31 ,即 0x00-0x1F... -
首行缩进2字符如何设置
2021-07-23 01:16:08首行缩进2字符如何设置2020-12-17 13:14:36 来源:网络整理扫码可以:1.在手机上浏览2.分享给微信好友或朋友圈摘要:以Word 2019为例,首行缩进2字符的设置方法:1、打开需要设置的文档。2、选中要设置首行缩进的...