我修改一下,在Professional试过能用。
/* 项目名称:多功能数码管时钟设计
调试要求:
1.MCU:STC89C51
2.晶振:12MHz
功能:实时时钟+温度计+闹钟+整点报时+正计时器+倒计时器+计数器*/
- #include <reg52.h>
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define smg_data P0//定义数码管数据
- sbit smg1=P2^4;//位码1声明 时
- sbit smg2=P2^5;//位码2声明
- sbit smg3=P2^6;//位码3声明 分
- sbit smg4=P2^7;//位码4声明
- sbit smg5=P1^6;//位码5声明 秒
- sbit smg6=P1^7;//位码6声明
- sbit gm=P1^3; //黑暗时等于1
- sbit k1=P1^2; //按键k1的声明
- sbit k2=P1^1; //按键k2的声明
- sbit k3=P1^0; //按键k3的声明
- sbit bell=P3^7; //蜂鸣器声明
- sbit clk_ds1302=P2^0;//定义控制DS1302的时钟线
- sbit io_ds1302=P2^1;//定义控制DS1302的串行数据
- sbit rest_ds1302=P2^2;
- const uchar tab1[16]={//共阳数码管段码表
- 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x86,0x87,0xFF,0xc6,0xbf,0xff};
- //0 ,1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,
- const uchar tab2[16]={//数码管3特殊处理用的段码表
- 0xc0,0xf9,0x64,0x70,0x59,0x52,0x42,0xf8,0x40,0x50,0x86,0x87,0xFF,0xc6,0x7f,0xff};
- // C -
- bit gm_en=0,zdbs_en=0;//光敏使能信号/整点报时使能信号
- uchar gm_time=40; //光敏控制亮度值
- char shi,fen,miao,b_shi=7,b_fen=0; //必须是有符号型:数据暂存单元shi/fen/miao,闹铃时间b_shi,b_fen,
- uchar hour,minute,second,n=0,a=0,b=0;//从1302读出的实时时间数据hour,minute,second, b控制字符闪烁
- uchar tab23[3];//={0x40,0x59,0x23,0x28,0x11,0x06,0x09};//首次上电时默认的时间
- uchar bell_en=0,x=1;//闹钟使能信号,任意键关闭铃声标志位
- char zjs_en=0,zjs_shi=0,zjs_fen=0,djs_en=0,djs_shi=60,djs_fen=0,jsq_shi=0,jsq_fen=0;
- void key();
- void delay_3us();//3US的延时程序
- void delay_50us(uint t);//延时50*T微妙函数的声明
- void display(uchar shi,fen,miao);//显示子程序
- void set_ds1302();//设置时间
- void get_ds1302();//读取当前时间
- void w_1byte_ds1302(uchar t);//向DS1302写一个字节的数据
- uchar r_1byte_ds1302();//从DS1302读一个字节的数据
- void init(); //初始化函数
- void baojing()//报警函数
- {
- uint j=10,i=10;
- bell=0;
- while(i--)display(shi,fen,miao);
- bell=1;
- while(j--)display(shi,fen,miao);
- }
- /******温度传感器18b20 IO引脚定义********/
- sbit DS=P2^3; //定义DS18B20接口
- uchar ly_dis[4]; //定义显示温度的缓冲区
- float tt; //定义浮点型变量tt存放温度值
- uchar temp_en=0;
- uchar wendu=0;
- uint t=0;
- /**********18b20延时子函数 *************/
- void delayb(uint count)
- {
- uint i;
- while(count)
- {
- i=200;
- while(i>0)
- i--;
- count--;
- }
- }
- /*********DS18B20初始化************/
- void dsreset(void)
- {
- uint i;
- DS=0;
- i=103;
- while(i>0)i--;
- DS=1;
- i=4;
- while(i>0)i--;
- }
- /**********18b20读一位***********/
- bit tmpreadbit(void)
- {
- uint i;
- bit dat;
- DS=0;
- i++; //小延时一下
- DS=1;
- i++;i++;
- dat=DS;
- i=8;
- while(i>0)i--;
- return (dat);
- }
- /**********18b20读一个**********/
- uchar tmpread(void)
- {
- uchar i,j,dat;
- dat=0;
- for(i=1;i<=8;i++)
- {
- j=tmpreadbit();
- dat=(j<<7)|(dat>>1); //读出的数据最低位在最前面,这样刚好//一个字节在DAT里
- }
- return(dat); //将一个字节数据返回
- }
- /**********18b20写一个字节**********/
- void tmpwritebyte(uchar dat)
- {
- uint i;
- uchar j;
- bit testb;
- for(j=1;j<=8;j++)
- {
- testb=dat&0x01;
- dat=dat>>1;
- if(testb) // 写1部分
- {
- DS=0;
- i++;i++;
- DS=1;
- i=8;
- while(i>0)i--;
- }
- else
- {
- DS=0; //写0部分
- i=8;
- while(i>0)i--;
- DS=1;
- i++;i++;
- }
- }
- }
- /***********18b20发送温度转换命令*************/
- void tmpchange(void)
- {
- dsreset(); //初始化DS18B20
- delayb(1); //延时
- tmpwritebyte(0xcc); // 跳过序列号命令
- tmpwritebyte(0x44); //发送温度转换命令
- }
- /***********获得温度************/
- int tmp()
- {
- int temp;
- uchar a,b;
- dsreset();
- delayb(1);
- tmpwritebyte(0xcc);
- tmpwritebyte(0xbe); //发送读取数据命令
- a=tmpread(); //连续读两个字节数据
- b=tmpread();
- temp=b;
- temp<<=8;
- temp=temp|a; //两字节合成一个整型变量。
- return temp; //返回温度值
- }
- void dis_temp()
- {
- tmpchange(); //温度转换
- tt=tmp()*0.0625; //得到真实十进制温度值,因为DS18B20
- wendu=tt; //可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度。
- if(tt<0) //判断第一位显示整数还是负号
- tt=0;
- if((wendu%100/10)<1) //如果温度小于10,不显示十位
- smg1=1;
- else
- {
- smg_data=tab1[wendu%100/10];//送显示断码 十位
- smg1=0;
- delay_50us(gm_time);
- smg1=1;
- }
- smg_data=tab1[wendu%10];//送显示断码 个位
- smg2=0;
- delay_50us(gm_time);
- smg2=1;
- smg_data=tab1[13];//送显示断码 ℃
- smg3=0;
- delay_50us(gm_time);
- smg3=1;
- smg4=1;
- }
- //***********************************************************************
- //主程序
- void main()
- {
- tmpchange(); //温度转换,为了消除首次显示的85,每次提前转换一次即可解决
- init();
- gm=1;
- while(1)
- {
- if(n==0&&temp_en==1)
- dis_temp();//每15秒切换显示温度一次
- else
- {
- get_ds1302();
- display(shi,fen,miao);
- key();
- if(n==0&&x==1&&bell_en==1&&b_shi==hour&&b_fen==minute)
- baojing();
- if(hour==b_shi&&minute==b_fen+1)x=1;
- }
- if(gm_en==1)//光敏控制亮度开关
- {
- if(gm==1)
- gm_time=1;
- else gm_time=40;
- }
- else gm_time=40;
- if(zdbs_en==1&&n==0&&minute==0&&miao==0)//整点报时开关
- baojing();
- }
- }
- //数码管显示程序
- void display(uchar s,f,m)
- {
- if((s/10)<1) smg1=1;
- else
- {
- smg_data=tab1[s/10];//送显示断码 时
- if((n==1||n==3)&&a<5)
- smg1=1;//锁存数据
- else smg1=0;
- delay_50us(gm_time);
- smg1=1;
- }
- if((n==1||n==3)&&a<5) smg_data=0x7f; //字符闪烁,小点不闪
- else if(b>=10) smg_data=tab1[s%10]-0x80;//小点闪烁,字符不闪
- else smg_data=tab1[s%10];//送显示断码
- smg2=0;
- delay_50us(gm_time);
- smg2=1;
- if((n==2||n==4)&&a<5) smg_data=0xbf;//b是控制小数点闪烁的,需要闪烁的时候他等于a
- else if(b>=10) smg_data=tab1[f/10]; //显示小点//送显示断码
- else smg_data=tab1[f/10];//送显示断码 分
- smg3=0;//锁存数据
- delay_50us(gm_time);
- smg3=1;
- if(bell_en==1) smg_data=tab1[f%10]-0x80;//送显示断码
- else smg_data=tab1[f%10];//送显示断码
- if((n==2||n==4)&&a<5)
- smg4=1;//锁存数据
- else smg4=0;
- delay_50us(gm_time);
- smg4=1;
- /**************秒,不需要显示********************/
- smg_data=tab2[m/10];//送显示断码 秒
- smg5=0;//锁存数据
- delay_50us(40);
- smg5=1;
- smg_data=tab1[m%10];//送显示断码
- smg6=0;//锁存数据
- delay_50us(40);
- smg6=1;
- /*********************************************/
- }
- void key() //按键控制函数
- {
- if(k2==0&&k3==0) //k2k3同时按下,切换闹铃开关 并且在按下之后查看闹钟时间松手后恢复时间显示
- {
- delay_50us(1);
- if(k2==0&&k3==0)
- {
- shi=b_shi;
- fen=b_fen;
- bell_en=!bell_en;
- baojing();
- baojing();
- while(k2==0&&k3==0)display(shi,fen,miao);//等待松手
- shi=hour;
- fen=minute;
- }
- }
-
- if(k1==0&&k3==0) //k1k3同时按下,切换闹铃开关 并且在按下之后查看闹钟时间松手后恢复时间显示
- {
- delay_50us(1);
- if(k1==0&&k3==0)
- {
- gm_en=!gm_en;
- if(gm_en==1)//使能的话报警两声
- {baojing();baojing();}
- else baojing();//无效的话报警一声
- while(k1==0&&k3==0)display(shi,fen,miao);//等待松手
- }
- }
- if(k1==0&&k2==0) //k1k2同时按下,切换整点报时开关
- {
- delay_50us(1);
- if(k1==0&&k2==0)
- {
- zdbs_en=!zdbs_en;
- if(zdbs_en==1)//使能的话报警两声
- {baojing();baojing();}
- else baojing();//无效的话报警一声
- while(k1==0&&k2==0)display(shi,fen,miao);//等待松手
- }
- }
- if(n==0&&(k2==0||k3==0)&&bell_en==1&&b_shi==hour&&b_fen==minute&&x==1)
- { //功能键k1被按下
- delay_50us(1);//消抖延时
- if(n==0&&(k2==0||k3==0)&&bell_en==1&&b_shi==hour&&b_fen==minute&&x==1)
- {
- x=0; //如果处于响零状态,就任意键关闭响铃
- while(k1==0)display(shi,fen,miao);//等待松手
- }
- }
- if(k1==0)
- { //功能键k1被按下
- delay_50us(1);//消抖延时
- if(k1==0)
- {
- uint i=0;
- while(k1==0)
- {
- display(shi,fen,miao);//等待松手
- i++;
- if(i>(2*(70-gm_time))){n=0;baojing();baojing();break;}//长按K1退出
- }
- if(bell_en==1&&b_shi==hour&&b_fen==minute&&x==1)x=0; //如果处于响零状态,就任意键关闭响铃
- else if(i<=(2*(70-gm_time)))
- {
- n++;//n记录功能键状态
- if(n>7) n=0; //n清零
- baojing();
- }
- i=0;
- }
- }
- if(n==0)//状态0,正常显示时间
- {
- b=a; //b是控制小数点闪烁的
- shi=hour;
- fen=minute;
- miao=second;
- }
- if(n==1)//状态1:调节时间的“时”
- {
- b=10;
- if(k2==0)
- { //k2被按下
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k2==0)
- {
- shi++;//小时加一
- if(shi==24)
- shi=0;//达到24清零
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
-
- if(k3==0)
- { //k3被按下
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k3==0)
- {
- shi--; //小时减一
- if(shi<0)
- shi=23;//小于0,重新复制
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
- }
- if(n==2)//状态2:调节时间的“分”
- { b=10;
- if(k2==0)
- { //k2被按下
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k2==0)
- {
- fen++;//分加一
- if(fen==60)
- fen=0;//分到达60 分清零
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
-
- if(k3==0)
- { //k3被按下
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k3==0)
- {
- fen--;//分减一
- if(fen<0)
- fen=59;//分小于0,分重新赋值59
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
- tab23[2]=shi/10*16+shi%10;
- tab23[1]=fen/10*16+fen%10;
- hour=shi;
- minute=fen;
- second=0;
- tab23[0]=0;
- set_ds1302();//设置DS1302的初始时间
- }
-
- if(n==3)//状态三:调节闹铃“时”
- {
- shi=b_shi;
- fen=b_fen;
- b=10;
- if(k2==0)
- { //k2被按下
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k2==0)
- {
- b_shi++;//闹铃时间加一
- if(b_shi==24)
- b_shi=0;//闹铃时间清零
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
-
- if(k3==0)
- { //k3被按下
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k3==0)
- {
- b_shi--;//闹铃时间减一
- if(b_shi<0)
- b_shi=23;//闹铃时间
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
- }
- if(n==4)//状态四 :调节闹铃的”分“
- { b=10;
- shi=b_shi;
- fen=b_fen;
- if(k2==0)
- { //k2被按下
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k2==0)
- {
- b_fen++;//闹铃时间分加一
- if(b_fen==60)
- b_fen=0;//闹铃分到达60 清零
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
-
- if(k3==0)
- { //k3被按下
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k3==0)
- {
- b_fen--;//闹铃时间分减一
- if(b_fen<0)
- b_fen=59;//闹铃时间分重新赋值
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
- }
- if(n==5)//状态5 :正计时
- {
- b=10; //显示小点
- shi=zjs_shi;
- fen=zjs_fen;
- if(k2==0)
- { //k2被按下
- delay_50us(1);//消抖延时
- if(k2==0)
- {
- zjs_en=!zjs_en;
- baojing();
- while(k2==0)display(shi,fen,miao);//等待松手
- }
- }
-
- if(k3==0)
- { //k3被按下
- delay_50us(1);//消抖延时
- if(k3==0)
- {
- zjs_shi=0;
- zjs_fen=0;
- baojing();
- while(k3==0)display(shi,fen,miao);//等待松手
- }
- }
- }
- if(n==6)//状态5 :倒计时
- { b=10; //显示小点
- shi=djs_shi;
- fen=djs_fen;
- if(k2==0)
- { //k2被按下
- delay_50us(1);//消抖延时
- if(k2==0)
- {
- djs_en=!djs_en;
- baojing();
- while(k2==0)display(shi,fen,miao);//等待松手
- }
- }
-
- if(k3==0&&djs_en==0)
- { //k3被按下
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k3==0)
- {
- djs_shi--;
- if(djs_shi<0)
- djs_shi=60;
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
- if(k3==0&&djs_en==1)
- { //k3被按下
- delay_50us(1);//消抖延时
- if(k3==0)
- {
- djs_shi=60;
- djs_fen=0;
- baojing();
- while(k3==0)display(shi,fen,miao);//等待松手
- }
- }
- }
- if(n==7)//状态5 :计数器
- {
- b=1; //不显示小点
- shi=jsq_shi;
- fen=jsq_fen;
-
- if(k2==0)
- {
- uint i=6,j=10;
- while(i--)display(shi,fen,miao);//长按连续递减
- if(k2==0)
- {
- jsq_fen++;
- if(jsq_fen>99)
- {
- jsq_fen=0;
- jsq_shi++;
- if(jsq_shi>99)
- jsq_shi=0;
- }
- }
- while(j--)display(shi,fen,miao);//长按连续递减
- }
- if(k3==0)
- { //k3被按下
- delay_50us(1);//消抖延时
- if(k3==0)
- {
- jsq_shi=0;
- jsq_fen=0;
- baojing();
- while(k3==0)display(shi,fen,miao);//等待松手
- }
- }
- }
- }
- void init() //初始化函数
- {
- IE=0X82;//1000 0010
- TMOD=0X01; //0000 0001选择定时器0的工作方式1 选择定时器1的工作方式1
- TH0=(65536-50000)/256;//初值15536定时50mS
- TL0=(65536-50000)%256;
- TR0=1; //开启定时器0
- }
- void timer0() interrupt 1 //定时器0中断服务程序,用来设置冒号闪烁频率
- {
- TH0=(65536-50000)/256;//进入中断重新赋初值15536
- TL0=(65536-50000)%256;//计数5万次(50毫秒)
- a++; //标志位b,用来确定光标闪烁频率
- t++;
- if(t==300)t=0;
- if(t>260)temp_en=1;
- else temp_en=0;
-
- if(a==20)
- {
- a=0;//a=20 时被清零
- if(zjs_en==1) //正计时
- {
- zjs_fen++;
- if(zjs_fen==60)
- {
- zjs_fen=0;
- zjs_shi++;
- if(zjs_shi==60)
- {
- zjs_shi=0;
- }
- }
- }
- /**********倒计时**********/
- if(djs_en==1)
- {
- djs_fen--;
- if(djs_fen==-1)
- {
- djs_fen=59;
- djs_shi--;
- if(djs_shi==-1)
- {
- djs_shi=0;
- djs_fen=0;
- djs_en=0;//关闭倒计时
- baojing();
- baojing();
- baojing();
- }
- }
- }
- /*************************/
- }
- }
- //函数名称:void delay_50US(unsigned int t)
- //功能: 延时50*t(us)
- void delay_50us(uint t)
- {
- unsigned char j;
- for(;t>0;t--)
- {
- for(j=19;j>0;j--);
- }
- }
- //*******************************************************************************
- //*******************************************************************************
- //3微秒延时程序
- void delay_3us()
- {
- ;
- ;
- }
- //;##############################################################################
- //;子程序名:w_1byte_ds1302
- //;功能: 向DS1302写一个字节的数据
- void w_1byte_ds1302(uchar t)
- {
- uchar i;
- for(i=0;i<8;i++)
- {
- if(t & 0x01)
- {io_ds1302=1;}
- else
- {io_ds1302=0;}
- clk_ds1302=1;
- delay_3us();
- delay_3us();
- clk_ds1302=0;
- delay_3us();
- delay_3us();
- t>>=1;
- }
- }
- //;########################################################################
- //;子程序名:r_1byte_ds1302()
- //;功能: 从DS1302读一个字节的数据
- uchar r_1byte_ds1302()
- {
- uchar i,temp11=0;
- io_ds1302=1;//置IO为1,准备读入数据
- for(i=0;i<8;i++)
- {
- temp11>>=1;
- if(io_ds1302) temp11 |= 0x80;
- clk_ds1302=1;
- delay_3us();
- delay_3us();
- clk_ds1302=0;
- delay_3us();
- }
- return(temp11);
- }
- //;#################################################################################
- //;子程序名:setbds1302
- //;功能: 设置DS1302初始时间,并启动计时
- void set_ds1302()
- {
- uchar i,j;
- rest_ds1302=0;
- delay_3us();
- clk_ds1302=0;
- delay_3us();
- rest_ds1302=1;
- delay_3us();
- w_1byte_ds1302(0x8e);//写控制命令字
- delay_3us();
- w_1byte_ds1302(0x00);//写保护关闭
- clk_ds1302=1;
- delay_3us();
- rest_ds1302=0;
- for(i=0,j=0x80;i<7;i++,j+=2)
- {
- rest_ds1302=0;
- delay_3us();
- clk_ds1302=0;
- delay_3us();
- rest_ds1302=1;
- delay_3us();
- w_1byte_ds1302(j);
- delay_3us();
- w_1byte_ds1302(tab23[i]);
- delay_3us();
- delay_3us();
- clk_ds1302=1;
- delay_3us();
- rest_ds1302=0;
- delay_3us();
- delay_3us();
- }
- rest_ds1302=0;
- delay_3us();
- clk_ds1302=0;
- delay_3us();
- rest_ds1302=1;
- delay_3us();
- w_1byte_ds1302(0x8e);
- delay_3us();
- w_1byte_ds1302(0x80);
- clk_ds1302=1;
- delay_3us();
- rest_ds1302=0;
- delay_3us();
- }
- //;#################################################################-------
- //;子程序名:get1302
- void get_ds1302()
- { uchar hour_count,minute_count,second_count;
- uchar temp11[7],i,j;
- for(i=0;i<7;i++)
- {temp11[i]=0;}
- for(i=0,j=0x81;i<7;i++,j+=2)
- {
- rest_ds1302=0;
- delay_3us();
- clk_ds1302=0;
- delay_3us();
- rest_ds1302=1;
- delay_3us();
- w_1byte_ds1302(j);
- temp11[i]=r_1byte_ds1302();
- delay_3us();
- clk_ds1302=1;
- delay_3us();
- rest_ds1302=0;
- delay_3us();
- }
- if(temp11[0]!=0xff)
- {second_count=temp11[0];}
- if(temp11[1]!=0xff)// 数据验证
- {minute_count=temp11[1];}
- if(temp11[2]!=0xff)//数据验证
- {hour_count=temp11[2];}
- hour=hour_count/16*10+hour_count%16;
- minute=minute_count/16*10+minute_count%16;
- second=second_count/16*10+second_count%16;
- /*zancun4=hour_count&0xf0;
- zancun4>>=4;
- zancun5=minute_count&0xf0;
- zancun5>>=4;
- zancun6=second_count&0xf0;
- zancun6>>=4;*/
- }
复制代码 |