仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- /*基于51单片机设计定时器闹钟 小老弟~*/
- #include "reg51.h" //定义头文件
- #define uchar unsigned char
- #define uint unsigned int
- #define LED P0 //定义数码管段选(数据)管脚
- sbit LSA=P2^0; //定义24译码器管脚,进行位选
- sbit LSB=P2^1;
- sbit k1=P2^2; //定义按键管脚
- sbit k2=P2^3;
- sbit k3=P2^4;
- sbit k4=P2^5;
- sbit beep=P2^6; //蜂鸣器管脚
- uchar s,sec,h; //定义计数变量对应分别为秒、分、时
- char pre_s=0,pre_sec=0,pre_h=8; //定义报警时间变量,对应分别为秒、分、时
- bit state,h_sec; //状态变量,state=1为进入闹铃时间设置,h_sec为时分选择设置
- uchar disp[4]; //数码管显示数组
- uchar pre_time[4]; //设定闹铃时间显示数组
- uchar code smgduan[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //段码表
- void delay_ms(uint t) //延时函数
- {
- uchar i;
- for(;t>0;t--)
- {
- for(i=0;i<125;i++);
- }
- }
- void T0Init() //定时器T0初始化
- {
- TMOD=0x01;
- TH0=(65536-1000)/256;
- TL0=(65536-1000)%256;
- EA=1;
- ET0=1;
- TR0=1;
- }
- void time_pro() //计数时间处理函数
- {
- disp[0]=smgduan[sec%10]; //分的个位
- disp[1]=smgduan[sec/10]; //分的十位
- disp[2]=smgduan[h%10]; //时的个位
- disp[3]=smgduan[h/10]; //时的十位
- }
- void pretime_pro()
- {
- pre_time[0]=smgduan[pre_sec%10]; //定时分的个位
- pre_time[1]=smgduan[pre_sec/10]; //定时分的十位
- pre_time[2]=smgduan[pre_h%10]; //定时时的个位
- pre_time[3]=smgduan[pre_h/10]; //定时时的十位
- }
- void digdisp() //计数时间显示
- {
- uchar i;
- for(i=0;i<4;i++)
- {
- switch(i)
- {
- case(0):
- LSA=0;LSB=0;break; //位选
- case(1):
- LSA=1;LSB=0;break;
- case(2):
- LSA=0;LSB=1;break;
- case(3):
- LSA=1;LSB=1;break;
- }
- LED=disp[i]; //对应位的显示
- delay_ms(1);
- LED=0xff; //消隐
- }
- }
- void digdisp_pre() //定时时间显示
- {
- uchar i;
- for(i=0;i<4;i++)
- {
- switch(i)
- {
- case(0):
- LSA=0;LSB=0;break; //位选
- case(1):
- LSA=1;LSB=0;break;
- case(2):
- LSA=0;LSB=1;break;
- case(3):
- LSA=1;LSB=1;break;
- }
- LED=pre_time[i]; //对应位的显示
- delay_ms(1);
- LED=0xff; //消隐
- }
- }
- void key_pro() //按键处理函数
- {
- if(k1==0)
- {
- delay_ms(1); //消抖
- if(k1==0)
- {
- state=~state; //改变状态state,state=1进入定时时间设置
- while(!k1); //松手检测
- }
- }
- if((k2==0)&&(state==1))
- {
- delay_ms(1); //消抖
- if((k2==0)&&(state==1))
- {
- h_sec=~h_sec; //改变状态h_sec,h_sec=1设置分,h_sec=0设置时
- while(!k2); //松手检测
- }
- }
- if((k3==0)&&(state==1)) //加一
- {
- delay_ms(1); //消抖
- if((k3==0)&&(state==1))
- {
- if(h_sec==0)
- {
- pre_h++; //定时时加一
- if(pre_h==24)
- {
- pre_h=0;
- }
- }
- else
- {
- pre_sec++; //定时分加一
- if(pre_sec==60)
- {
- pre_sec=0;
- }
- }
- while(!k3); //松手检测
- }
- }
- if((k4==0)&&(state==1)) //减一
- {
- delay_ms(1);
- if((k4==0)&&(state==1))
- {
- if(h_sec==0)
- {
- pre_h--; //定时时减一
- if(pre_h<0)
- {
- pre_h=23;
- }
- }
- else
- {
- pre_sec--; //定时分减一
- if(pre_sec<0)
- {
- pre_sec=59;
- }
- }
- while(!k4); //松手检测
- }
- }
- }
- void sound() //蜂鸣器报警函数
- {
- uchar i;
- for(i=0;i<10;i++)
- {
- beep=~beep;
- delay_ms(1);
- }
- }
- void main()
- { //T0初始化
- T0Init();
- while(1)
- {
- key_pro(); //按键检测
- if(state==0) //如果state为0,数码管显示计数时间
- {
- time_pro();
- digdisp();
- if((pre_sec==sec)&&(pre_h==h)&&(s-pre_s<10)) //计数时间到定时时间发出报警声,持续10s
- {
- sound();
- }
- }
- else //如果state=0,进入定时时间设置,数码管显示当前设置时间
- {
- pretime_pro();
- digdisp_pre();
- }
- }
- }
- void time0() interrupt 1 //定时器T0中断处理函数
- {
- static int n; //定义局部静态变量
- TH0=(65536-1000)/256; //赋初值
- TL0=(65536-1000)%256;
- n++; //进入一次中断n+1
- if(n==1000) //当n=1000时,满足1s
- {
- n=0;
- s++; //秒加1
- if(s==60)
- {
- s=0;
- sec++; //秒满60,分加1
- if(sec==60)
- {
- sec=0; //分满60,时加1
- h++;
- if(h==24)
- {
- h=0;
- }
- }
- }
- }
- }
复制代码
所有资料51hei提供下载:
定时器闹钟(带仿真).zip
(67.7 KB, 下载次数: 110)
|