功能:實時時鐘+溫度計+鬧鐘+整點報時+正計時器+倒計時器+計數器
電路原理圖如下:
0.png (132.49 KB, 下載次數: 137)
下載附件
2017-5-18 17:12 上傳
多功能時鐘 元件清單
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個
0.png (44.45 KB, 下載次數: 124)
下載附件
2017-5-18 17:12 上傳
單片機源程序:
- #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, 下載次數: 309)
2017-5-18 14:12 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|