|
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include<reg52.h> //包含单片机寄存器的头文件
- #include<intrins.h> //包含_nop_()函数定义的头文件
- #define uchar unsigned char
- #define uint unsigned int
- sbit RS=P2^0; //寄存器选择位,将RS位定义为P2.0引脚
- sbit RW=P2^1; //读写选择位,将RW位定义为P2.1引脚
- sbit E=P2^2; //使能信号位,将E位定义为P2.2引脚
- sbit BF=P0^7; //忙碌标志位,将BF位定义为P0.7引脚
- sbit k1=P3^2; //功能键
- sbit k2=P3^4; //加键
- sbit k3=P3^5; //减键
- sbit k4=P3^7; //保存并退出、开启或关闭闹钟
- sbit buzz=P1^0; //蜂鸣器
- uchar code table[] = " 19-59-55 0N "; //初始化液晶显示
- uchar code table1[] = " 19-59-50 ";
- uchar count,k1num;
- char sec = 50,min = 59,hour = 19;//时钟秒、分、时
- char s = 55,m = 59,h = 19; //闹秒、分、时
- char alarm_flag = 0; //闹钟开启关闭标志位 0开启;1关闭
- char num = 0; //用于蜂鸣器报警时间计数
- /****延时若干毫秒****/
- void delay(uchar n)
- {
- uchar i,a,b;
- for(i=0;i<n;i++)
- for(b=199;b>0;b--)
- for(a=1;a>0;a--);
- }
- /***********************************************
- 函数功能:判断液晶模块的忙碌状态
- 返回值:result。result=1,忙碌;result=0,不忙
- ************************************************/
- uchar BusyTest(void)
- {
- bit result;
- RS=0; //根据规定,RS为低电平,RW为高电平时,可以读状态
- RW=1;
- E=1; //E=1,才允许读写
- _nop_(); //空操作
- _nop_();
- _nop_();
- _nop_(); //空操作四个机器周期,给硬件反应时间
- result=BF; //将忙碌标志电平赋给result
- E=0; //将E恢复低电平
- return result;
- }
- /********************************************
- 函数功能:写指令
- 入口参数:dictate
- *********************************************/
- void Write_add(uchar dictate)
- {
- 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由高电平跳变成低电平时,液晶模块开始执行命令
- }
- /*********************************************
- 函数功能:写数据
- 入口参数:y(为字符常量)
- **********************************************/
- void Write_data(uchar y)
- {
- while(BusyTest()==1);
- RS=1; //RS为高电平,RW为低电平时,可以写入数据
- RW=0;
- E=0; //E置低电平(根据表8-6,写指令时,E为高脉冲,
- //就是让E从0到1发生正跳变,所以应先置"0"
- P0=y; //将数据送入P0口,即将数据写入液晶模块
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四个机器周期,给硬件反应时间
- E=1; //E置高电平
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四个机器周期,给硬件反应时间
- E=0; //当E由高电平跳变成低电平时,液晶模块开始执行命令
- }
- /******************************************
- 函数功能:对LCD的显示模式进行初始化设置
- *******************************************/
- void LcdInitiate(void)
- {
- uchar num;
-
- count=0;
- k1num=0;
- E=0;
- delay(15); //延时15ms,首次写指令时应给LCD一段较长的反应时间
- Write_add(0x38); //显示模式设置:16×2显示,
- //5×7点阵,8位数据接口
- delay(5); //延时5ms?,给硬件一点反应时间
- Write_add(0x38);
- delay(5);
- Write_add(0x38); //连续三次,确保初始化成功
- delay(5);
- Write_add(0x0c); //显示模式设置:显示开,无光标,
- //光标不闪烁
- delay(5);
- Write_add(0x06); //显示模式设置:光标右移,字符不移
- delay(5);
- Write_add(0x01); //清屏幕指令,将以前的显示内容清除
- delay(5);
- Write_add(0x80);
- for(num=0;num<16;num++) //让液晶显示日期
- {
- Write_data(table[num]);
- delay(5);
- }
- Write_add(0x80+0x40);
- for(num=0;num<14;num++) //让液晶显示时间
- {
- Write_data(table1[num]);
- delay(5);
- }
- TMOD=0x01; //定时器中断初始化
- TH0=(65536-50000)/256;
- TL0=(65536-50000)%256;
- EA=1;
- ET0=1;
- TR0=1;
- }
- /**********写实时时分秒************/
- void write_sfm(uchar add,uchar date)
- {
- uchar i,j;
- i=date/10;
- j=date%10;
- Write_add(0x80+0x40+add);
- Write_data(0x30+i);
- Write_data(0x30+j);
- }
- /**********写闹钟时分秒************/
- void write_alarm(uchar add,uchar date)
- {
- uchar i,j;
- i=date/10;
- j=date%10;
- Write_add(0x80+add);
- Write_data(0x30+i);
- Write_data(0x30+j);
- }
- /**********写ON字符串************/
- void write_ON()
- {
- char i;
- char p[3] = "0N ";
-
- for(i=0;i<3;i++)
- {
- Write_add(0x80+(13+i));
- Write_data(p[i]);
- }
- }
- /**********写OFF字符串************/
- void write_OFF()
- {
- char i;
- char p[3] = "0FF";
-
- for(i=0;i<3;i++)
- {
- Write_add(0x80+(13+i));
- Write_data(p[i]);
- }
- }
- //键盘扫描
- void keyscan()
- {
- if(k1==0) //第一个键是否按下
- {
- delay(5);
- if(k1==0)
- {
- while(!k1); //松手检测
- k1num++;
- if(k1num>6)
- k1num=1;
- if(k1num==1) //k1按下 光标跳转
- {
- TR0=0;//在调整界面停止计时
- Write_add(0x80+0x40+11); //设置光标位置
- Write_add(0x0f);
- }
- if(k1num==2)
- {
- Write_add(0x80+0x40+8);
- }
- if(k1num==3)
- {
- Write_add(0x80+0x40+5);
- }
- if(k1num==4)
- {
- Write_add(0x80+11);
- }
- if(k1num==5)
- {
- Write_add(0x80+8);
- }
- if(k1num==6)
- {
- Write_add(0x80+5);
- }
- }
- }
- if(k1num!=0) //如果功能键被按下后
- {
- if(k2==0) //k2按下
- {
- delay(5);
- if(k2==0)
- {
- while(!k2); //松手检测
- if(k1num==1) //k1键被按一次,时钟 秒加一
- {
- sec++;
- if(sec==60)
- sec=0;
- write_sfm(10,sec);
- Write_add(0x80+0x40+11);
- }
- if(k1num==2) //k1键被按二次,时钟 分加一
- {
- min++;
- if(min==60)
- min=0;
- write_sfm(7,min);
- Write_add(0x80+0x40+8);
- }
- if(k1num==3) //k1键被按三次,时钟 时加一
- {
- hour++;
- if(hour==24)
- hour=0;
- write_sfm(4,hour);
- Write_add(0x80+0x40+5);
- }
- if(k1num==4) //k1键被按四次,闹钟 秒加一
- {
- s++;
- if(s==60)
- s=0;
- write_alarm(10,s);
- Write_add(0x80+11);
- }
- if(k1num==5) //k1键被按五次,闹钟 分加一
- {
- m++;
- if(m==60)
- m=0;
- write_alarm(7,m);
- Write_add(0x80+8);
- }
- if(k1num==6) //k1键被按六次,闹钟 时加一
- {
- h++;
- if(h==24)
- h=0;
- write_alarm(4,h);
- Write_add(0x80+5);
- }
- }
- }
- if(k3==0) //k3键被按下
- {
- delay(5);
- if(k3==0)
- {
- while(!k3);
- if(k1num==1) //时钟 秒减一
- {
- sec--;
- if(sec<=-1)
- sec=59;
- write_sfm(10,sec);
- Write_add(0x80+0x40+11);
- }
- if(k1num==2) //时钟 分减一
- {
- min--;
- if(min<=-1)
- min=59;
- write_sfm(7,min);
- Write_add(0x80+0x40+8);
- }
- if(k1num==3) //时钟 时减一
- {
- hour--;
- if(hour<=-1)
- hour=23;
- write_sfm(4,hour);
- Write_add(0x80+0x40+5);
- }
- if(k1num==4) //闹钟 秒减一
- {
- s--;
- if(s<=-1)
- s=59;
- write_alarm(10,s);
- Write_add(0x80+11);
- }
- if(k1num==5) //闹钟 分减一
- {
- m--;
- if(m<=-1)
- m=59;
- write_alarm(7,m);
- Write_add(0x80+8);
- }
- if(k1num==6) //闹钟 时减一
- {
- h--;
- if(h<=-1)
- h=23;
- write_alarm(4,h);
- Write_add(0x80+5);
- }
- }
- }
- }
- if(k4==0) //k4按键按下
- {
- delay(5);
- if(k4==0)
- {
- while(!k4);
- if(buzz == 1)
- {
- if(k1num!=0)//保存并退出
- {
- k1num=0;
- Write_add(0x0c); //关闭光标
- TR0=1; //开始计时
- }
- else //开启或关闭闹钟
- {
- if(alarm_flag == 0)
- {
- alarm_flag = 1;
- write_OFF();
- }
- else
- {
- alarm_flag = 0;
- write_ON();
- }
- }
- }
- else
- {
- buzz = 1;//关闭蜂鸣器
- num = 0;//清空计数,方便下一次计数
- }
-
- }
- }
- }
- /******************************************
- 主函数
- *******************************************/
- void main(void)
- {
- LcdInitiate(); //调用LCD初始化函数
- while(1)
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
|
|