1 液晶概述
液晶(LiquidCrystal) 是一种高分子材料,因为其特殊的物理、化学、光学特性,20世纪中叶开始广泛应用在轻薄型显示器上。
液晶显示器(LiquidCrystalDisplay,LCD)的主要原理是以电流刺激液晶分子产生点、线、面并配合背部灯管构成画面。为叙述简便,通常把各种液晶显示器都直接叫做液晶。
各种型号的液晶通常是按照显示字符的行数或液晶点阵的行、列数来命名的。比如:1602的意思是每行显示16个字符,一共可以显示两行;类似的命名还有0801、0802、1601等,这类液晶通常都是字符型液晶,即只能显示ASCII码字符,如数字、大小写字母、各种符号等。12232液晶属于图形型液晶,她的意思是液晶由122列、32行组成,即共有122X32个点来显示各种图形,我们可以通过程序控制这122X32个点中的任一个点显示或不显示。类似的命名还有12864、19264、192128、320240等,根据客户需要,厂家可以设计出任意数组合的点阵液晶。
液晶体积小、功耗低、显示操作简单,但是它有一个致命的弱点,其使用的温度范围很窄,通用型液晶正常工作温度范围为0°C+55°C,存储温度范围为-20°C+60°C,即使是宽温级液晶,其正常工作温度范围也仅为-20°C+70°C,存储温度范围为-30°C+80°C,因此在设计相应产品时,务必要考虑周全,选取合适的液晶。
本章主要介绍三种具有代表性的常用液晶,同时详细讲解并行操作方式和串行操作方式。市场上使用的1602液晶以并行操作方式居多,但也有并、串口同时具有的,用户可以选择用并口或串口操作。12232液晶同样也有这两种操作方式。只有并行接口的1602液晶接口如下左图所示,其显示状态如下右图所示。
并、串口兼有的12232液晶接口如下左图所示,其显示状态如下右图所示。
12864液晶串行接口与并行接口共用,用户可选择其中一种方式操作,其接口图如下左图所示,其显示状态如下右图所示。
2 常用1602液品操作实例
1602液晶的讲解以并行操作为主,设计两个程序,一个是在液晶的任意位置显示字符,另一个是滚动显示一串字符。
本教材实验使用的1602液晶为5V电压驱动,带背光,可显示两行,每行16个字符,不能显示汉字,内置含128个字符的ASCII字符集字库,只有并行接口,无串行接口。
2.1 接口信号说明
1602型液晶接口信号说明如下表所示。
2.2 主要技术参数
2.3 基本操作时序
读状态输入:RS=L,R/W=H,E=H 输出:D0~D7=状态字。
读数据输入:RS=H,R/W=H,E=H 输出:无。
写指令输入:RS=L,R/W=L,D0~D7=指令码,E=高脉冲 输出:D0~D7=数据。
写数据输入:RS=H,R/W=L,D0~D7=数据,E=高脉冲 输出:无
2.4 RAM地址映射图
控制器内部带有80B的RAM缓冲区,对应关系如下图所示。
当我们向上图中的00~0F、40~4F地址中的任一处写入显示数据时,液晶都可立即显示出来,当写入到10~27或50~67地址处时,必须通过移屏指令将它们移入可显示区域方可正常显示。
2.5 状态字说明
注意:原则上每次对控制器进行读/写操作之前,都必须进行读/写检测,确保STA7为0。实际上,由于单片机的操作速度慢于液晶控制器的反应速度,因此可以不进行读/写检测,或只进行简短延时即可。
2.6 数据指针设置
控制器内部设有一个数据地址指针,用户可以通过它们访问内部的全部80B的RAM,如下表所示。
2.7 其他设置
2.8 初始化设置
显示模式设置:
显示开/关及光标设置
2.9 写操作时序
分析时序图可知操作 1602液晶的流程如下:
1)通过RS 确定是写数据还是写命令。写命令包括使液晶的光标显示/不显示、光标闪烁/不闪烁、需要/不需要移屏、在液晶的什么位置显示,等等。写数据是指要显示什么内容。
2)读/写控制端设置为写模式,即低电平。
3)将数据或命令送达数据线上。
4)给E一个高脉冲将数据送入液晶控制器,完成写操作。
关于时序图中的各个延时,不同厂家生产的液晶其延时不同,我们无法提供准确数据,大多数基本都为纳秒级,单片机操作最小单位为微秒级,因此我们在写程序时可不做延时,不过为了使液晶运行稳定,最好做简短延时,这需要大家自行测试以选定最佳延时。
实验板上1602液晶与单片机接口如下图所示。
接口说明如下:
1)液晶1、2端为电源;15,16为背光电源;为防止直接加5V电压烧坏背光灯,在15脚串接一个10Ω电阻用于限流。
2)液晶3端为液晶对比度调节端,通过一个10kΩ电位器接地来调节液晶显示对比度。首次使用时,在液晶上电状态下,调节至液晶上面一行显示出黑色小格为止。
3)液晶4端为向液晶控制器写数据/写命令选择端,接单片机的P3.5口。
4)液晶5端为读/写选择端,因为我们不从液晶读取任何数据,只向其写入命令和显示数据,因此此端始终选择为写状态,即低电平接地。
5)液晶6端为使能信号,是操作时必需的信号,接单片机的P3.4口。
例如:用C语言编程,实现在1602液晶的第一行显示"123456789Temp",在第二行显示" 00:00:00 "。新建文件Temp.c,程序代码如下:
#include <reg52.h> //编译器自带的库用 < > 编译器包含C52的定义
#include <intrins.h> //编译器自带的库用 < > 循环移位函数等
#include <stdio.h> //编译器自带的库用 < > 标准输入输出函数
#include <stdlib.h> //编译器自带的库用 < > C语言标准库函数#include "delay_Sum.h" //后加的库用 “ ” 延时函数、显示器延时函数
#include "74hc595_Sum.h" //后加的库用 “ ” 74hc595芯片操作
#include "boardinit_Sum.h" //后加的库用 “ ” 数码管硬件芯片定义
#include "1602_Sum.h" //后加的库用 “ ” 1602函数void main()
{ char e[14]={"123456789Temp"}; uchar m=0;boardinit(); //数码管硬件初始化lcdinit_1602(); //1602初始化while(1){ m=rand(); Disp_1602(1,1,e,16);Disp_1602(1,2," 00:00:00 ",16);write_twoline_1602(2,(int)m);delay(1000);}
}
库函数如下:
/*
* 文 件 名:1602led.c.c
* 芯 片:1602液晶
* 晶 振:11.0592MHz
* 创 建 者:XK
* 创建日期:2011.8.6
* 修 改 者:
* 修改日期:
* 功能描述:1602,写数据函数
*/#include <reg52.h>
#include "1602_Sum.h"
#include "delay_Sum.h"
#include "74hc595_Sum.h"sbit rs_1602=P2^5; //1602rs信号
sbit rw_1602=P2^6; //1602rw信号
sbit e=P2^4; /*
void write_zl(uchar zl)
{rs=0;P0=zl;delay(5);e=1;delay(5);e=0;
}void write_sj(uchar sj)
{rs=1;P0=sj;delay(5); e=1;delay(5);e=0;
} */
void write_order_1602(uchar order_data)
{e=0;rs_1602=0;P0=order_data;e=1;delay(1);e=0;
}void write_data_1602(uchar data_1602)
{ e=0;rs_1602=1;P0=data_1602;e=1;delay(1);e=0;
}/
//功能:按指定位置显示一串字符
///
//输入:
//列显示地址x_1602(取值范围1-16)
//行显示地址y_1602(取值范围1-2),
//指定字符串指针*p_1602,
//要显示的字符个数count_1602 (取值范围1-16)
///
// 子函数使用例子: Disp_1602(1,1," TEMP: . ",16); //在1602第一行第一列写16个字符,既字符串数据
/void Disp_1602(unsigned char x_1602,unsigned char y_1602,unsigned char *p_1602,unsigned char count_1602)
{
unsigned char i; for(i=0;i<count_1602;i++){if (1 == y_1602) x_1602 |= 0x80; //当要显示第一行时地址码+0x80;else x_1602 |= 0xC0; //在第二行显示是地址码+0xC0;write_order_1602(x_1602-1);write_data_1602(*p_1602);x_1602++; p_1602++;}
} void write_oneline_1602(uchar add_1602,uint date_1602)
{uchar ge,shi;shi=date_1602/10;ge=date_1602%10;write_order_1602(0x80+add_1602-1);write_data_1602(0x30+shi);write_order_1602(0x80+add_1602);write_data_1602(0x30+ge); //在1602上写时间函数 即在1602第二行指定位置上写显示}void write_twoline_1602(uchar add_1602,uint date_1602)
{uchar shi,ge;shi=date_1602/10;ge=date_1602%10;write_order_1602(0x80+0x40+add_1602-1);write_data_1602(0x30+shi);write_order_1602(0x80+0x40+add_1602);write_data_1602(0x30+ge); //在1602上写时间函数 即在1602第二行指定位}void lcdinit_1602()
{rw_1602=0;e=0;write_byte_74hc595(0X02);//关流水灯使能 关蜂鸣器 光继电器 打开1602背光打开 write_order_1602(0x38); //液晶设置不判忙模式write_order_1602(0x0c); //开显示 不显示光标write_order_1602(0x06); //当写一个字符是,地址指针加 1write_order_1602(0x01); //显示清屏
}
分析如下:
①写命令操作和写数据操作分别用两个独立的函数来完成,函数内部唯一的区别就是液晶数据命令选择端的电平,写命令函数解释如下:
void write_com(uchar com)
{lcdrs=0; //选择写命令模式P0=com;//将要写的命令字送到数据总线上delay(5);//稍做延时以待数据稳定lcden=1;//使能端给一高脉冲,因为初始化函数中已经将lcden置为0delay(5);//稍做延时lcden=0;//将使能端置0以完成高脉冲
}
②初始化函数中几个命令的解释请对照前面的指令码及功能说明。
write_com(0x38); //设置16X2显示,5X7点阵,8位数据接口
write_com(0x0c); //设置开显示,不显示光标
write_com(0x06); //写一个字符后地址指针自动加1
write_com(0x01); //显示清0, 数据指针清0
③ 进入主函数,执行完初始化函数后,用"write_com(0x80);"命令先将数据指针定位到第一行第一个字处,然后写完第一行要显示的字,在每两个字之间做简短延时,这个时间可自行测试,时间太长会影响写入及显示速度,时间太短会影响控制器接收数据的稳定性,以测试稳定为最佳。
④当写第二行时需要重新定位数据指针:write_com(0x80+0x40)。
例如:用C语言编程,实现第一行从右侧移入"Hello everyone!",同时第二行从右侧移入"Welcome to here",移入速度自定,然后停留在屏幕上,新建文件Temp.c,程序代码如下:
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar code table[]="Hello everyone!";
uchar code table1[]="Welcome to here!";
sbit lcden=P3^4; //液晶使能端
sbit lcdrs=P3^5; //液晶数据命令选择端
sbit dula=P2^6; //申明U1锁存器的锁存端
sbit wela=P2^7; //申明U2锁存器的锁存端
uchar num;
void delay(uint z)
{uint x,y;for(x=z;x>0;x--)for(y=110;y>0;y--);
}
void write_com(uchar com)
{lcdrs=0;P0=com;delay(5);lcden=1;delay(5);lcden=0;
}
void write_data(uchar date)
{lcdrs=1;P0=date;delay(5);lcden=1;delay(5);lcden=0;
}
void init()
{dula=0;wela=0;lcden=0;write_com(0x38);//设置16X2显示,5X7点阵,8位数据接口write_com(0x0c);//设置开显示,不显示光标write_com(0x06);//写一个字符后地址指针加1write_com(0x01);//显示清零,数据指针清零
}
void main()
{init();write_com(0x80+0x10);for(num=0;num<15;num++){write_data(table[num]);delay(5);}write_com(0x80+0x50);for(num=0;num<16;num++){write_data(table1[num]);delay(5);}for(num=0;num<16;num++){write_com(0x18);delay(200);}while(1);
}
分析如下:
①在写第一行数据前先定位数据指针"write_com(0x80+0x10);",将数据写在液晶第一行非显示区域地址处,写第二行时同样用’'write_com(0x80+0x10);"定位数据指针,这样写的目的是在接下来要使用移屏命令将液晶整屏向左移动。
②"write_com(0x18);"为整屏左移指令,每间隔200ms移动1个地址,共移动16个地址,刚好将要显示的数据全部移入液晶可显示区域。
③0x07指令也可完成移屏功能,大家可自行做实验验证。
3 常用12232 液晶操作实例
12232液晶的讲解以串行操作为主,设计两个程序,一个是在液晶的任意位置显示数字、符号和汉字,另一个是滚动显示一串字符。
本教材实验使用的12232液晶为5V电压驱动,带背光,内置含8192个汉字的16X16点汉字库和含128个字符的16X8点ASCII字符集。该液晶主要由行驱动器、列驱动器及128X32全点阵液晶显示器组成可完成图形显示,也可以显示7.5X2个(16X16点阵)汉字,与外部CPU接口采用并行或串行两种控制方式。
3.1 接口信号说明
12232液晶并行接口信号说明如下表所示。
12232液晶串行接口信号说明如下表所示。
3.2 主要技术参数
3.3 并行基本操作时序
读状态输入:RS=L,R/W=H,E=H 输出:D0~D7=状态字。
读数据输入:RS=H,R/W=H,E=H 输出:无。
写指令输入:RS=L,R/W=L,D0~D7=指令码,E=高脉冲输出:D0~D7=数据。
写数据输入:RS=H,R/W=L,D0~D7=数据,E=高脉冲输出:无。
3.4 忙标志(BF)
BF标志提供内部工作情况。BF=1表示模块在进行内部操作,此时模块不接受外部指令和数据。BF=0时,模块为准备状态,随时可接受外部指令和数据。
利用STATUSRD指令,可以将BF读到DB7总线来检验模块的工作状态。
3.5 字型产生ROM(CGROM)
字型产生ROM(CGROM)提供8192个触发器,用于模块内部屏幕显示开/关控制。DFF=1为开显示(DISPLAYON),此时将DDRAM的内容显示在屏幕上。DFF=0为关显示(DISPLAY
OFF)。DFF状态是由指令DISPLAYON/OFF和RST信号控制的。
3.6 显示数据RAM(DDRAM)
模块内部显示数据RAM提供64X2个位元组空间,最多可控制4行16字(64个字)的中文字型显示(本模块只用到其中的7.5X2 个)。当写入显示数据RAM时,可分别显示CGROM与CGRAM字型。此模块可显示三种字型,分别是瘦长的英数字型(16X8)、CGRAM字型及CGROM中文字型。三种字型的选择,由DDRAM中写入的编码选择,在00~0F的编码中将选择CGRAM的定义,10~7F的编码中将选择瘦长英数字的字型,至于A0以上的编码自动地结合下一个位元组,组成两个位元组的编码,形成中文字型编码(A140~D75F)。
3.7 字型产生RAM(CGRAM)
字型产生RAM提供图像定义(造字)功能,可以提供4组16X16点的自定义图像空间,使用者可以将内部字型没有提供的图像字型自行定义到CGRAM中,便可和CGROM中定义过的字型一样,通过DDRAM显示在屏幕上。
3.8 地址计数器AC
地址计数器用来存储DDRAM/CGRAM的地址,它可由设定指令暂存器来改变,之后只要读取或写入DDRAM/CGRAM的值,地址计数器就会自动加1,当RS=O且R/W=1时,地址计数器的值会被读取到DB6~DB0中。
3.9 游标/闪烁控制电路
此模块提供硬件游标及闪烁控制电路,由地址计数器的值来指定DDRAM中的游标或闪烁位置。
3.10 状态字说明
注意:原则上每次对控制器进行读/写操作之前,都必须进行读/写检测,确保STA7为0。实际上,由于单片机的操作速度低于液晶控制器的反应速度,因此可以不进行读/写检测,或只进行简短延时即可。
3.11 指令说明
另外,当RE=1时,还有一些扩充指令可设定液晶的一些功能,如待机模式、卷动地址开关开/启、反白显示、睡眠、控制功能设定、绘图模式、设定绘图RAM地址等,关于这部分扩展功能请大家查阅相关资料,这里不再赘述。
3.12 并行写操作时序
3.13 串行读/写操作时序
由于122332液晶的并行操作方式基本与1602液晶相同,所以不再讲述,本节主要讲解12232液晶的串行操作方式,这里重点讲解串行时序。
(1)CS—液晶的片选信号线,每次在进行数据操作时都必须将CS端拉高。
(2)SCLK—串行同步时钟线,每操作一位数据都要有一个SCLK跳变沿,而且在这里是上升沿有效。也就是说,每次SCLK由低电平变为高电平的瞬间,液晶控制器将SID上的数据读入或输出。
(3)SID—串行数据,每一次操作都由三个字节数据组成,第一字节向控制器发送命令控制字,告诉控制器接下来是什么操作,若为写指令则发送11111000,若为写数据则发送11111010。第二字节的高4位发送指令或数据的高4位,第二字节的低4位补0。第三字节的高4位发送指令或数据的低4位,第三字节的低4位同样补0。
12232液晶的串行接口非常简单,只需要三条线与单片机的任意三个I/O口相连即可操作,下图为12232的最简单接线图,这里我们没有加入背光,3端的对比度调节端接一10kΩ电位器的滑动端,电位器另两端分别接Vcc和GND,注意这里和1602液晶有所不同,现在市面上也有部分12232液晶不需要调节对比度,出厂时已经设定好。SCLK、SID、CS三条线与单片机的任意I/O口相连,实验板上连接方式见源程序。
分析如下:
(1)发送命令和发送数据分别用"send_command()"和"send_data()"函数实现,由前面的描述可知,无论是发送一条命令还是发送一条数据都是由三个字节组成,若发送指令则第—个字节为0xf8,若发送数据则第一个字节为0xfa,从上面两个函数可看出,它们的不同之处也就在这里。
(2)"SID=(bit)(i_data&0x80);"中(bit)表示将后面括号里的数强制转换成位,当把一个字节强制转换成一位时使用(bit),这里只取这个字节的最高位。整条语句的意思是,将i_data的最高位取出来赋给SID。然后通过下面的"i_data=i_data<<1;"依次将i_data的每一位从高到低在SCLK的作用下送给SID,从而发送给液晶。
(3)"i_data=command_data;"和"i_data&=0xf0;"这两句的意思是,将所发送字节的高4位取出,低4位补0。
"i_data=command_data;"和"i_data<<=4;"这两句的意思是,将所发送字节的低4位移到高4位的位置上,原来的低4位自动补0。
(4)"lcd_init()“是对12232液晶的初始化设置,只有对液晶进行了正确的初始化设置,液晶才可正常运行。
例如:用C语言编程,实现第一行从右侧移入"Hello everyone!”,同时第二行从右侧移入“欢迎大家来学习!",移入速度自定,最后停留在屏幕上。新建文件Temp.c,程序代码如下:
#include <REG52.h>
#define uint unsigned int
#define uchar unsigned char
sbit CS=P1^2;
sbit SID=P1^1;
sbit SCLK=P1^0;
uchar code disps[]={"Hello everyone!"};
uchar code dispx[]={"欢迎大家来学习!"};void delay_1ms(uint x)
{
uint i,j;
for(j=0;j<x;j++) for(i=0;i<110;i++);
}
void send_command(uchar command_data)
{ uchar i; uchar i_data;i_data=0xf8; CS=1; SCLK=0; for(i=0;i<8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data<<1; } i_data=command_data; i_data&=0xf0;for(i=0;i<8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data<<1; } i_data=command_data; i_data<<=4;for(i=0;i<8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data<<1; } CS=0; delay_1ms(1);
}
void send_data(uchar command_data)
{ uchar i; uchar i_data;i_data=0xfa; CS=1; for(i=0;i<8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data<<1; } i_data=command_data; i_data&=0xf0; for(i=0;i<8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data<<1; } i_data=command_data;i_data<<=4; for(i=0;i<8;i++) { SID=(bit)(i_data&0x80); SCLK=0; SCLK=1; i_data=i_data<<1; } CS=0; delay_1ms(1);
}
void lcd_init()
{ delay_1ms(100); send_command(0x30); /*设置8位数据接口,基本指令模式。*/ send_command(0x02); /*清DDRAM*/ send_command(0x06); /*游标及显示右移一位*/ send_command(0x0c); /*整体显示开,游标关,反白关*/ send_command(0x01); /*写入空格清屏幕*/ send_command(0x80); /*设定首次显示位置*/ }
void display_s(uchar num)
{uchar a;send_command(0x88-num);for(a=0;a<15;a++){send_data(disps[a]); }
}
void display_x(uchar num)
{ uchar a;send_command(0x98-num);for(a=0;a<15;a++){send_data(dispx[a]); }
}
main()
{ uchar aa;lcd_init(); for(aa=0;aa<9;aa++){display_s(aa);display_x(aa); delay_1ms(300);}while(1);
}
分析如下:
(1)由于12232液晶没有专门的移屏指令,因此我们使用for循环来实现移屏效果,实际上这种效果是重复向不同的地方写入显示字符而实现的。用这种方法看上去是从右往左移动,也可以使它从左向右移动。
(2)"delay_lms(300);"这个延时函数决定屏幕移动的速度,大家可做测试,自行调节。
4 常用12864液品操作实例
12864液晶操作方法与7.3节12232液晶操作方法非常相似,本节讲解其并行操作方法,设计一个程序,在液晶的任意位置显示数字、符号和汉字。
本教材实验用12864液晶使用ST7920控制器,5V电压驱动,带背光,内置8192个16X16点阵、128个字符(8X16点阵)及64X256点阵显示RAM(GDRAM)。与外部CPU接口采用并行或串行两种控制方式。
4.1 接口信号说明
12864液晶接口信号说明如下表所示。
4.2 主要技术参数
4.3 并行基本操作时序
读状态 输入:RS=L,R/W=H,E=H 输出:D0~D7=状态字。
读数据 输入:RS=H,R/W=H,E=H 输出:无。
写指令 输入:RS=L,R/W=L,D0~D7=指令码,E=高脉冲 输出:D0~D7=数据。
写数据 输入:RS=H,R/W=L,D0~D7=数据,E=高脉冲 输出:无。
4.4 忙标志(BF)
BF标志提供内部工作情况,BF=1表示模块在进行内部操作,此时模块不接受外部指令和数据。BF=0时,模块为准备状态,随时可接受外部指令和数据。
利用STATUSRD指令,可以将BF读到DB7总线来检验模块的工作状态。
4.5 状态字说明
注意:原则上每次对控制器进行读/写操作之前,都必须进行读/写检测,确保STA7为0。实际上,由于单片机的操作速度低于液晶控制器的反应速度,因此可不必进行读/写检测,或只进行简短延时即可。
4.6 指令说明
另外,当RE=1时,还有一些扩充指令可设定液晶功能,如待机模式、卷动地址开关开启、反白显示、睡眼、控制功能设定、绘图模式、设定绘图RAM地址等,下面详细解释各个指令。
4.7 指令详解
4.8 显示坐标关系
(1)图形显示坐标
水平方向X以字为单位,垂直方向Y以位为单位。
绘图显示RAM提供128X8B的记忆空间,在更改绘图RAM时,先连续写入水平与垂直的坐标值,再写入两个字节的数据,而地址计数器(AC)会自动加1;在写入绘图RAM期间,绘图显示必须关闭。写入绘图RAM的步骤如下:
①关闭绘图显示功能。
②先将水平的位元组坐标(CX)写入绘图RAM地址。
③再将垂直的坐标(Y)写入绘图RAM地址。
④将D15~D8写入到RAM中。
⑤将D7~D0写入到RAM中。
⑥打开绘图显示功能,绘图显示缓冲区分布如下图绘图显示坐标所示。
(2)汉字显示坐标
4.9 并行写操作时序
4.10 串行读/写操作时序
对比上节12232液晶的时序图可知,无论是并行操作还是串行操作,12864液晶与12232液晶几乎完全一样。
12864液晶的串行接口也非常简单,并行连接到实验板上原理图如下图所示。
例如:用C语言编程,在12864液晶上第一行显示"----欢迎使用----",并且让每一位数字随机变化,第二行显示"QQ:1296416321",第三行显示"博客:Tom",第三行显示"祝你学习愉快"。新建文件Temp.c,程序代码如下:
#include <reg52.h> //编译器自带的库用 < > 编译器包含C52的定义
#include <intrins.h> //编译器自带的库用 < > 循环移位函数等
#include <stdio.h> //编译器自带的库用 < > 标准输入输出函数
#include <string.h> //编译器自带的库用 < > 字符串处理函数#include "delay_Sum.h" //后加的库用 “ ” 延时函数、显示器延时函数
#include "74hc595_Sum.h" //后加的库用 “ ” 74hc595芯片操作
#include "boardinit_Sum.h" //后加的库用 “ ” 数码管硬件芯片定义
#include "12864_Sum.h" //后加的库用 “ ” 12864函数unsigned char code IC_DAT[]={
"----欢迎使用----"
" QQ:1371129880 "
" 博客:Sumjess "
" 祝你学习愉快 "
};unsigned char code IC_DAT2[]={
"我爱你时, "
"我不爱你时, "
"你是那么的闪耀 "
"你什么都不是。 "
};void main()
{ boardinit(); //数码管硬件初始化while(1){ initinal();//调用LCD字库初始化程序delay(5);lcd_mesg(IC_DAT);delayms(300); //延时程序必要的,长与短,自己调节initinal();delay(5);lcd_mesg(IC_DAT2);delayms(300); }}
库函数:
#include <reg52.h>
#include "12864_Sum.h"
#include "74hc595_Sum.h"sbit RS = P2^5; //注意:一定要看12864液晶模块的资料,来确定怎样操作
sbit WRD = P2^6;sbit E = P2^4;
sbit PSE = P1^3;
sbit RES = P1^5;void lcd_mesg(unsigned char code *addr1) //显示汉字函数,8*4=32
{
unsigned char i;
TransferData(0x80,0);
delay(100);
for(i=0;i<32;i++){TransferData(*addr1,1);addr1++;}TransferData(0x90,0);delay(100);for(i=32;i<64;i++){TransferData(*addr1,1);addr1++;}
}
void TransferData(char data1,bit DI) //传送数据或是命令,当DI=0时,传送命令,当DI=1时,传送数据
{
WRD=0;
RS=DI;
P0=0XFF;
P0=data1;
E=1;// 置12684 使能端 E=1;
delay(1);
E=0;// 置12684 使能端 E=0;
}void initinal(void) //初始化,12864有要求的要写上
{
PSE=1; //并口工作模式
RES=0; //复位
RES=1; //复位置高
TransferData(0x30,0);
TransferData(0x30,0);
TransferData(0x08,0);
TransferData(0x10,0);
TransferData(0x0C,0);
TransferData(0x01,0);
TransferData(0x06,0);}
分析如下:
(1)写命令和写数据分别用两个函数"write_cmd()"和"write_dat()"来实现,由于其并行操作时序与1602液晶一样,这里不再讲解。
(2)"lcd_pos()"函数用来设定液晶上显示的位置。12864液晶一共可以显示4行,每行可以显示8个汉字或16个字符,每一个汉字位置都有固定的地址,设置不同的地址即可在不同的位置上显示字符,关于其显示位置及地址请参照前面的汉字显示坐标。
(3)
i=0;
while(dis2[i]!=’\0’)
{write_dat(dis2[i]); //显示字符1++;
}
上面程序段实现的功能是,将数组dis2[]中的所有字符一个个地显示在液晶屏幕上。程序执行时,依次查询数组dis2[]中的所有元素,当查到一个“空”时,退出此while循环语句,
“空”在存储器中的存储形式是\0’'如果数组中有8个元素,那么第9个元素即为“空”。
(4)"makerand()"函数生成10个随机数,然后把这10个随机数存在数组dist[]中。实际上,在函数中只调用了两次随机数生成函数,产生了两个5位的随机数,然后再将这两个5位的随机数分别取出存储在数组中。关千随机数生成函数的介绍请看下一个知识点。
4.11 单片机中如何生成随机数
打开Keil\C51\HLP文件夹下的C51lib.chm文件,在索引文件夹下输入"rand",详细内容如下:
#include <stdlib.h>
int rand (void);
Description:The rand function generates a pseudo-random number between 0 and 32767.
Return Value:The rand function returns a pseudo-random number.
rand()函数生成一个0~32767之间的伪随机数,函数运行完后将返回这个伪随机数,另外还可以看到void srand (inseed); /*random number generator seed*/
Description:The srand function sets the starting value, seed, used by the pseudo-random number generator in the rand function. The random number generator produces the same sequence of pseudo-random numbers for any given value of seed.
Return Value:None.
srand(int seed)函数可设置一个初值,然后调用rand()函数生成一个初值与32767之间的随机数。如:
int a;
srand(200);
a=rand();
这时,a的值将是200~32767之间的一个随机数,大家可自行写程序测试,看如何写一个函数让它生成0-10或0-100之间的随机数。