時鐘目前能正常走時,大概1天快12秒
鄙人愚昧,部分問題未能解決,
還望各位高手出手相救,出謀劃策
【按鍵掃描問題】:
調時間時:1,調小時分鐘 加鍵不是按一次加一,是亂加,
小時能調到24時,退出設置顯示0時
2,調小時分鐘 減鍵不是按一次減一,是亂減
[size=13.63636302948px] 3,調秒時,加鍵減鍵亂加減,秒能調到8*,9*秒
[size=13.63636302948px] 4,退出設置秒清零,設置的秒未能保存,時和分能保存
[size=13.63636302948px] 5,時間能調到24時,退出設置顯示0時
[size=13.63636302948px] 當有按鍵按下時數碼管全滅不顯示,按鍵松開數碼管顯示
[size=13.63636302948px] 6,啟動定時器中斷,能輕微看見數碼管閃爍
[size=13.63636302948px] //7,鬧鐘有問題,麻煩增加鬧鐘函數,
[size=13.63636302948px] // 鬧鐘開指示燈亮,鬧鐘關指示燈滅
[size=13.63636302948px] 8,如何提高走時精度[size=13.63636302948px] 這里是源工程文件
加按鍵測試01.zip
(33.2 KB, 下載次數: 22)
2015-1-14 01:04 上傳
點擊文件名下載附件
[size=13.63636302948px]源程序:
- /************************
- ds1302數碼管顯示時間
- ************************/
- /*****頭文件*****/
- #include<reg52.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- /*****DS1302引腳定義*****/
- sbit rst = P0^7; /*實時時鐘復位線引腳*///(所有的數據傳輸在rst置1時進行,rst為0時終止傳輸)
- sbit io = P0^6; /*實時時鐘數據線引腳*/
- sbit clk = P0^5; /*實時時鐘時鐘線引腳*/
- sbit ACC0 = ACC^0; /*累加寄存器的第0位*/
- sbit ACC7 = ACC^7; /*累加寄存器的第7位*/
- sbit LED1 = P3^0; /*未定義(高電平亮)(3mm紅發紅光)*/
- sbit LED2 = P3^1; /*鬧鐘指示燈(低電平亮)(亮:鬧鐘開;滅:鬧鐘關)(alarm clock)(3mm白發綠光)*/
- sbit tele = P3^2; /*紅外遙控數據線引腳(telecontrol)*/
- sbit motor = P3^3; /*振子,馬達,震動(低電平轉)(vibration,motor)*/
- sbit beep = P3^4; /*蜂鳴器(低電平響)*/
- /*****按鍵定義*****/
- sbit key1 = P3^7; /*設置鍵*/
- sbit key2 = P3^6; /*加鍵*/
- sbit key3 = P3^5; /*減鍵*/
- uchar keynum; /*按鍵計數*/
-
- /*****數碼管數組*****/
- uchar code smg_du[]= /*共陽數碼管段碼表*//*P2引腳*/
- {0xc0,0xf9,0xa4,0xb0,0x99, /*0-9*/
- 0x92,0x82,0xf8,0x80,0x90,0xbf};
- uchar code smg_we[]= /*數碼管位碼*//*P1引腳*/
- {0xC1,0xC2,0xC4, /*從左到右*/
- 0xC8,0xD0,0xE0}; /*位置1,2,3,4,5,6*/
- /*****時間初值*****/
- uchar table_shijian[7]={15,7,12,30,23,59,55}; /*年周月日時分秒*/
- uchar write_add[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80}; /*定義寫寄存器(年周月日時分秒)*/
- uchar read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81}; /*定義讀寄存器(年周月日時分秒)*/
- uchar disp[6]; //存放轉換成十進制后并分離出個位十位的數/*6個顯示元素(6個數碼管)*/
-
- /******函數聲明*****/
- void write_ds1302byte(uchar com); /*寫一個字節*/
- void write_ds1302(uchar com,uchar dat); /*寫一個字節命令和一個字節數據*/
- uchar read_ds1302(uchar com); /*讀一字節數據*/
- void ds1302_init(void); /*初始化ds1302*/
- void read_rtc(void); /*讀取時間*/
- void display(void); /*顯示處理函數*/
- void display_shijian(void); /*顯示函數*/
- void delay(uchar z); /*延時*/
- void tiaoshi(void); /*按鍵掃描*/
- void Timer0Init(); /*定時器初始化*/
- void Timer0zd(); /*定時器中斷*/
- /************************************************************************/
- /************主函數***************/
- void main(void)
- {
- delay(200); //等待系統穩定
- LED1=0; //關閉未定義LED (P3.0)
- // Timer0Init(); //初始化定時器0
- ds1302_init(); //初始化ds1302/*一次即可*/
- while(1) /*大循環*/
- {
- tiaoshi(); /*調用按鍵掃描函數*/
- display(); /*調用顯示處理函數*/
- display_shijian(); /*調用顯示時間函數*/
- if(keynum==0) /*如果按鍵沒有動作則執行以下指令*/
- {
- read_rtc(); /*調用讀時間函數*/
- }
- }
- }
- /*****定時器*****/
- //void Timer0Init() //20毫秒@11.0592MHz
- //{
- // TMOD |= 0x01; //定時器0模式1定時器時鐘12T模式
- // TL0 = 0x00; //設置定時初值
- // TH0 = 0xb8; //設置定時初值
- // TF0 = 0; //清除TF0標志
- // TR0 = 1; //開定時器0
- // ET0 = 1; //開定時器中斷
- // EA = 1; //開總中斷
- //}
- ////
- //void Timer0zd() interrupt 1
- //{
- // TL0 = 0x00; //設置定時初值
- // TH0 = 0xb8; //設置定時初值
- //
- // display();
- ////display_shijian(); /*調用顯示時間函數*/
- //// read_rtc(); /*調用讀時間函數*/
- // if(keynum==0) /*如果按鍵沒有動作則執行以下指令*/
- // {
- // read_rtc(); /*調用讀時間函數*/
- // }
- //}
- /*****延時函數*****/
- void delay(uchar z) /*延時≈1毫秒*/
- {
- uint x,y;
- for(x=z;x>0;x--)
- for(y=115;y>0;y--);
- }
- /*****按鍵掃描模塊*****/
- void tiaoshi(void)
- {
- if(key1==0) //如果設置鍵按下
- {
- delay(10); //延時消抖
- if(key1==0) //判斷,防誤操作
- {
- while(!key1); //松手檢測
- write_ds1302(0x8e,0x00); //關閉寫保護(可以寫操作)
- write_ds1302(0x80,0x80); //晶振停振時鐘停止秒停
- keynum++; //設置鍵按鍵計數自動加1*/
- switch(keynum) //設置鍵按鍵次數統計*/
- {
- case 1:P2=smg_du[disp[1]];P1=smg_we[1];delay(100);break; /*按1次*//*調小時*//*數碼管第二位閃爍*//*時個位*/
- case 2:P2=smg_du[disp[3]];P1=smg_we[3];delay(100);break; /*按2次*//*調分鐘*//*數碼管第四位閃爍*//*分個位*/
- case 3:P2=smg_du[disp[5]];P1=smg_we[5];delay(100);break; /*按3次*//*調秒鐘*//*數碼管第六位閃爍*//*秒個位*/
- case 4:keynum=0;write_ds1302(0x80,0x00);write_ds1302(0x8e,0x80);break; /*按4次*//*退出設置*//*啟動晶振開始走時*//*開寫保護*/
- default:break;
- }
- }
- }
- if(keynum!=0) //如果keynum不是0說明設置鍵有動作
- { //則執行以下指令
- if(key2==0) //如果加鍵被按下
- { //則執行以下指令
- delay(10); //延時消抖
- while(!key2) //松手檢測
- switch(keynum) /*設置鍵按鍵計數*/
- {
- case 1: /*加鍵按一次*//*時加1*/
- table_shijian[4]=read_ds1302(read_add[4]); //讀出當前的小時
- table_shijian[4]=((((table_shijian[4]&0xf0)>>4)*10)+(table_shijian[4]&0x0f)); //將當前的時轉換成十進制數
- table_shijian[4]++;
- if(table_shijian[4]==24) table_shijian[4]=0;
- table_shijian[4]=(((table_shijian[4]/10)<<4)|table_shijian[4]%10); //將時部分十進制數轉換為十六進制數
- write_ds1302(write_add[4],table_shijian[4]);break; //寫入ds1302時位置
-
- case 2: /*加鍵按一次*//*分加1*/
- table_shijian[5]=read_ds1302(read_add[5]); //讀出當前的分鐘
- table_shijian[5]=((((table_shijian[5]&0xf0)>>4)*10)+(table_shijian[5]&0x0f)); //將當前的分鐘轉換成十進制數
- table_shijian[5]++;
- if(table_shijian[5]==60) table_shijian[5]=0;
- table_shijian[5]=(((table_shijian[5]/10)<<4)|table_shijian[5]%10); //將分鐘部分十進制數轉換為十六進制數
- write_ds1302(write_add[5],table_shijian[5]);break; //寫入ds1302分位置
-
- case 3: /*加鍵按一次*//*秒加1*/
- table_shijian[6]=read_ds1302(read_add[6]); //讀出當前的秒
- table_shijian[6]=((((table_shijian[6]&0xf0)>>4)*10)+(table_shijian[6]&0x0f)); //將當前的秒轉換成十進制數
- table_shijian[6]++;
- if(table_shijian[6]==60) table_shijian[6]=0;
- table_shijian[6]=(((table_shijian[6]/10)<<4)|table_shijian[6]%10); //將秒部分十進制數轉換為十六進制數
- write_ds1302(write_add[6],table_shijian[6]);break; //寫入ds1302秒位置
- }
- }
- }
- if(keynum!=0) //如果keynum不是0說明設置鍵有動作
- { //則執行以下指令
- if(key3==0) //如果減鍵被按下
- { //則執行以下指令
- delay(10); //延時消抖
- while(!key3) //松手檢測
- switch(keynum) /*設置鍵按鍵計數*/
- {
- case 1: /*減鍵按一次*//*時減1*/
- table_shijian[4]=read_ds1302(read_add[4]); //讀出當前的時
- table_shijian[4]=((((table_shijian[4]&0xf0)>>4)*10)+(table_shijian[4]&0x0f)); //將當前的時轉換成十進制數
- table_shijian[4]--;
- if(table_shijian[4]==-1) table_shijian[4]=23;
- table_shijian[4]=(((table_shijian[4]/10)<<4)|table_shijian[4]%10); //將時部分十進制數轉換為十六進制數
- write_ds1302(write_add[4],table_shijian[4]);break; //寫入ds1302時位置
-
- case 2: /*減鍵按一次*//*分減1*/
- table_shijian[5]=read_ds1302(read_add[5]); //讀出當前的分
- table_shijian[5]=((((table_shijian[4]&0xf0)>>4)*10)+(table_shijian[5]&0x0f)); //將當前的分轉換成十進制數
- table_shijian[5]--;
- if(table_shijian[5]==-1) table_shijian[5]=59;
- table_shijian[5]=(((table_shijian[5]/10)<<4)|table_shijian[5]%10); //將分部分十進制數轉換為十六進制數
- write_ds1302(write_add[5],table_shijian[5]);break; //寫入ds1302分位置
-
- case 3: /*減鍵按一次*//*秒減1*/
- table_shijian[6]=read_ds1302(read_add[6]); //讀出當前的秒
- table_shijian[6]=((((table_shijian[6]&0xf0)>>4)*10)+(table_shijian[6]&0x0f)); //將當前的秒轉換成十進制數
- table_shijian[6]--;
- if(table_shijian[6]==-1) table_shijian[6]=59;
- table_shijian[6]=(((table_shijian[6]/10)<<4)|table_shijian[6]%10); //將秒部分十進制數轉換為十六進制數
- write_ds1302(write_add[6],table_shijian[6]);break; //寫入ds1302秒位置
- }
- }
- }
- }
- /*****ds1302模塊*****/
- /*****寫一個字節*****/
- void write_ds1302byte(uchar com)
- {
- uchar i; //定義一個變量i
- for(i=0;i<8;i++) //連續寫8個二進制位數據
- {
- clk=0; //拉低時鐘線,為脈沖上升沿寫入數據做好準備
- io=com&0x01; //取出com的第0位數據寫入1302//(數據和0x01與)每次傳輸低字節
- com=com>>1; //將com的數據位右移1位
- clk=1; //時鐘線上升沿寫入數據
- }
- }
- /*****寫一個字節命令和一個字節數據*****/
- void write_ds1302(uchar com,uchar dat)
- {
- rst=0; _nop_(); //禁止數據傳輸//空操作(相當于短暫延時)
- clk=0; _nop_(); //確保寫數據前時鐘線被拉低//空操作
- rst=1; _nop_(); //啟動數據傳輸//空操作
- write_ds1302byte(com); //寫命令地址
- write_ds1302byte(dat); //寫數據
- rst=0; _nop_(); //禁止數據傳遞(操作完趕緊拉低防止誤操作)//空操作
- io=0; _nop_(); //釋放io
- clk=1; _nop_(); //將時鐘線電平置于已知狀態
- }
- /*****讀一個字節命令讀一個字節數據*****/
- uchar read_ds1302(uchar com)
- {
- uchar i,value;
- clk=1; _nop_(); //確保寫數據前時鐘線被拉高//空操作
- io=1; _nop_(); //數據線拉高
- rst=1; _nop_(); //啟動數據傳輸//空操作
- write_ds1302byte(com); //寫入命令字后/進行讀操作之前要進行寫命令(地址),以確定是讀那個
- for(i=0;i<8;i++) //連續讀8個二進制位數據
- {
- clk=0; //拉低時鐘線,形成脈沖下降沿讀數據
- value=value>>1; //將value的各數據位右移1位,先讀出的是字節的最低位
- if(io) //如果讀出的數據是1
- value=value|0x80; //將1取出,寫在value的最高位
- clk=1; //將clk拉高,為下次下降沿讀出數據做好準備
- }
- rst=0; //禁止數據傳輸
- return(value); //將讀出的數據返回
- }
- /*****初始化DS1302*****/
- void ds1302_init(void)
- {
- uchar i,a,b;
- // uchar CH;
- write_ds1302(0x8e,0x00); //關閉寫保護(可以寫操作)
- // write_ds1302(0x80,0x80); //裝初值前晶振停止,秒停
- for(i=0;i<7;i++)
- {
- a=table_shijian[i]%10; //個位
- b=table_shijian[i]/10; //十位
- table_shijian[i]=a+b*16; //轉換為十六進制
- }
- // CH=read_ds1302(0x81); //先對ds1302進行讀回秒寄存器,
- //
- // if(CH&0x80) //判斷秒寄存器最高位(CH)是否為1
- // { //如為1,說明晶振停止工作,ds1302處于低功耗待命狀態,對它寫入初值
- // //如為0,說明晶振開始振動,ds1302處于工作狀態,(說明在斷電時還起用了備用電池,所以ds1302還處于工作狀態)
- // //如果每次上電要求都寫入初值,就無需這步操作,
- // for(i=0;i<7;i++) //寫入數據(年周月日時分秒)
- // {
- // write_ds1302(write_add[i],table_shijian[i]); //寫入命令,寫數據
- // }
- // }
- for(i=0;i<7;i++) //連續寫7個數據(年周月日時分秒)
- {
- write_ds1302(write_add[i],table_shijian[i]); //寫入命令,寫數據//對號入座
- }
-
- // write_ds1302(0x80,0x00); //啟動晶振開始走時,秒走
- write_ds1302(0x90,0xa5); //使能充電,1個二極管,2K電阻
- write_ds1302(0x8e,0x80); //打開寫保護(禁止寫操作)
- }
- //*****讀取時間*****/
- void read_rtc(void)
- {
- uchar i;
- for(i=0;i<7;i++) //連續讀7個數據(年周月日時分秒)
- {
- table_shijian[i]=read_ds1302(read_add[i]); //數據對應寄存器的地址
- }
- }
- /************顯示處理**************/
- void display(void)
- {
- disp[0]=table_shijian[4]/16; /*時的十位*/
- disp[1]=table_shijian[4]%16; /*時的個位*/
- /*disp[2]=10;*/
- disp[2]=table_shijian[5]/16; /*分的十位*/
- disp[3]=table_shijian[5]%16; /*分的個位*/
- /*disp[5]=10; */
- disp[4]=table_shijian[6]/16; /*秒的十位*/
- disp[5]=table_shijian[6]%16; /*秒的個位*/
- }
- /*****顯示時間*****/
- void display_shijian(void)
- {
- uchar i;
- for(i=0;i<6;i++) /*連續寫入6位,時時分分秒秒*/
- {
- P1=smg_we[i]; /*數碼管位選*/
- P2=smg_du[disp[i]]; /*數碼管段選*/
- delay(2); /*延時*/
- P2=0xff; /*消隱*/
- // delay(2); /*延時*///這個延時影響數碼管閃爍
- }
- }
復制代碼
|