//实例84:液晶时钟设计#includereg51.h//包含单片机寄存器的头文件#includestdlib.h//包含随机函数rand()的定义文件#includeintrins.h//包含_nop_()函数定义的头文件sbitRS=P2^0;//寄存器选择位,将RS位定义为P2.0引脚sbitRW=P2^1;//读写选择位,将RW位定义为P2.1引脚sbitE=P2^2;//使能信号位,将E位定义为P2.2引脚sbitBF=P0^7;//忙碌标志位,,将BF位定义为P0.7引脚sbitk0=P1^0;sbitk1=P1^1;sbitk2=P1^2;sbitk3=P1^3;sbitk4=P1^4;sbitk5=P1^5;sbitk6=P1^6;sbitk7=P1^7;sbitk8=P2^6;sbitk9=P2^7;unsignedchartable_1[9]={0x00,0x00,0x3A,0x00,0x00,0x3A,0x00,0x00,0x00};//定义字符数组显示数字unsignedcharcount;//定义变量统计中断累计次数unsignedchars,m,h;//定义变量储存秒、分钟和小时/*****************************************************函数功能:延时1ms(3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒***************************************************/voiddelay1ms(){unsignedchari,j;for(i=0;i10;i++)for(j=0;j33;j++);}/*****************************************************函数功能:延时若干毫秒入口参数:n***************************************************/voiddelay(unsignedcharn){unsignedchari;if(k9==0)n=n/2;for(i=0;in;i++)delay1ms();}/*****************************************************函数功能:判断液晶模块的忙碌状态返回值:result。result=1,忙碌;result=0,不忙***************************************************/unsignedcharBusyTest(void){bitresult;RS=0;//根据规定,RS为低电平,RW为高电平时,可以读状态RW=1;E=1;//E=1,才允许读写_nop_();//空操作_nop_();_nop_();_nop_();//空操作四个机器周期,给硬件反应时间result=BF;//将忙碌标志电平赋给resultE=0;//将E恢复低电平returnresult;}/*****************************************************函数功能:将模式设置指令或显示地址写入液晶模块入口参数:dictate***************************************************/voidWriteInstruction(unsignedchardictate){while(BusyTest()==1);//如果忙就等待RS=0;//根据规定,RS和R/W同时为低电平时,可以写入指令RW=0;E=0;//E置低电平(根据表8-6,写指令时,E为高脉冲,//就是让E从0到1发生正跳变,所以应先置0_nop_();_nop_();//空操作两个机器周期,给硬件反应时间P0=dictate;//将数据送入P0口,即写入指令或地址_nop_();_nop_();_nop_();_nop_();//空操作四个机器周期,给硬件反应时间E=1;//E置高电平_nop_();_nop_();_nop_();_nop_();//空操作四个机器周期,给硬件反应时间E=0;//当E由高电平跳变成低电平时,液晶模块开始执行命令}/********************************************函数功能:转换******************************************************************************/voidCovhms(){table_1[0]=h/10+0x30;table_1[1]=h%10+0x30;table_1[3]=m/10+0x30;table_1[4]=m%10+0x30;table_1[6]=s/10+0x30;table_1[7]=s%10+0x30;}/*****************************************************函数功能:指定字符显示的实际地址入口参数:x***************************************************/voidWriteAddress(unsignedcharx){WriteInstruction(x|0x80);//显示位置的确定方法规定为80H+地址码x}/*****************************************************函数功能:将数据(字符的标准ASCII码)写入液晶模块入口参数:y(为字符常量)***************************************************/voidWriteData(unsignedchary){while(BusyTest()==1);RS=1;//RS为高电平,RW为低电平时,可以写入数据RW=0;E=0;//E置低电平(根据表8-6,写指令时,E为高脉冲,//就是让E从0到1发生正跳变,所以应先置0Covhms();P0=y;//将数据送入P0口,即将数据写入液晶模块_nop_();_nop_();_nop_();_nop_();//空操作四个机器周期,给硬件反应时间E=1;//E置高电平_nop_();_nop_();_nop_();_nop_();//空操作四个机器周期,给硬件反应时间E=0;//当E由高电平跳变成低电平时,液晶模块开始执行命令}/*****************************************************函数功能:对LCD的显示模式进行初始化设置***************************************************/voidLcdInitiate(void){delay(15);//延时15ms,首次写指令时应给LCD一段较长的反应时间WriteInstruction(0x38);//显示模式设置:16×2显示,5×7点阵,8位数据接口delay(5);//延时5ms,给硬件一点反应时间WriteInstruction(0x38);delay(5);WriteInstruction(0x38);//连续三次,确保初始化成功delay(5);WriteInstruction(0x0c);//显示模式设置:显示开,无光标,光标不闪烁delay(5);WriteInstruction(0x06);//显示模式设置:光标右移,字符不移delay(5);WriteInstruction(0x01);//清屏幕指令,将以前的显示内容清除delay(5);}/************************mainfunction***********************************************/voidmain(void){unsignedchari,j,k=0x00;LcdInitiate();//调用LCD初始化函数TMOD=0x01;//使用定时器T0的模式1TH0=0xD8;//定时器T0的高8位设置初值TL0=0xF0;//定时器T0的低8位设置初值EA=1;//开总中断ET0=1;//定时器T0中断允许TR0=1;//启动定时器T0count=0;//中断次数初始化为0s=0;//秒初始化为0m=0;//分钟初始化为0h=12;while(!k0)//如果是按键k0按下静止{WriteAddress(0x10);//写地址for(i=0;i8;i++){WriteData(table_1[i]);}LcdInitiate();}while(!k1)//如果是按键k1按下整体闪烁{WriteAddress(0x10);//写地址for(i=0;i8;i++){WriteData(table_1[i]);};delay(5000);delay(5000);delay(5000);WriteInstruction(0x01);delay(5000);delay(5000);delay(5000);}while(!k2)//如果是按键k2按下单字闪烁{for(j=0;j8;j++){WriteAddress(0x50);//写地址for(i=0;i8;i++){WriteData(table_1[i]);}delay(5000);delay(5000);LcdInitiate();WriteAddress(0x50);for(i=0;i8;i++){if(i==j)table_1[j]=0x00;WriteData(table_1[i]);};if(j==2||j==5)table_1[j]=0x3A;delay(5000);delay(5000);LcdInitiate();};};while(!k3)//如果是按键k3按下向前向后滚动{for(j=0;j33;j++){WriteAddress(0x00+j);//写地址for(i=0;i8;i++){WriteData(table_1[i]);};delay(5000);LcdInitiate();}for(j=31;j0;j--){WriteAddress(0x00+j);//写地址for(i=0;i8;i++){WriteData(table_1[i]);};delay(5000);LcdInitiate();};};while(!k4)//如果是按键k4按下单字移动{for(j=0;j8;j++){WriteAddress(0x50);//写地址for(i=0;i8;i++){WriteData(table_1[i]);};delay(5000);delay(5000);LcdInitiate();WriteAddress(0x10+j);WriteData(table_1[j]);WriteAddress(0x50);for(i=0;i8;i++){if(i==j)table_1[j]=0x00;WriteData(table_1[i]);};if(j==2||j==5)table_1[j]=0x3A;delay(5000);delay(5000);LcdInitiate();}};while(!k5)//如果是按键k5按下向两边扩张{WriteAddress(0x50);//写地址for(i=0;i8;i++){WriteData(table_1[i]);};delay(5000);delay(5000);LcdInitiate();WriteAddress(0x4c);//写地址for(i=0;i8;i++){WriteData(table_1[i]);WriteData(table_1[8]);};delay(5000);delay(5000);LcdInitiate