Protues仿真12864的学习笔记

硬件驱动

Protues内置12864液晶型号是AMPIRE KS0108,其中KS0108为驱动器芯片的型号。驱动器作为桥梁,为引脚输入到显示在液晶上输出提供了连接。引用网友“jiangnanzhl”在百度知道的回答:CGROM和CGRAM中存储的字模信息相当于厨房中的食品,CGROM是厨房中现成的熟食,CGRAM是用户自行制作的菜肴,这些食品都要通过托盘转移一下,才能送到餐桌上食用;类似的字模编码都要先被读取到对应的DDRAM中,经如上中转以后,屏幕的相应位置才显示出字符。

以ST7920驱动为例,这是大多数有字库版本的12864所使用的驱动器,其内部结构如下图:
ST7920驱动内部结构
驱动内部的主要结构是这些存储器。
DDRAM(Data Display RAM): 数据显示存储器,输入到DDRAM的信息将会通过普通驱动和段驱动显示在LCD上。
CGROM(Character Generation ROM): 字符发生器,只读,包含有标准的ASCII码、日文字符、和希腊文字符,包括中文字符也存在CGROM中。字库一般指的就是CGROM。
CGRAM(Character Generation RAM): 为了使用户存储自己设计的字模编码,厂家所提供的自定义字符区,一般空间不大。
HCGROM(Half height Character Generation ROM): 半宽字符发生器。

Protues中KS0108驱动版本的12864是无字库的,就是只有DDRAM,没有其他的存储器。CS1和CS2是KS0108驱动类12864的标志性引脚。因此该型号显示屏含有两个驱动器,每一块驱动器控制64×64个点,两块驱动器就控制128×64个点,由片选引脚CS1和CS2控制显示哪一块。RST复位端接单片机接口,或者接高电平,但不能不接。

字模显示

显示屏上有128×64个点,划分为64小行,4大行,8页,128列,如图所示。在编写代码的时候,我是先通过片选确定写在左半部分还是右半部分,然后选择第一页到第七页(一般为了工整不选择小行),再选择1~64列,这样光标就确定了从某一点上开始写。
在这里插入图片描述
关于字模,先从汉字的数字化说起吧。汉字是象形文字,其结构较英文字母复杂的多。而且英文字母的种类很少,中文的种类更是浩繁,因此汉字数字化后所占的空间自然也是要比英文字符大。因此要想使汉字也储存在计算机中,就要中国人另想办法,另起炉灶。为了使每一个汉字有一个全国统一的代码,1980年,我国颁布了第一个汉字编码的国家标准: G(国)B(标)2312。这个字符集是我国中文信息处理技术的发展基础,是推动汉字数字化的重要举措。国标码是四位十六进制,然而为了便于交流,大家常用的是四位十进制的区位码,区位码是国标码0xXXYY减去0xA0A0,再转换为十进制。常见的汉字与符号组成一个94×94的矩阵。在此方阵中,每一行称为一个“区”,每一列称为一个“位”。01-09区为682个特殊字符,16~87区为汉字区,包含6763个汉字。
在这里插入图片描述
ASCII码的最大值是127,转换成二进制是1111111,不足八位,存储时在最高位补0就是01111111。char类型在计算机中占用一个字节,可以囊括ASCII码上所有字符。而汉字在计算机中存储需要两个字节,区码和位码需要分别占一个字节。如28区的46位上的汉字区位码是2846,区码、位码分别转换成16进制后是0x1C和0x2E。但这样的区码和位码在存储时就和ASCII码重复了,为了区别,将区码和位码在存储时分别加0xA0,这样必定大于01111111,就和ASCII码区分开了。区位码2846对应的国标码是0xBCCE,对应的汉字都是“嘉”。(其实以上内容与字模无直接联系,不过简单了解可以避免把概念搞混)

但是,国标码也只是一串由0、1组成的数字,它该如何在屏幕上显示呢?这就要用到字模了。字模虽然也是一组数字,但它的意义却与数字的意义有了根本的变化,它是用数字的各位信息来记载英文或汉字的形状。
在这里插入图片描述
在这里插入图片描述
如此,0的含义变成了“不填充”,1的含义变成了“填充”。这样,中文的显示需要32个字节的数据,英文、ASCII上的符号的显示需要16个字节的数据。字库就是厂家已经取好了一些常用汉字的字模,放在了只读的CGROM中。
在这里插入图片描述
字符按照什么样的顺序存储在ROM中,就涉及到驱动的工作方式。通过实验发现, 一般是以“第x页第y列从下到上、先写低位后写高位”的方式从CGROM读出数据并写在LCD上。
在这里插入图片描述
以上图“A”的字模为例,往LCD上写“A”的第一个字节的顺序为:1、1、1、0、0、0、0,那么储存在CGROM的第一个字节就需要是0000 0111,即0x07。第二个字节需要是0x0F,写在第x页第y+1列。写完第八个字节后就要在命令中“page+1”,从下一页开始写,一直到写完十六个字节。所谓字模的宽和高就是这样来的,“A”的宽是8,高是16。无字库版本只不过需要人为地按这样的规则将数据写入DDRAM,因而就要借助取模软件。取模软件能够把汉字、字符等等按照顺序以数组的形式呈现出来,供我们使用。

取模软件

由于12864没有字库,因此向它直接写入ASCII码是无法显示的。如图写入ASCII码,结果屏幕只是单纯显示出一个字节。
在这里插入图片描述
但这样的话自由度比较高,我们可以使用任意字体、任意字号来写,粗细、倾斜等也可以设置。字模软件Zimo21界面如图。
在这里插入图片描述
在这里插入图片描述
主要想说一下参数设置中的取模方式:
想实现从左到右的显示顺序的话,在取模的时候就要先取出字符位代码的第1竖列、第1到8横行的数据,接着取出第2竖列、第1~8横行的数据的数据,最后一直取到第y+7列的数据,然后按列依次呈现出来,这种按列取模方式叫做纵向取模。再点击以C51方式取模,就可以获得十六进制的一串数字,我们把它放到数组A[ ]中,就建立了自己的字库。
想实现从上到下显示顺序的话,在取模的时候就要按照从上到下的顺序了,这个叫横向取模。
在这里插入图片描述
字节倒序是根据不同驱动器的驱动方式来勾选,看其先写低字节或是先写高字节,如果不知道不妨勾选然后试两次。
此外,字模所占内存的大小与字体和字号都有关。宋体、小四对应的汉字点阵宽×高=16×16,英文点阵宽×高=8×16,所以汉字占了LCD的一大行和16列;英文也占了一大行,但比较窄,占了8列。其他字体和大小也都可以,考虑美观的话可以多实践几次,找到更合适的字体。在控制面板中搜索字体,可以在里面开启已安装但未显示的字体。

主要函数代码

在这里插入图片描述
以上是各个指令的控制代码。包括读、写、初始化的各个函数在网上已经有很多人编写了,我们能看懂即可。我觉得重要的是在理解原理的基础上,调用这些模块化的东西来实现自己想要的功能。先写这么多了,以上只是一些个人拙见,我也在不断地学习更深入的应用。如有错误,还望各位不吝指正!

void selectscreen(unsigned int i)			//选屏幕
{
	switch (i)
	{
		case 0: CS1 = 0; CS2 = 1; break;	//片选左屏
		case 1: CS1 = 1; CS2 = 0; break;	//片选右屏
		case 2: CS1 = 0; CS2 = 0; break;	//选两块屏
		default: break;						//退出
	}
}

void chekbusy12864(void)
{
	unsigned int dat;

	RS = 0;       				//指令模式 
	RW = 1;       				//读数据
	do{
		P2 = 0;
		EN = 1;					//E端口置1
		delay_us(1);
		dat = P2 & 0x80;		//dat取总线上最高位的值
		EN = 0;					//E端口置0
	}while (dat != 0);			//dat若为1意味着LCD“忙”,系统将停在这里,等到“不忙”的时候再运行下去
}

void writeinstr(unsigned char x)   //写入命令
{
	chekbusy12864();
	RS=0;						//写指令
	RW=0;						//低电平是Write
	EN=0;						//保险起见,将E先置0。其实没有必要
	P2=x;						//总线写入
//	delay_us(1);				//仿真时可以不用延时,实际电气连接后就需要调试了
	EN=1;
//	delay_us(1);				
    EN = 0;						//在R/W=0时,E=“1→0”会在下降沿锁存DB7∽DB0,从而数据被写到IR或DR
}

void writedata(unsigned char y)		//写入数据,一系列写函数的最小单元
{
	chekbusy12864();
	RS=1;						//写数据
	RW=0;						//低电平是Write,高电平是Read
	EN=0;
	P2=y;
//	delay_us(1);
	EN=1;
//	delay_us(1);
	EN=0;
}

void setpage(unsigned char page)
{
	page=0xb8|page;      		//1011 1XXX,XXX为0~7,对应第一页到第8页
	writeinstr(page);	 		//写入“页设置”指令
}

void setcolumn(unsigned char column)
{
	column=column&0x3f;   		//这里限制column取值最大为0x3f,即63。
	column=0x40|column;			//01XX XXXX,XXXXXX为0~63,对应1~64列
	writeinstr(column);			//写入“列设置”指令
}

void clear12864(unsigned char screen)  //12864清零
{
	unsigned char i,j;
	selectscreen(screen);		//选择清哪一个屏幕
	for(i=0;i<8;i++)
	{
		setpage(i);
		setcolumn(0);
		for(j=0;j<64;j++)
		{
			writedata(0x00);	//逐个点清空
		}
	}
}

void initlcd(void)
{
	chekbusy12864();
	clear12864(2);
	writeinstr(0xc0);	  		//从第0行开始显示
}

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
KS0108是一种图形LCD控制器,常用于128x64像素的屏幕上。下面是一个KS0108的汇编代码示例,用于在屏幕上绘制一个矩形。 ``` ; 初始化KS0108控制器 INIT_KS0108: ; 设置控制线为输出 mov P0,#0xFF ; 发送“启动”命令 mov P2,#0x3F clr P1.0 setb P1.1 clr P1.2 ; 发送“复位”命令 mov P2,#0xC0 setb P1.0 clr P1.1 setb P1.2 ; 发送“显示开启”命令 mov P2,#0x3F setb P1.0 setb P1.1 clr P1.2 ret ; 绘制矩形 DRAW_RECTANGLE: ; 设置起点 mov R0,#0 mov R1,#0 ; 绘制上边框 DRAW_TOP: ; 绘制一个点 call DRAW_PIXEL ; 移动到下一个点 inc R0 ; 判断是否绘制完毕 cjne R0,#127,DRAW_TOP ; 绘制右边框 DRAW_RIGHT: ; 绘制一个点 call DRAW_PIXEL ; 移动到下一个点 inc R1 ; 判断是否绘制完毕 cjne R1,#63,DRAW_RIGHT ; 绘制下边框 DRAW_BOTTOM: ; 绘制一个点 call DRAW_PIXEL ; 移动到下一个点 djnz R0,DRAW_BOTTOM ; 绘制左边框 DRAW_LEFT: ; 绘制一个点 call DRAW_PIXEL ; 移动到下一个点 djnz R1,DRAW_LEFT ret ; 绘制像素点 DRAW_PIXEL: ; 计算像素点所在的页和列 mov R2,R0 mov R3,R1 shr R2,#3 and R3,#0x3F ; 计算页的地址 mov A,R2 add A,#0xB8 mov R4,A ; 计算列的地址 mov A,R3 add A,#0x40 mov R5,A ; 发送“页地址”和“列地址”命令 mov P2,R4 setb P1.0 clr P1.1 clr P1.2 mov P2,R5 setb P1.0 clr P1.1 clr P1.2 ; 发送“写数据”命令 mov P2,#0xC0 setb P1.0 setb P1.1 setb P1.2 ; 发送像素数据 mov P2,#0xFF ret ``` 这段代码首先初始化了KS0108控制器,然后绘制了一个128x64像素的矩形。绘制矩形的过程中,先绘制上边框、右边框、下边框和左边框,然后再依次连接它们。绘制像素点的过程中,首先计算出像素点所在的页和列,然后发送“页地址”和“列地址”命令,再发送“写数据”命令和像素数据。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值