现在玩51的人少了,把两年前的笔记发上来赚点积分, `E`HVZ}
曾用这个程序,c语言写了个1602秒表,不用中断定时,只用软件延时,达到17分钟5秒的误差 T0QvnIaP
这5秒的误差应理解成晶振的误差和温度引起的原因 r@}bDkx
/*****************************************/ 3vic(^Qh
/*项目名:lcd1602显示程序 @F5f"8!.\
/*程序名: <M+R\SH-
/*公司名称: "VUYh$=[
/*创始人: 日期:2011-12-28 L^J-("e_
/*修改人: 日期: IApT'QNM
/*功能描述:写入1个字符和写入字符串 X9=N%GY[
/*其他说明: 1y"3
/*版本:1.0 aMuVqZw
/*****************************************/ ]N)DS+V/
#include<AT89X51.h> /f{$I
#include<intrins.h> wa09$4>_w
#define uchar unsigned char eVz#7vqv
#define uint unsigned int +Ic ~ f1zh
sbit RS=P2^5;//寄存器选择位,1602的第4脚。 2.I^Xf2
sbit RW=P2^6;//读写选择位,1602的第5脚。 =t0tK}Y+4
sbit E=P2^7;//使能信号位,1602的第6脚。
Qd`T5[b\
sbit BF=P0^7; //忙碌标志位,,将BF位定义为P0.7引脚 J ++v@4Z
uchar code lcdstring[]={"LCD1602"}; |`O5Xs1{B
/*****************************************/ 4vZ4/#(x
/*函数名:delayms() 9(_{`2R8
/*功能描述:延时 FiAY\4
/*函数说明:最高65535ms,最低1ms S -&)p@4
/*调用函数:无 sH#X0fG
/*全局变量:无 UXr5aZ7y
/*输入:unsigned int t rxZi8w>}
/*返回:无 _r Y,}\
/*设计者:张周伟 日期:2011-12-19 0HeD{TH\
/*修改者: 日期: 7
h=QW5
/*版本:1.0 $9!D\N,}]C
/*****************************************/ lHfe<j]
void delayms(uint t) k%'m *T f
{ GC@+V|u
uchar i; y*b3&%.ml
while(t--)for(i=0;i<120;i++); .giz=*q+
} #E7AmmqD%
/***************************************************** nA7M8HB
函数功能:判断液晶模块的忙碌状态 zU5Hb2a
返回值:result。result=1,忙碌;result=0,不忙 E)N<lh
***************************************************/ ,yMU@Vg
uchar BusyTest(void) 9]'&RyH=#
{ j+4H}XyE
bit result; Z=S>0|`R
RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态 yzsab ^]
RW=1; !BIOY!M
E=1; //E=1,才允许读写 A=5epsB
_nop_(); //空操作 KDP H6
_nop_(); ZAKeEm2A
_nop_(); ~ Hy,7
_nop_(); //空操作四个机器周期,给硬件反应时间 Rf-[svA
result=BF; //将忙碌标志电平赋给result tB7}|jC
E=0; //将E恢复低电平 bru/AZ# de
return result; O\KQl0*l\\
} uGU;Y'W)
/***************************************************** &[mZD,
函数功能:将模式设置指令或显示地址写入液晶模块 F/d7q%I
入口参数:dictate q%>'4_
***************************************************/ >gll-&;t
void WriteInstruction (unsigned char dictate) ^D^JzEy'?C
{ w~R`D
while(BusyTest()==1); //如果忙就等待 d)o!5L
RS=0; //根据规定,RS和R/W同时为低电平时,可以写入指令 bizTd
RW=0; BG&cQr
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲, Joe_PS
// 就是让E从0到1发生正跳变,所以应先置"0" Flxvhl)L
_nop_(); t>)45<PEw
_nop_(); //空操作两个机器周期,给硬件反应时间 1SIq[1
P0=dictate; //将数据送入P0口,即写入指令或地址 (6p]ZY
_nop_(); p{dwZ_gl
_nop_(); 9i5,2~
_nop_(); h&3YGCl
_nop_(); //空操作四个机器周期,给硬件反应时间 :p&!RI(l
E=1; //E置高电平 i`(^[h
?;
_nop_(); /.Nov
_nop_(); nwt C:*}
_nop_(); y4:H3Sk
_nop_(); //空操作四个机器周期,给硬件反应时间 hG~reVNf
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 XZNY4/25G
} dx*qb
/***************************************************** DmVP
函数功能:指定字符显示的实际地址 ^>y@4q B
入口参数:x {yU+)t(.
***************************************************/ $2DuB
void WriteAddress(unsigned char x) ~9\WFF/
{ q*![AzFh
WriteInstruction(x|0x80); //显示位置的确定方法规定为"80H+地址码x" g$:Xuw1
} RyB~Lm`ZK%
/***************************************************** tGdf/aTjy
函数功能:将数据(字符的标准ASCII码)写入液晶模块 M~*u;vA/
入口参数:y(为字符常量) w6dFb6~R
***************************************************/ D0(xNhmKz
void WriteData(unsigned char y) vKwQXR~C
{ R2L;bGI*J
while(BusyTest()==1); 2jsw"aHW
RS=1; //RS为高电平,RW为低电平时,可以写入数据 Lj\/Ji_
RW=0; |sZ!
E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲, S_T^G` [
// 就是让E从0到1发生正跳变,所以应先置"0" ,B&fFis
P0=y; //将数据送入P0口,即将数据写入液晶模块 depYqYK7G
_nop_(); R:JX<Ba
_nop_(); "1q>At
_nop_(); !|q<E0@w\
_nop_(); //空操作四个机器周期,给硬件反应时间 X7UuwIIP
E=1; //E置高电平 oBq 49u1
_nop_(); v1k)hFjPK
_nop_(); ffXyc2o
_nop_(); bb42v7?
_nop_(); //空操作四个机器周期,给硬件反应时间 e6X[vc|Y}
E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令 8By,#T".
} 22<0DhJ
/***************************************************** &AuF]VT
函数功能:对LCD的显示模式进行初始化设置 Dlo xrdOY&
***************************************************/ B()/.w?A
void LcdInitiate(void) SYeadsvF
{ p2J|Hl|
delayms(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间 f"7M^1)h2%
WriteInstruction(0x38); //显示模式设置:001(0/1数据总线4位/8位)(0/1显示1行/2行)(0/1每字符5x7点阵/5x10)xx {Y}dv`G#Iu
delayms(5); //延时5ms ,给硬件一点反应时间 )2UZ% ?V#
WriteInstruction(0x38); ~'5
delayms(5); %;D+k
WriteInstruction(0x38); //连续三次,确保初始化成功 3'c\;1lhT
delayms(5); )5%C3/Dl!
WriteInstruction(0x06); //显示模式设置:显示开,无光标,光标不闪烁 000001(0/1光标左移/右移)(0/1写入新数据后显示屏不移动/显示屏右移1个字符) {:c]|^w6
delayms(5); vvB(r!
WriteInstruction(0x0c); //显示模式设置:光标右移,字符不移 00001(0/1显示器关/开)(0/1无光标/有光标)(0/1光标闪/不闪) /!}'t
delayms(5); .t&R>9cZ^
WriteInstruction(0x01); //清屏幕指令,将以前的显示内容清除 Hv]7e|
delayms(5); 7@.cOB`y@3
// 移动方向设置:显示屏或光标 0001()()xx zJ+8FWy:S
//(0)(0)=光标左移1格,ac-1()() //(0)(1)=光标右移1格,ac+1 H4OhIxK
//(1)(0)=显示器上的字符全部左移1格,光标不动 //(1)(1)=显示器上的字符全部右移1格,光标不动 SxyONp.$\
o ]Jv;Iy@?
} :RSz4
//主程序 \^1+U JU
/*void main() zPEg
{ krq/7|
uchar lcdi=0; !$A 37j6
LcdInitiate(); //调用LCD初始化函数 KucV3-I
delayms(10); //延时10ms,给硬件一点反应时间 EzW)'Zzw~
WriteAddress(0x00); //写入一个字符 ES <1tG
WriteData('L'); x?x`oirh
WriteAddress(0x01); //写入一个字符 Q@e[5RA+]
WriteData('C'); $(s\{(Wn
WriteAddress(0x02); //写入一个字符 -K(fh#<6KO
WriteData('D'); |vte=)%
WriteAddress(0x40); //写入字符串 //第二行第一个位置开始显示 yix'rA -T
while(lcdstring[lcdi]!='\0') `<^VR[Mx
{ l5Y/Ok0,
WriteData(lcdstring[lcdi]); #8{F9w<Rf
lcdi++; //指向下字符数组一个元素 ,3v+PIcMM+
} OE)~yKy
delayms(100); 53 QfTP
while(1); 2c<&eX8"
} *////