精华内容
下载资源
问答
  • 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 57的点阵字符,1: 5 ∗ 10 5*10 510的点阵字符
    • 指令7:字符发生器RAM地址设置
    • 指令8:DDRAM地址设置
    • 指令9:读忙信号和光标地址
      • BF:1:忙,此时模块不能接收命令或数据,0:不忙
    • 指令10:写数据
    • 指令11:读数据

    其他说明

    1. 液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平(不忙),否则该指令失效
    2. 当显示字符时要先输入显示字符地址,以下是内部显示地址
      在这里插入图片描述
      所以若要写入字符到第二行第一个(40H),那么实际上写入的命令数据为C0H0100_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();
    		}
    	}
    }
    
    展开全文
  • 1. 简单的显示测试程序 — 帮助理解 使用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);
    }
    

    测试结果:

    展开全文
  • 一、字符显示机制 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中无法正确显示字符的原因
  • 【笔记】I2C接口OLED显示屏——显示字符以及字符

    千次阅读 多人点赞 2020-03-04 17:13:39
    ASCII字符的字体大小是可以通过取模软件自定的,但常用的字体大小是8×16和6×12这两种,因为字体太小会看清,字体太大的话就太占空间,下面以8×16的字体来举例。 一个8×16大小的字体需要占用8×16个bit的空间...
  • 开始 设置 进入windows设置 在搜索框中输入添加可选功能 点击添加功能 把 其他几种字体安装
  • 8位数码管逐位显示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、 ...
  • 首先,要查看数据库中的字符集是否支持中文,如果支持,是无法存储中文数据的,哪怕在linux中能显示出来,也无法存入到数据库中。 查询数据库中的字符集类型: SELECT * FROM NLS_DATABASE_PARAMETERS where ...
  • 文件下载时,文件名为中文和含有特殊字符的综合解决方案 先来分析这个问题: 文件名中含有特殊字符 文件名含有中文 文件名中含有特殊字符 分析: 含有英文逗号,导致下载链接失效 含有特殊符号(< &...
  • 前言:因为最近在准备中国软件杯的比赛,所以暂时暂停了对8086汇编的学习,拿出更多的时间去肝前后端、计算机视觉、数据处理等。花在汇编上的时间变少了,所以我之前以理论知识为主,打算只会再把这本书留下来的启发...
  • 字符显示只修改vga_display模块,其他模块参考FPGA实现VGA显示(二)——————color_bar显示及方框移动(参考开拓者FPGA开发指南) 字符显示相对较简单,主要是控制每一个像素点的黑白,...
  • 在使用中琅领跑条码标签打印软件制作并打印二维码时,有些朋友也会遇到这种问题:使用扫描软件扫描含有中文字符的二维码时,扫描界面显示为一串问号(即乱码)。是什么原因造成扫描中文乱码的呢?又该如何解决呢?今天...
  • ASCII控制字符和ASCII可显示字符

    千次阅读 2018-07-03 17:29:22
    ASCII控制字符和ASCII可显示字符 ASCII控制字符 二进制 十进制 十六进制 缩写 可以显示的表示法 名称/意义 00000000 0 00 NUL ␀ 空字符(Null) 000000...
  • 如果要显示彩色字符串,用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:49
    1. ANSI escape code 最近在研究日志打印组件easylogger,玩转...escape sequence code 全称叫做 escape sequence code,即 Escape 序列屏幕控制码,其实就是一些特殊的字符,将这些字符加入到printf打印的内容中,...
  • LCD1602模块如何显示自定义字符

    万次阅读 多人点赞 2018-01-28 22:44:23
    假如现在我想显示某个温度值,需要标志出温度符号”°C”,现在你去字库表里面查找,发现根本找到这个符号,那怎么办?下面我们就来就来通过自定义字符解决这个问题。前面讲了,对于显示模块的控制,主要关注两个...
  • 主要完成功能:输入随机个字符个数(最大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分钟的一次经历
  • 前面笔者总结了如何显示单字符,设立通过一个简单的任务来总结如何实现vga多字符显示。 实验要求 基础: 由PC通过UART发送数据在VGA显示。数据可以为字母,数字,汉字(任选10个字),VGA分为左右两个区域,输入...
  • 在每个字符显示完之后都要结束当前ROM占用,释放给下一个字符;字符的显示代码跟字符‘F’的代码除了高低地址不同,其他不变。 2.7、 当显示动态数字时有所变化。以显示个位为列,其他位置的数字显示跟个位显示相同...
  • 文件名的长度可达()个字符

    千次阅读 2021-05-13 17:25:06
    [单选] 文件名的长度可达()个字符。A . 1B . 无数C . 255D . 10文件名的长度可长达255个字符。为了方便人们区分计算机中的不同文件,而给每个文件设定一个指定的名称。由文件主名和扩展名组成。为文件指定的名称。...
  • 问题的引入:在InputStreamReader(OutputStreamWriter)的构造方法中,有指定字符集编码,那么什么是字符集?有哪些常用的字符集?怎么用字符集进行编码?   一 什么是字符集?  字符字符(Char)是各种文字...
  • Message=输入字符串的格式正确。 Source=mscorlib StackTrace: 在 System.Text.StringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ParamsArray args) 在 System.String....
  • 如何解决SPSS数据文件中中文字符乱码
  • ASCII码可见字符过滤处理

    千次阅读 2018-04-19 10:46:27
    Function/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、选中要设置首行缩进的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 454,132
精华内容 181,652
关键字:

下载软件动态字符不显示