采用stc15單片機做的主控芯片,僅供參考
制作出來的ds3132時鐘實物圖:
正面.JPG (201.1 KB, 下載次數: 115)
下載附件
2017-12-18 22:21 上傳
背面.JPG (371.14 KB, 下載次數: 101)
下載附件
2017-12-18 22:21 上傳
電路原理圖:
QQ圖片20171218183531.png (52.38 KB, 下載次數: 115)
下載附件
2017-12-18 18:51 上傳
pcb文件:工程文件可到本帖附件中下載
QQ圖片20171218183907.png (32.14 KB, 下載次數: 104)
下載附件
2017-12-18 18:51 上傳
51單片機源程序如下:
- //#include <reg52.h>
- #include "stc15f104w.h"
- #include "I2C.h"
- #include "Led_can.h"
-
- typedef unsigned int u16; //16位無符號整型數
- typedef unsigned char u8; //8位無符號整型數
- #define E2PROM_WriteAddress 0xAE //器件寫地址
- #define DS3231_WriteAddress 0xD0 //器件寫地址
- #define DS3231_ReadAddress 0xD1 //器件讀地址
- #define DS3231_SECOND 0x00 //秒
- #define DS3231_MINUTE 0x01 //分
- #define DS3231_HOUR 0x02 //時
- #define DS3231_WEEK 0x03 //星期
- #define DS3231_DAY 0x04 //日
- #define DS3231_MONTH 0x05 //月
- #define DS3231_YEAR 0x06 //年
- //鬧鈴1
- //#define DS3231_SALARM1ECOND 0x07 //秒
- //#define DS3231_ALARM1MINUTE 0x08 //分
- //#define DS3231_ALARM1HOUR 0x09 //時
- //#define DS3231_ALARM1WEEK 0x0A //星期/日
- //鬧鈴2
- //#define DS3231_ALARM2MINUTE 0x0b //分
- //#define DS3231_ALARM2HOUR 0x0c //時
- //#define DS3231_ALARM2WEEK 0x0d //星期/日
- #define DS3231_CONTROL 0x0e //控制寄存器
- #define DS3231_STATUS 0x0f //狀態寄存器
- #define BSY 2 //忙
- #define OSF 7 //振蕩器停止標志
- #define DS3231_XTAL 0x10 //晶體老化寄存器
- #define DS3231_TEMPERATUREH 0x11 //溫度寄存器高字節(8位)
- #define DS3231_TEMPERATUREL 0x12 //溫度寄存器低字節(高2位)
- sbit BP = P1^5; //秒數碼管驅動
- sbit KEY1 = P1^5; //按鍵輸入引腳
- u8 Time[18]; //時鐘數值緩沖區
- bit BiaoJi=0; //讀實時時鐘標記
- bit BianJi_c=0; //長按鍵標記
- bit BianJi_d=0; //短按鍵標記
- u8 BianJi=0; //編輯模式標記
- u8 L_u[4]={2,3,4,5};//數碼管顯示第幾時鐘緩沖區
- u8 ling=0; //數碼管首位是否顯示零標記
- bit WenDu = 0; //溫度轉換標記
- void ConfigTimer0(u8 ms); //配置并啟動T0,ms-T0定時時間
- void write_byte(u8 addr, u8 write_data);//DS3231_寫一個字節數據到時鐘芯片
- u8 read_byte(u8 random_addr); //DS3231_讀一個字節數據到時鐘芯片
- void write_byte_E2( u8 write_data); //E2PROM-寫一個字節數據到時鐘芯片
- u8 read_byte_E2(); //E2PROM-讀一個字節數據到時鐘芯片
- u8 BCD2HEX(u8 val); //BCD轉換為Byte
- u8 HEX2BCD(u8 val); //B碼轉換為BCD碼
- void anjian(); //按鈕掃描 需在定時中斷中調用
- void Anjian_d(u8 addr, u8 map); //短按鍵處理—子程序
- void main()
- {
- u8 map;
- u16 wend;
-
- EA = 1; //開總中斷
- Led_cu(); //數碼管初始化
- ConfigTimer0(5); //配置T0定時
- ling=read_byte_E2(); //E2PROM讀出數據—數碼管首位是否顯示零標記
- //初始化實時時鐘,小時采用24小時制
- write_byte(DS3231_CONTROL, 0x1C); //控制寄存器 DS3231_CONTROL
- write_byte(DS3231_STATUS, 0x00); //狀態寄存器 DS3231_STATUS
- //write_byte(DS3231_SECOND,HEX2BCD(30)); //修改秒
- //write_byte(DS3231_MINUTE,HEX2BCD(30)); //修改分
- //write_byte(DS3231_HOUR,HEX2BCD(16)); //修改時
- //write_byte(DS3231_DAY,HEX2BCD(1)); //修改日
- //write_byte(DS3231_MONTH,HEX2BCD(12)); //修改月
- //write_byte(DS3231_YEAR,HEX2BCD(17)); //修改年
-
- while(1)
- { //讀取時鐘芯片并寫進數碼管顯示緩沖區======================
- if(BiaoJi == 1)
- { BiaoJi = 0;
-
- map=read_byte(DS3231_SECOND); //讀秒
- map=BCD2HEX(map);
- Time[0]=map%10;
- Time[1]=map/10%10;
- map=read_byte(DS3231_MINUTE); //讀分
- map=BCD2HEX(map);
- Time[2]=map%10;
- Time[3]=map/10%10;
- map=read_byte(DS3231_HOUR)&0x3f; //讀小時 24小時制
- map=BCD2HEX(map);
- Time[4]=map%10 ;
- Time[5]=map/10%10 ;
-
- //map=read_byte(DS3231_WEEK ); //讀星期
- //Time[6]=map
- //map=read_byte(DS3231_DAY); //讀日
- //map=BCD2HEX(map);
- //Time[8]=map%10
- //Time[9]=map/10%10
- //map=read_byte(DS3231_MONTH); //讀月
- //map=BCD2HEX(map);
- //Time[10]=map%10
- //Time[11]=map/10%10
- //map=read_byte(DS3231_YEAR); //讀年
- //map=BCD2HEX(map);
- //Time[12]=map%10
- //Time[13]=map/10%10
-
- if((ling==0) && (Time[L_u[3]]==0)) //判斷數碼管首位零是否顯示
- Led_buff[3] = 0xff;
- else
- Led_buff[3] = Led_Char[ Time[L_u[3]]];
- Led_buff[2] = Led_Char[ Time[L_u[2]]];
- Led_buff[1] = Led_Char[ Time[L_u[1]]];
- Led_buff[0] = Led_Char[ Time[L_u[0]]];
-
- }
- //讀取溫度并寫進數碼管顯示緩沖區======================
- if(WenDu == 1)
- { WenDu = 0;
- //零上溫度轉換
- map=read_byte(DS3231_TEMPERATUREH); //溫度高字節—整數位
- if((map&0x80)==0) //判斷首字節為1即為 零下溫度
- { Led_buff[0] = 0xa7;
- Time[16]=map%10 ;
- Time[17]=map/10%10;
- map=read_byte(DS3231_TEMPERATUREL); //溫度低字節—小數位
- map=(map>>6)*25; //由于分辨率為0.25 所以擴大25倍便于顯示
- Time[14]=map%10;
- Time[15]=map/10%10;
- }
- else //零下溫度轉換—零下是以2的補碼形式存儲的
- { Led_buff[0] = 0xa6;
- wend=map; //單字節轉換雙字節
- wend=wend<<2; //移出兩位放溫度的低位
- map=read_byte(DS3231_TEMPERATUREL); //讀溫度低字節
- map=map>>6; //由于2位放在頭兩位上,移到低位
- wend=wend+map; //組成10位的2進制的溫度編碼
- wend=(~wend)+1; //負數是以2的補碼形式存儲的,轉為原碼
- wend=wend&0x03ff;//10位的2進制的溫度編碼,截去無用位
- map= wend&0x0003;//分離低兩位,作為小數位
- map= map*25; //由于分辨率為0.25 所以擴大25倍便于顯示
- Time[14]=map%10;
- Time[15]=map/10%10;
- wend=wend>>2; //整數位處理
- Time[16]=wend%10;
- Time[17]=wend/10%10;
- }
-
- if((ling==0) && (Time[L_u[17]]==0)) //判斷數碼管首位零是否顯示
- Led_buff[3] = 0xff;
- else
- Led_buff[3] = Led_Char[ Time[17]]; //整數位顯示兩位
- Led_buff[2] = Led_Char[ Time[16]];
- Led_buff[1] = Led_Char[ Time[15]]; //小數位顯示一位
-
- write_byte(DS3231_CONTROL, 0x3C); //溫度強制轉換—準備下次讀取
- }
- //長按鍵處理
- if(BianJi_c==1)
- { BianJi_c=0;
- KEY1=1;
- BianJi++;
- if(BianJi==1) //進入溫度顯示
- { WenDu = 1; }
- if(BianJi==2) //進入首位數碼管修改位
- { Led_buff[3] = Led_Char[ Time[L_u[3]]];
- Led_buff[2] = 0xbf;
- Led_buff[1] = 0xbf;
- Led_buff[0] = 0xbf;
- }
- if(BianJi==3) //進入第二位數碼管修改位
- { Led_buff[3] = 0xbf;
- Led_buff[2] = Led_Char[ Time[L_u[2]]];
- if(Time[L_u[3]]==2 && Time[L_u[2]]>3) //若為24小時制 首位為2則壓縮次位的修改范圍
- { Time[L_u[2]]=3;
- Anjian_d(L_u[2],3);
- }
- }
- if(BianJi==4) //進入第三位數碼管修改位
- { Led_buff[2] = 0xbf;
- Led_buff[1] = Led_Char[ Time[L_u[1]]];
- }
- if(BianJi==5) //進入第四位數碼管修改位
- { Led_buff[1] = 0xbf;
- Led_buff[0] = Led_Char[ Time[L_u[0]]];
- }
- if(BianJi==6) //進入數碼管首位零是否顯示,修改選項 顯示零:ON 不顯示零:OFF
- { if(ling==0)
- { Led_buff[3] = 0xff;
- Led_buff[2] = 0xC0;
- Led_buff[1] = 0x8E;
- Led_buff[0] = 0x8E;
- }
- else
- { Led_buff[3] = 0xff;
- Led_buff[2] = 0xff;
- Led_buff[1] = 0xC0;
- Led_buff[0] = 0xc8;
- }
- }
- if(BianJi==7) //退出編輯模式
- { BianJi=0; }
-
- }
- //短按鍵處理
- if(BianJi_d==1)
- { BianJi_d=0;
- if(BianJi==1) //退出編輯模式
- { BianJi=0; }
- if(BianJi==2) //首位數碼管修改位
- { Anjian_d(L_u[3],2);}
- if(BianJi==3) //第二位數碼管修改位
- { if(Time[L_u[3]]==2 )
- { Anjian_d(L_u[2],3); }
- else
- { Anjian_d(L_u[2],9); }
-
- }
- if(BianJi==4) //第三位數碼管修改位
- { Anjian_d(L_u[1],5); }
- if(BianJi==5) //第四位數碼管修改位
- { Anjian_d(L_u[0],9); }
- if(BianJi==6) //進入數碼管首位零是否顯示,修改選項 顯示零:ON 不顯示零:OFF
- {
- if(ling==0)
- { ling = 1;
- Led_buff[3] = 0xff;
- Led_buff[2] = 0xff;
- Led_buff[1] = 0xC0;
- Led_buff[0] = 0xc8;
- write_byte_E2(ling);
- }
- else
- { ling = 0;
- Led_buff[3] = 0xff;
- Led_buff[2] = 0xC0;
- Led_buff[1] = 0x8E ;
- Led_buff[0] = 0x8E;
- write_byte_E2(ling);
- }
- }
-
- }
- }
- }
- //短按鍵處理
- void Anjian_d(u8 addr, u8 map)
- {
- u8 i;
- Time[addr]++; //時間變量
- if(Time[addr]>map) //時間變量最大值
- Time[addr]=0;
- if((addr%2)==0) //計算傳入值時十位或個位 0:各位 1:十位
- i = Time[addr+1]*10+Time[addr]; //十位個位組成數值待寫入DS3231
- else
- i = Time[addr]*10+Time[addr-1]; //十位個位組成數值待寫入DS3231
- Led_buff[5-BianJi] = Led_Char[ Time[addr]]; //修改的值顯示到數碼管上
- write_byte(addr/2,HEX2BCD(i)); //寫入DS3231
-
- }
- /* 配置并啟動T0,ms-T0定時時間 */
- void ConfigTimer0(u8 ms)
- {
- unsigned long tmp; //臨時變量
-
- tmp = 12000000 / 12; //定時器計數頻率
- tmp = (tmp * ms) / 1000; //計算所需的計數值
- tmp = 65536 - tmp; //計算定時器重載值
- TMOD &= 0xF0; //清零T0的控制位
- TH0 = (u8)(tmp>>8); //定時器重載值拆分為高低字節
- TL0 = (u8)tmp;
- ET0 = 1; //使能T0中斷
- TR0 = 1; //啟動T0
- }
- //中斷定義為5毫秒
- void InterruptTimer0() interrupt 1
- {
- static u8 Di;
- //非編輯模式進入
- if(BianJi==0)
- {
- Di++;
- if(Di==100)
- {BP=1;} //秒顯示賦值 0.5秒
- if(Di==200)
- {
- Di=0;
- BiaoJi=1; //一秒一次讀DS3231時間,并寫入數碼管緩沖區的標記
- BP=0; //秒顯示賦值 0.5秒
- }
- }
- //編輯模式(1)進入
- if(BianJi==1)
- { Di++;
- if(Di==200)
- { Di=0; WenDu = 1;} //一秒一次讀DS3231溫度,并寫入數碼管緩沖區的標記
- }
-
- Led_can(); //數碼管刷新
- anjian(); //按鍵掃描
- WDT_CONTR=0x37; //看門狗刷新 8.4S
- }
- //E2PROM-寫一個字節數據到時鐘芯片
- void write_byte_E2( u8 write_data)
- {
- I2CStart(); //產生總線起始信號
- I2CWrite(E2PROM_WriteAddress); //<<<<I2C總線寫操作 E2PROM-器件碼
- I2CWrite(0); // E2PROM-存儲空間高八位地址
- I2CWrite(1); // E2PROM-存儲空間低八位地址
- I2CWrite(write_data); // 寫數據
- I2CStop(); //產生總線停止信號
-
- }
- //E2PROM-讀一個字節數據到時鐘芯片
- u8 read_byte_E2()
- {
- char temp;
- I2CStart(); //產生總線起始信號
- I2CWrite(E2PROM_WriteAddress); //<<<<I2C總線寫操作 E2PROM-器件碼
- I2CWrite(0); // E2PROM-存儲空間高八位地址
- I2CWrite(1); // E2PROM-存儲空間低八位地址
- I2CStart(); //產生總線起始信號
- I2CWrite(E2PROM_WriteAddress|1); //從寫 E2PROM-器件碼
- temp = I2CReadNAK(); // 讀數據-發送非應答信號,不讀了
- I2CStop(); //產生總線停止信號
- return(temp);
- }
- //DS3231_寫一個字節數據到時鐘芯片
- void write_byte(u8 addr, u8 write_data)
- {
- I2CStart(); //產生總線起始信號
- I2CWrite(DS3231_WriteAddress); //<<<<I2C總線寫操作
- I2CWrite(addr); //<<<<I2C總線寫操作
- I2CWrite(write_data); //<<<<I2C總線寫操作
- I2CStop(); //產生總線停止信號
-
- }
- //DS3231_讀一個字節數據到時鐘芯片
- u8 read_byte(u8 random_addr)
- {
- char temp;
- I2CStart(); //產生總線起始信號
- I2CWrite(DS3231_WriteAddress); //<<<<I2C總線寫操作 器件碼
- I2CWrite(random_addr); //<<<<存儲空間地址
- I2CStart(); //產生總線起始信號
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
0.jpg (22.38 KB, 下載次數: 84)
下載附件
2017-12-18 21:57 上傳
所有資料51hei提供下載:
實時時鐘.rar
(145.56 KB, 下載次數: 369)
2017-12-18 18:52 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|