功能:实时时钟+温度计+闹钟+整点报时+正计时器+倒计时器+计数器
电路原理图如下:
多功能时钟 元件清单
1·一寸数码管 4个 2·单片机STC89C51RC 1个 3·DIP40芯片底座 1个 4·PCB电路板 1个 5·按键(带铁架) 3个 6·DS1302芯片 1个 7·DIP8芯片底座 1个 8·32.768K晶振 1个 10·蜂鸣器 1个 11·纽扣电池槽 1个 12·纽扣电池 1个 13·DC电源座 1个 14·三极管S8550 5个 15·12M晶振 1个 16·30P瓷片电容 2个 17·104(0.1UF)瓷片电容 1个 18·光敏电阻 1个 19·DS18B20温度传感器 1个 20·47电阻 8个 21·4.7K电阻 6个 22·10K电阻 1个 23·3P空心插针 1个 24·USB供电线 1个
单片机源程序:
- #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[10];//送显示断码 ℃
- 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=tab2[f/10]&0xbf; //显示小点//送显示断码
- else smg_data=tab2[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;
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
全部资料下载地址:
多功能时钟.rar
(171.7 KB, 下载次数: 302)
|