STC89C52单片机+DS1302+数码管显示时钟及按键时+整点报时功能
资料含有程序源代码+及仿真原理图
仿真软件运行和实际焊接电路运行都通过验证。
//注意事项://:仿真时请将程序char H=0,L=1,开发板下载试验请将变量char H=1 ,L=0;
//:请屏蔽此 DS1302初始化 //init_1302(); 函数。
void main()
{
t0_init();
t1_init();
//init_1302(); //仿真时如你需要显示当前实时系统时间,请屏蔽此函数。
while(1)
{
read_sf();
ExecuteKeyNum();
}
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
1》按下设置启动键:分钟闪烁进入分钟调时,再次按下小时闪烁进入小时调时
2》按下参数加或参数减按钮:进行小时后分钟的时间设置
注意:仿真时请将程序里WELA的变量H=0 L=1,开发板试验请将变量H=1 L=0;
单片机源程序如下:
- /*********************************************************************************
- 描述: 8位共阴数码管时钟,显示88-88-88样式,正常走时的时候,两个“-”0.5秒闪烁一次;
- 调时:按KEY1按键第1次分钟位闪烁,再按KEY2一次分钟加1,按KEY3一次分钟减1,长按连加连减;
- 按KEY1按键第2次小时位闪烁,再按KEY2一次小时加1,按KEY3一次小时减1,长按连加连减;
- 按KEY1按键第3次,秒从零开始累加,时钟回到正常走时;
- 对时的时候先调好时、分,分钟要比参考时间的分钟加1分,
- 再看参考时间的秒数到了59再按KEY1按键的第3次,这样对时可以很准的
- 仿真 实物都通过. 11.0592MHz晶振,STC89C52RC,两个74HC573锁存器做位选、段选
- **********************************************************************************/
- #include<reg52.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- sbit sclk = P2^4; //1302时钟端口
- sbit dio = P2^5; //1302数据端口
- sbit ce = P2^6;
- //1302使能
- sbit wela1 = P2^0; //位选
- sbit wela2 = P2^1; //位选
- sbit wela3 = P2^2;
- sbit wela4 = P2^3;
- sbit buzzer=P3^7;
- sbit KEY1=P3^0; //按键 设置/确认
- sbit KEY2=P3^1; //按键 加
- sbit KEY3=P3^2; //按键 减
- uchar snum,fnum;
- char shi,fen,miao,shi_alarm=6;
- uchar ss,mm;
- char H=0,L=1; //用软件仿真时关闭数码管H全部改为0,单片机下载H改为1.
- char FunctionKeyNum=0; //功能键键值
- char FuncTempNum=0; //功能键临时键值
- typedef enum KeyState{StateInit,StateAffirm,StateSingle,StateRepeat}; //键值状态值
- /***********写时DS1302地址************/
- #define write_year 0x8c //写年的地址
- #define write_moon 0x88 //写月的地址
- #define write_week 0x8a //写周的地址
- #define write_day 0x86 //写日的地址
- #define write_shi 0x84 //写时的地址
- #define write_fen 0x82 //写分的地址
- #define write_miao 0x80 //写秒的地址
- #define write_ram 0xc0 ////RAM的基地址
- /***********读时DS1302地址************/
- #define read_year 0x8d //读年的地址
- #define read_moon 0x89 //读月的地址
- #define read_week 0x8b //读周的地址
- #define read_day 0x87 //读日的地址
- #define read_shi 0x85 //读时的地址
- #define read_fen 0x83 //读分的地址
- #define read_miao 0x81 //读秒的地址
- #define read_ram 0xc1 //RAM的基地址
- // 0 1 2 3 4 5 6 7 8 9
- //uchar d[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共阴不带小数点
- //uchar d[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef}; // 共阴带小数点
- uchar d[]={0Xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //共阳极
- uchar dd[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10}; //共阳极带小数点
- void Time_alarm(); //整点报时子程序
- void delayms(uint z)
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=120;y>0;y--);
- }
- /*
- void buzzer1()
- {
- uint i;
- for(i=0;i<10;i++)
- {
- buzzer=0;
- delayms(500);
- buzzer=1;
- delayms(500);
- }
- }
- */
- void buzzer2() //发声子程序
- {
-
- uint t,tt;
- for(t=0;t<50;t++) //45为蜂鸣器发声频率
- {
- buzzer=!buzzer;
- for(tt=0;tt<50;tt++); //45为蜂鸣器发声频率
- }
- }
- void t0_init() //定时50ms一个中断
- {
-
- TMOD |= 0X01;
- TH0 = (65536-46080)/256;
- TL0 = (65536-46080)%256;
- EA = 1;
- ET0 = 1;
- TR0 = 1;
- }
- void t1_init()
- {
- TMOD |= 0x10;
- TH1 = 0x500;
- TL1 = 0x00;
- TR1 = 1;
- }
- void temer0() interrupt 1
- {
- TH0=(65536-46080)/256;
- TL0=(65536-46080)%256;
- ss++;
- mm++;
- if(ss==22)
- {
- ss=0;
- }
- if(mm==10)
- {
- mm=0;
- Time_alarm();
- }
- }
-
-
- void Display(uchar shi,uchar fen) //显示函数
- {
- if(FunctionKeyNum==0)
- {
- snum=30;
- fnum=30;
- }
-
- if(FunctionKeyNum==1)
- {
- fnum++;
- snum=30;
- }
-
- if(FunctionKeyNum==2)
- {
- snum++;
- fnum=30;
- }
-
- wela1=H; //关闭所有数码管
- wela2=H; //用软件仿真时关闭数码管H全部改为0,单片机下载H改为1.
- wela3=H; //用软件仿真时关闭数码管H全部改为0,单片机下载H改为1.
- wela4=H;
-
- if(snum>=30)
- {
- if((shi/10)<1) //如果小时十位小于1,
- {
- wela1=L; // 小时十位就不显示
- P0=d[0]; // 小时十位就显示"0"
- delayms(2);
- P0=0xff;
- wela1=H;
-
- }
-
- else
- {
- wela1=L;
- P0=d[shi/10];
- delayms(2);
- P0=0xff;
- wela1=H;
- }
-
- if(miao%2==0) //if(miao%2==0) 1秒闪烁1次
- // if(ss>=20) // 这里写为ss>=10,闪烁频率可调
- {
- wela2=L;
- P0=dd[shi%10];
- delayms(2);
- P0=0xff;
- wela2=H;
- }
-
- else
- {
- wela2=L;
- P0=d[shi%10];
- delayms(2);
- P0=0xff;
- wela2=H;
- }
- if(snum==60)
- snum=0;
- }
-
- // if(miao%2==0) //if(miao%2==0) 1秒闪烁1次
- if(ss>=20) // 这里写为ss>=10,闪烁频率可调
- {
- wela2=L;
- P0=d[shi%10];
- delayms(2);
- P0=0xff;
- wela2=H;
- }
-
- if(fnum>=30)
- {
- wela3=L;
- P0=d[fen/10];
- delayms(2);
- P0=0xff;
- wela3=H;
-
- wela4=L;
- P0=d[fen%10];
- delayms(2);
- P0=0xff;
- wela4=H;
-
-
- if(fnum==60)
- fnum=0;
- }
- }
- void write_1302(uchar add,dat) //写1302函数
- {
- uchar i,temp;
- temp=add;
- ce=0;
- _nop_();
- sclk=0;
- _nop_();
- ce=1;
- _nop_();
- for(i=0;i<8;i++)
- {
- sclk=0;
- _nop_();
- if((temp&0x01)==0x01)
- dio=1;
- else
- dio=0;
- temp>>=1;
- sclk=1;
- _nop_();
- }
- temp=dat;
- for(i=0;i<8;i++)
- {
- sclk=0;
- _nop_();
- if((temp&0x01)==0x01)
- dio=1;
- else
- dio=0;
- temp>>=1;
- sclk=1;
- _nop_();
- }
- ce=0;
- sclk=0;
- }
- uchar read_1302(uchar add) //读1302函数
- {
- uchar dat,dat1,i,temp;
- temp=add;
- ce=0;
- _nop_();
- sclk=0;
- _nop_();
- ce=1;
- for(i=0;i<8;i++)
- {
- sclk=0;
- _nop_();
- if((temp&0x01)==0x01)
- dio=1;
- else
- dio=0;
- temp>>=1;
- sclk=1;
- _nop_();
- }
- for(i=0;i<8;i++)
- {
- sclk=0;
- _nop_();
- if(dio)
- dat|=0x80;
- if(i<7)
- dat>>=1;
- sclk=1;
- }
- dat1=dat/16;
- dat=dat%16;
- dat=dat1*10+dat;
- ce=0;
- sclk=0;
- return dat;
- }
- void init_1302() //初始化函数 设置时间
- {
- write_1302(0x8e,0x00); //保护取消,可以进行写操作
- write_1302(write_year,0x20);
- write_1302(write_moon,0x12); //写入时修改月
- write_1302(write_week,0x30); //写入时修改星期
- write_1302(write_day,0x04); //写时修改日期
- write_1302(write_miao,0x00);
- write_1302(write_fen,0x30);
- write_1302(write_shi,0x10);
- write_1302(0x8e,0x80); //保护启动,不能进行写操作
- }
- void read_sf()
- {
- shi=read_1302(read_shi);
- fen=read_1302(read_fen);
- miao=read_1302(read_miao);
- Display(shi,fen);
- }
- void KeyScan(void)
- {
- static uchar KeyStateTemp1 = 0; //按键状态临时存储值1
- static uchar KeyStateTemp2 = 0; //按键状态临时存储值2
- static uchar KeyStateTemp3 = 0; //按键状态临时存储值3
- static uchar KeyTime = 0; //按键延时时间
- bit KeyPressTemp1; //按键是否按下存储值1
- bit KeyPressTemp2; //按键是否按下存储值2
- bit KeyPressTemp3; //按键是否按下存储值3
- KeyPressTemp1 = KEY1; //读取IO口的键值
- switch(KeyStateTemp1)
- {
- case StateInit:
- if(!KeyPressTemp1) //KEY1按下
- KeyStateTemp1 = StateAffirm; //按键状态切换到确认态
- break;
- case StateAffirm: //确认状态
- if(!KeyPressTemp1) //按键还在按下
- {
- KeyTime = 0;
- KeyStateTemp1 = StateSingle; //按键状态切换到单击状态
- }
- else KeyStateTemp1 = StateInit; //否则按键抬起,回到初始态
- break;
-
- case StateSingle: //单击
- if(KeyPressTemp1)
- {
- KeyStateTemp1 = StateInit; //按键释放
- FuncTempNum++; //键值加1
- if(FuncTempNum>3)
- FuncTempNum = 0;
- }
- else if(++KeyTime>100)
- {
- KeyPressTemp1 = StateRepeat;
- KeyTime = 0;
- }
- break;
-
- case StateRepeat: //连发
- if(KeyPressTemp1)
- KeyStateTemp1 = StateInit;
- else
- {
- if(++KeyTime > 10)
- {
- KeyTime = 0;
- FuncTempNum++;
- if(FuncTempNum>3)
- FuncTempNum = 0;
- }
- break;
- }
- break;
-
- default :KeyStateTemp1 = KeyStateTemp1 = StateInit; break;
-
- }
- if(FuncTempNum) //只有功能键被按下后,增加和减小键才有效
- {
- KeyPressTemp2 = KEY2; //读取I/O口的键值
- switch(KeyStateTemp2)
- {
- case StateInit: //按键初始状态
- if(!KeyPressTemp2) //当按键按下,状态切换到确认态
- KeyStateTemp2 = StateAffirm;
- break;
- case StateAffirm: //按键确认态
- if(!KeyPressTemp2)
- {
- KeyTime = 0;
- KeyStateTemp2 = StateSingle;//切换到单次触发态
- }
- else KeyStateTemp2 = StateInit; //按键已抬起,切换到初始态
- break;
- case StateSingle: //按键单发态
- if(KeyPressTemp2) //按下时间小于1s
- {
- KeyStateTemp2 = StateInit; //按键释放,则回到初始态
- if(FunctionKeyNum == 1) //若功能键第一次按下
- {
- fen++;
- fen=fen/10*16+fen%10; //转为16进制
- if(fen==0x60)
- fen=0x00;
- write_1302(write_fen,fen); //写入1302
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
所有资料51hei附件下载:
STC89C52单片机+DS1302+数码管显示及按键调时的时钟程序.7z
(72.88 KB, 下载次数: 58)
|