//DS1302時(shí)鐘程序 #include <stc89c52.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int /********************************************************************/ //少占魚制作 河北正定歡迎您 長(zhǎng)沙航空職業(yè)技術(shù)學(xué)院 //2010 年QQ:411656434 //版權(quán)所有:www.torrancerestoration.com #define LCD1602_RS P2_5 //定義引腳 #define LCD1602_RW P2_6 #define LCD1602_E P2_7 #define LCD1602_IO P0 #define Busy 0x80 //用于檢測(cè)LCD1602狀態(tài)字中的Busy標(biāo)識(shí) const uchar num[]=" 3456789+"; uchar code a[] = {" E N v"}; void WriteData(uchar DAT); void WriteCommand(uchar command,BuysC); uchar ReadData(void); void Readbusy(void); void LCD1602_Init(void); void DisplayOneChar(uchar X, uchar Y, uchar DData); void Displaystring(uchar X, uchar Y, uchar *DData); void Delay5Ms(void); void Delay400Ms(void); void delayms(uint); void delays(uint m) ; void delayus(uchar x) ; sbit DS1302_CLK =P2^0;// P1^0; sbit DS1302_IO =P2^1;// P1^1; sbit DS1302_RST =P2^2;// P1^2; uchar shuju; unsigned char time[]={0x11,0x03,0x28,0x01,0x12,0x39,0x00};// 初始化時(shí)間年月日星期時(shí)分秒 uchar Display_Buffer[12]={"12:25:00"};//時(shí)、分、秒 的格式 uchar riqi[12]={"11-03-28"};//年、月、日 的格式 uchar xingqi[5]="week";//星期 unsigned char second,minute,hour,week,day,month,year; /******************1602函數(shù)********************************/ /********************************************************************/ void delays(uint m) { uint i,j; for(i=0;i<m;i++) { for(j=0;j<1000;j++) {;} } } void Delay(void) { unsigned char i; unsigned int j; for(i=0;i<200;i++) for(j=300;j>0;j--); } /***************************************************************************** 函數(shù)功能:向DS1302送一字節(jié)數(shù)據(jù)子程序 入口參數(shù): 出口參數(shù): *****************************************************************************/ void InputByte(unsigned char BYTE) { char i; for(i=8;i>0;i--) { //前面在read_ds1302()函數(shù)里已經(jīng)把CLK清0了 DS1302_CLK=0;//這里再清0一次,看著清楚。呵呵 _nop_(); DS1302_IO=(bit)(BYTE&0x01);//取出低位數(shù)據(jù)給數(shù)據(jù)引腳 _nop_(); _nop_(); DS1302_CLK=1;//置1,時(shí)鐘上升沿,引腳上的數(shù)據(jù)傳入1302寄存器中 _nop_(); _nop_(); BYTE>>=1;//因?yàn)檫@里移位的BYTE不是最后要的結(jié)果,雖然最后循環(huán)完會(huì)多移一位,但沒影響。 _nop_(); //循環(huán)最后一次后,時(shí)鐘狀態(tài)是高電平。 } _nop_(); _nop_(); } /***************************************************************************** 函數(shù)功能:讀DS1302一個(gè)字節(jié)子程序,讀數(shù)據(jù)是下降沿讀 入口參數(shù): 出口參數(shù): *****************************************************************************/ unsigned char OutputByte(void) { unsigned char i; unsigned char ucdat=0; for(i=8;i>0;i--) { //前面時(shí)鐘狀態(tài)是高電平。 ucdat>>=1; //移位注意,移位不能放在循環(huán)語句末,否則最后循環(huán)完會(huì)多移一位。得到結(jié)果就錯(cuò)了。 DS1302_IO=1;//單片機(jī)端置高防止破壞1302傳來的數(shù)據(jù),開始接收1302端的高低數(shù)據(jù)對(duì)數(shù)據(jù)線的改變。 DS1302_CLK=0;//緊接著時(shí)鐘變低,下降沿?cái)?shù)據(jù)輸出。 if(DS1302_IO)//數(shù)據(jù)已經(jīng)輸出,判斷是1還是0. ucdat|=0x80;//如果引腳是高則此位保存1。低不保存,右移的時(shí)候自然補(bǔ)0了。 _nop_(); DS1302_CLK=1;//讀完一位數(shù)據(jù),再置高時(shí)鐘,準(zhǔn)備讀下一個(gè)。 _nop_();//延時(shí)一下。 } //讀完數(shù)據(jù)還是把時(shí)鐘清0,下次好直接用。 DS1302_CLK=0;//讀完數(shù)據(jù)還是把時(shí)鐘清0,下次好直接用。 _nop_(); _nop_(); DS1302_RST=0; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); DS1302_CLK=0; _nop_(); _nop_(); _nop_(); _nop_(); DS1302_RST=0; _nop_(); _nop_(); _nop_(); _nop_(); _nop_(); return(ucdat); } /***************************************************************************** 函數(shù)功能:向DS1302某地址寫一字節(jié)數(shù)據(jù)子程序 入口參數(shù):addr,TDat 出口參數(shù): *****************************************************************************/ void write_ds1302(unsigned char addr,unsigned char TDat) { DS1302_RST=0; _nop_(); _nop_(); DS1302_CLK=0; _nop_(); _nop_(); DS1302_RST=1; _nop_(); _nop_(); _nop_(); _nop_(); InputByte(addr);//先寫地址 _nop_(); _nop_(); InputByte(TDat);//再寫數(shù)據(jù) DS1302_IO=1;//單片機(jī)端置高防止破壞1302傳來的數(shù)據(jù),開始接收1302端的高低數(shù)據(jù)對(duì)數(shù)據(jù)線的改變。 DS1302_RST=0; delayus(10); DS1302_CLK=0; delayus(10); } /***************************************************************************** 函數(shù)功能:讀DS1302地址子程序 入口參數(shù):add 出口參數(shù):timedata *****************************************************************************/ unsigned char read_ds1302(unsigned char addr) { unsigned char timedata; DS1302_RST=0; _nop_(); DS1302_CLK=0; _nop_(); DS1302_RST=1; InputByte(addr);//先寫入讀命令 timedata=OutputByte();//再讀出數(shù)據(jù) DS1302_IO=1;//單片機(jī)端置高防止破壞1302傳來的數(shù)據(jù),開始接收1302端的高低數(shù)據(jù)對(duì)數(shù)據(jù)線的改變。 DS1302_RST=0; delayus(10); DS1302_CLK=0; delayus(10); return(timedata); } /***************************************************************************** 函數(shù)功能:初始化DS1302子程序 入口參數(shù):time[](全局變量) 出口參數(shù): *****************************************************************************/ void initial_ds1302() { DS1302_IO=1;//單片機(jī)端置高防止破壞1302傳來的數(shù)據(jù),開始接收1302端的高低數(shù)據(jù)對(duì)數(shù)據(jù)線的改變。 DS1302_RST=0; delayms(100); DS1302_CLK=0; delayms(100); write_ds1302(0x8e,0x00); //寫保護(hù)寄存器,在對(duì)時(shí)鐘或RAM寫前WP一定要為0 write_ds1302(0x8c,time[0]); //年 write_ds1302(0x88,time[1]); //月 write_ds1302(0x86,time[2]); //日 write_ds1302(0x8A,time[3]); //星期 write_ds1302(0x84,time[4]); //時(shí) write_ds1302(0x82,time[5]); //分 write_ds1302(0x80,time[6]); //秒 write_ds1302(0x8e,0x80); //寫保護(hù)寄存器 } /***************************************************************************** 函數(shù)功能:讀DS1302時(shí)間子程序 入口參數(shù): 出口參數(shù):全局變量(second,minute,hour,week,day,month,year) *****************************************************************************/ void read_time() { second=read_ds1302(0x81); //秒寄存器 _nop_(); minute=read_ds1302(0x83); //讀分 _nop_(); hour=read_ds1302(0x85); //讀時(shí) _nop_(); week=read_ds1302(0x8B); //讀星期 _nop_(); day=read_ds1302(0x87); //日 _nop_(); month=read_ds1302(0x89); //月 _nop_(); year=read_ds1302(0x8d); //年 _nop_(); } void main(void) {uchar shuju; delayms(2); Delay400Ms(); //啟動(dòng)等待,等LCM講入工作狀態(tài) delays(1); LCD1602_Init(); //LCM初始化 Delay5Ms(); //延時(shí)片刻(可不要) DS1302_RST=0; delayms(1000); DS1302_CLK=0; delayms(1000); shuju=ReadData(); Displaystring(2, 0, a); Delay();Delay(); delayms(2000); Displaystring(3,0,riqi); Displaystring(12,0,xingqi); delayms(4000); // initial_ds1302(); //初始化DS1302 delayms(1200); while(1) { read_time();//讀取時(shí)間 Display_Buffer[0]=hour/16+'0';//存儲(chǔ)下時(shí)的高位進(jìn)數(shù)組 Display_Buffer[1]=hour%16+'0';//存儲(chǔ)下時(shí)的低位進(jìn)數(shù)組 Display_Buffer[3]=minute/16+'0';//注意+'0'后存儲(chǔ)的是ASCII。用于下面液晶顯示。 Display_Buffer[4]=minute%16+'0';//注意+'0'后存儲(chǔ)的是ASCII。用于下面液晶顯示。 Display_Buffer[6]=second/16+'0'; Display_Buffer[7]=second%16+'0'; riqi[0]=year/16+'0'; riqi[1]=year%16+'0'; riqi[3]=month/16+'0'; riqi[4]=month%16+'0'; riqi[6]=day/16+'0'; riqi[7]=day%16+'0'; Displaystring(3,0,riqi); delayms(1); DisplayOneChar(14,1,week+'0'); Displaystring(3,1,Display_Buffer); } } //寫數(shù)據(jù) void WriteData(uchar DAT) { Readbusy(); LCD1602_RS = 1; LCD1602_RW = 0; LCD1602_IO = DAT; LCD1602_E = 0; //若晶振速度太高可以在這后加小的延時(shí) LCD1602_E = 0; //延時(shí) LCD1602_E = 1; LCD1602_E=1; LCD1602_E=0; } //寫指令 void WriteCommand(uchar command,BuysC) //BuysC為0時(shí)忽略忙檢測(cè) { LCD1602_IO=0x00; if (BuysC) Readbusy(); //根據(jù)需要檢測(cè)忙 LCD1602_RS = 0; LCD1602_RW = 0; LCD1602_IO = command; LCD1602_E = 0; LCD1602_E = 0; LCD1602_E = 1; LCD1602_E = 1; LCD1602_E=0; } //讀數(shù)據(jù) uchar ReadData(void) { Readbusy(); LCD1602_RS = 1; LCD1602_RW = 1; LCD1602_E = 0; LCD1602_E = 0; LCD1602_E = 1; delayms(1); LCD1602_E = 0; return(LCD1602_IO); } //讀忙 void Readbusy(void) { LCD1602_IO = 0xff; LCD1602_RS = 0; LCD1602_RW = 1; LCD1602_E = 0; LCD1602_E = 0; LCD1602_E = 1; delayms(2); while (LCD1602_IO&0x80); //檢測(cè)忙信號(hào) LCD1602_E = 0; } //初始化 void LCD1602_Init(void) //LCM初始化 { Delay400Ms(); LCD1602_E = 0; LCD1602_IO=0x00; WriteCommand(0x38,0); //三次顯示模式設(shè)置,不檢測(cè)忙信號(hào) Delay5Ms(); WriteCommand(0x38,0); Delay5Ms(); WriteCommand(0x38,0); Delay5Ms(); WriteCommand(0x38,1); //顯示模式設(shè)置,開始要求每次檢測(cè)忙信號(hào) Delay5Ms(); WriteCommand(0x08,1); //關(guān)閉顯示 ] Delay5Ms(); WriteCommand(0x01,1); //顯示清屏 Delay5Ms(); WriteCommand(0x06,1); // 顯示光標(biāo)移動(dòng)設(shè)置 Delay5Ms(); WriteCommand(0x0f,1); // 顯示開及光標(biāo)設(shè)置 Delay5Ms(); } //按指定位置顯示一個(gè)字符 void DisplayOneChar(uchar X, uchar Y, uchar DData) { Y &= 0x01; X &= 0x0f; //限制X不能大于15,Y不能大于1 if (Y) X |= 0x40; //當(dāng)要顯示第二行時(shí)地址碼+0x40; X |= 0x80; // 算出指令碼 WriteCommand(X, 0); //這里不檢測(cè)忙信號(hào),發(fā)送地址碼 WriteData(DData); } //按指定位置顯示一串字符 void Displaystring(uchar X, uchar Y, uchar *DData) { uchar ListLength; ListLength = 0; Y &= 0x01; X &= 0x0f; //限制X不能大于15,Y不能大于1 while (DData[ListLength]>0x20) //若到達(dá)字串尾則退出 { if (X <= 0x0f) //X坐標(biāo)應(yīng)小于0x0f { DisplayOneChar(X, Y, DData[ListLength]); //顯示單個(gè)字符 ListLength++; X++; } } } //5ms延時(shí) void Delay5Ms(void) { unsigned int t = 5552; while(t--); } //400ms延時(shí) void Delay400Ms(void) { uchar i = 5; uint j; while(i--) { j=7269; while(j--); } } // void delayms(uint k) { uint data i,j; for(i=0;i<k;i++) { for(j=0;j<121;j++) {;} } } void delayus(uchar x) { while(--x); }