在Proteus中模拟了89C52操作HDG12864F-1液晶屏,原理图如下:
一、HDG12864F-1官网信息
该液晶屏是Hantronix的产品,官网上搜索出这个型号是系列型号中的一种,各种型号间的区别主要是尺寸不同、有无背光、背光颜色等等。
下面是官网中几个手册的链接:
二、基本操作函数
根据几个手册提供的信息,“写命令”和“写数据”函数如下:
1 sbit cs = P1^7;//-cs,片选,低电平有效 2 sbit rst = P1^6;//-rst,复位,低电平有效 3 sbit a0 = P1^5;//写命令、写数据控制位。1=Display data; 0=Control data; 4 sbit wr = P1^4;//-Write serial data,写串口数据,低电平有效 5 sbit rd = P1^3;//-Read serial data,读串口数据,低电平有效 6 sbit scl = P1^2;//Shift clock input,时钟输入 7 sbit si = P1^1;//Serial data input,串口数据输入 8 //手册中说了,各种操作都是ns级,不用各种等待命令,下面操作也没有写入等待功能 9 //写命令 10 void wrt_cmd(unsigned char command) 11 { 12 unsigned char i = 8; 13 cs = 0; 14 a0 = 0;//0=Control data,命令置0 15 wr = 0; 16 rd = 1; 17 while(i--){ 18 scl = 0; 19 si = (bit) (command & 0x80);//先写高位 20 scl = 1; 21 command <<= 1; 22 } 23 scl = 0; 24 } 25 //写数据 26 void wrt_dt(unsigned char data_) 27 { 28 unsigned char i = 8; 29 cs = 0; 30 wr = 0; 31 a0 = 1;//1=Display data,写数据置1 32 rd = 1; 33 while(i--){ 34 scl = 0; 35 si = (bit) (data_ & 0x80); 36 scl = 1; 37 data_ <<= 1; 38 } 39 scl = 0; 40 }
三、显存和屏幕的对应关系
手册中有描述,不太好理解,网上也查了不少,还是用自己的方法好理解一些。
在详细说明对应关系前,必须提到该芯片有正、反两种写入方向,ADC Select (Segment Driver Direction Select),见完整版手册第50页。厂家居然把“从屏幕右边开始写”称为“正”,看着别扭。不过我先看的是“正”的,下面就先“正”着说。手册中对正反的描述如下:
- 屏幕从左到右分成128列,分别是column0~column127,后面简称c0~c127,每一列对应着屏幕上横向的一个点;同时,从上到下分成8行,手册中将每一行称之为1个Page,每个Page对应着一个字节,恰好8个bit,每个bit对应着屏幕上纵向的一个点,8个Page一共8*8=64个点。这样,就将屏幕分成了128*64个点。“使用注意事项”中给出了图示:
2. 大格局说清楚了,再来说说写RAM的顺序,我在这里绕了好长时间,利用下面的图形反复校对终于搞清楚了。图中:1-代表亮点,空白(0)-代表暗点。
下图一共有8*8的点阵4个,形成了一个16*16的大点阵,一个16*16的大点阵可以显示一个汉字。
如果从屏幕右上角开始显示汉字,则有:
- 右上角的点阵代表汉字的右上角,其中每一列8个点构成一个Byte,下面的点是高位,上面的点是低位,例如:代表C0列的Byte为1010 1011B=abH。
- 因为写数据的时候是从右边开始,所以字模数组的顺序也是从右边开始的。例如右上角8*8点阵形成的数组为:N[0],N[1],N[2],N[3],N[4],N[5],N[6],N[7]。
- 写完一个Byte后,控制器将列坐标自动加1,因此按0~7的顺序写完这个数组后,在屏幕的右上角就完成了一个汉字右上四分之一的显示。
- 接着连续写汉字左上四分之一,就是写N[8]~N[15]共8个字节。到这里一个汉字的上半部分就写完了。
- 接下来就是更改Page了(相当于更改纵向位置)。刚才写汉字的上半部分时,纵坐标是在Page=0的位置,现在需要将纵坐标设置成Page=1;同时,也要将列重新设置为0。这样再连续写N[16]~N[31]共16个Byte后,一个完整的汉字就在屏幕上写好了。
这段功能的主程序和实际效果如下:
1 #include "HDG12864F1.h" 2 void main(void) 3 { unsigned char i; 4 unsigned char chinachar[32] = { 5 0xab,0xab,0xab,0xab, 0xab,0xab,0xab,0xab, 6 0x55,0x55,0x55,0x55, 0x55,0x55,0x55,0x55, 7 0xaa,0xaa,0xaa,0xaa, 0xaa,0xaa,0xaa,0xaa, 8 0xd5,0xd5,0xd5,0xd5, 0xd5,0xd5,0xd5,0xff 9 }; 10 //HDG12864F1_Direction(DISPLAY_LEFT_TO_RIGHT); 11 HDG12864F1_SetColumnAddress(0);//设开始写的横向坐标为C0 12 HDG12864F1_SetPageAddress(0);//设开始写的纵向坐标为Page0 13 for(i=0; i<16; i++){ 14 HDG12864F1_WriteData(chinachar[i]);//连续写汉字的上半部分 15 } 16 HDG12864F1_SetColumnAddress(0);//再将横向坐标设为C0 17 HDG12864F1_SetPageAddress(1);//将纵向坐标设为Page1 18 for(i=16; i<32; i++){ 19 HDG12864F1_WriteData(chinachar[i]);//连续写汉字的下半部分 20 } 21 }
其中,用到的几个函数如下。设置纵向位置、列位置两个函数,分别根据手册要求编写,见下图中(3)Page address set和(4)Column address set。
1 //设置列位置,其中参数address:0~127 2 void HDG12864F1_SetColumnAddress(unsigned char address) 3 { //写列要分成两步走,先写高四位,再写低四位 4 wrt_cmd(0x10 + (address >> 4 & 0x0f));//C中右移是算术右移,必须&0x0f去掉高4位才能得到正确的结果 5 wrt_cmd(address & 0x0f); 6 } 7 //设置纵向位置,其中参数pageAddress:0~8 8 void HDG12864F1_SetPageAddress(unsigned char pageAddress) 9 { 10 wrt_cmd(0xb0 + pageAddress); 11 } 12 //写数据 13 void HDG12864F1_WriteData(unsigned char data_) 14 { 15 wrt_dt(data_); 16 }
3. 上面说的内容都是以“从右侧开始写入”为条件的,也就是厂家所说的“正”着来,这不太符合我们日常的习惯,厂家也考虑到了这一点,并且提供了一个功能,让用户决定从左还是从右开始写起,就是上图中(9)Display normal/reverse。为了更加清楚,定义了两个宏,使用的时候直接把参数direction换成需要的宏即可。
1 #define DISPLAY_LEFT_TO_RIGHT 0 2 #define DISPLAY_RIGHT_TO_LEFT 1 3 void HDG12864F1_Direction(unsigned char direction) 4 { 5 wrt_cmd(0xa0+direction); 6 }
将main()函数第10行注释的“//”去掉,再次运行程序得到字形呈镜面对称。
4. 另外,还验证了上2图中功能(2)Display start line set,该功能的作用是对写好的屏幕内容向上滚屏,滚出上边的部分会从屏幕下边冒出来,我设置了一个循环,对该函数的参数从0~63逐次加1,刚刚开始运行后截屏得到的图形如下。
1 //参数line取值范围0~63 2 void HDG12864F1_SetStartLine(unsigned char line) 3 { 4 wrt_cmd(0x40 + line); 5 }
5. 其他功能还有很多,没有逐个试验,下面贴出功能表的下半部分,需要时可参考。
来源:https://www.cnblogs.com/jqdy/p/12410665.html