久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3677|回復: 7
打印 上一主題 下一主題
收起左側

51單片機+ds1302電子鐘能正常走時,按鍵有問題

[復制鏈接]
跳轉到指定樓層
樓主
ID:67519 發表于 2015-1-14 01:06 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
時鐘目前能正常走時,大概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)
[size=13.63636302948px]源程序:
  1. /************************

  2. ds1302數碼管顯示時間

  3. ************************/

  4. /*****頭文件*****/
  5. #include<reg52.h>
  6. #include<intrins.h>
  7. #define uchar unsigned char
  8. #define uint unsigned int

  9. /*****DS1302引腳定義*****/
  10. sbit rst = P0^7;    /*實時時鐘復位線引腳*///(所有的數據傳輸在rst置1時進行,rst為0時終止傳輸)
  11. sbit io = P0^6;     /*實時時鐘數據線引腳*/
  12. sbit clk = P0^5;    /*實時時鐘時鐘線引腳*/

  13. sbit  ACC0 = ACC^0; /*累加寄存器的第0位*/
  14. sbit  ACC7 = ACC^7; /*累加寄存器的第7位*/

  15. sbit  LED1 = P3^0;  /*未定義(高電平亮)(3mm紅發紅光)*/
  16. sbit  LED2 = P3^1;  /*鬧鐘指示燈(低電平亮)(亮:鬧鐘開;滅:鬧鐘關)(alarm clock)(3mm白發綠光)*/
  17. sbit  tele = P3^2;  /*紅外遙控數據線引腳(telecontrol)*/
  18. sbit  motor = P3^3; /*振子,馬達,震動(低電平轉)(vibration,motor)*/
  19. sbit  beep = P3^4;  /*蜂鳴器(低電平響)*/

  20. /*****按鍵定義*****/
  21. sbit key1 = P3^7; /*設置鍵*/
  22. sbit key2 = P3^6; /*加鍵*/
  23. sbit key3 = P3^5; /*減鍵*/

  24. uchar keynum; /*按鍵計數*/
  25.         
  26. /*****數碼管數組*****/
  27. uchar code smg_du[]=                 /*共陽數碼管段碼表*//*P2引腳*/
  28. {0xc0,0xf9,0xa4,0xb0,0x99,          /*0-9*/
  29. 0x92,0x82,0xf8,0x80,0x90,0xbf};
  30. uchar code smg_we[]=        /*數碼管位碼*//*P1引腳*/
  31. {0xC1,0xC2,0xC4,             /*從左到右*/
  32. 0xC8,0xD0,0xE0};        /*位置1,2,3,4,5,6*/

  33. /*****時間初值*****/
  34. uchar table_shijian[7]={15,7,12,30,23,59,55}; /*年周月日時分秒*/

  35. uchar write_add[7]={0x8c,0x8a,0x88,0x86,0x84,0x82,0x80}; /*定義寫寄存器(年周月日時分秒)*/
  36. uchar read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};         /*定義讀寄存器(年周月日時分秒)*/

  37. uchar disp[6]; //存放轉換成十進制后并分離出個位十位的數/*6個顯示元素(6個數碼管)*/
  38.          
  39. /******函數聲明*****/
  40. void write_ds1302byte(uchar com);  /*寫一個字節*/
  41. void write_ds1302(uchar com,uchar dat);        /*寫一個字節命令和一個字節數據*/
  42. uchar read_ds1302(uchar com); /*讀一字節數據*/
  43. void ds1302_init(void);        /*初始化ds1302*/
  44. void read_rtc(void);    /*讀取時間*/
  45. void display(void);            /*顯示處理函數*/
  46. void display_shijian(void);        /*顯示函數*/
  47. void delay(uchar z); /*延時*/
  48. void tiaoshi(void);         /*按鍵掃描*/
  49. void Timer0Init();   /*定時器初始化*/
  50. void Timer0zd();          /*定時器中斷*/

  51. /************************************************************************/

  52. /************主函數***************/
  53. void main(void)
  54. {
  55.         delay(200);           //等待系統穩定
  56.         LED1=0;                   //關閉未定義LED (P3.0)
  57. //    Timer0Init();  //初始化定時器0         
  58.     ds1302_init(); //初始化ds1302/*一次即可*/
  59.         while(1)                         /*大循環*/
  60.         {
  61.           tiaoshi();                 /*調用按鍵掃描函數*/
  62.           display();             /*調用顯示處理函數*/
  63.           display_shijian(); /*調用顯示時間函數*/         
  64.           if(keynum==0)                 /*如果按鍵沒有動作則執行以下指令*/
  65.           {
  66.                 read_rtc();             /*調用讀時間函數*/
  67.           }
  68.         }  
  69. }

  70. /*****定時器*****/
  71. //void Timer0Init()         //20毫秒@11.0592MHz
  72. //{
  73. //        TMOD |= 0x01; //定時器0模式1定時器時鐘12T模式
  74. //        TL0 = 0x00;         //設置定時初值
  75. //        TH0 = 0xb8;         //設置定時初值
  76. //        TF0 = 0;         //清除TF0標志
  77. //        TR0 = 1;           //開定時器0
  78. //        ET0 = 1;         //開定時器中斷
  79. //        EA = 1;                 //開總中斷
  80. //}
  81. ////
  82. //void Timer0zd() interrupt 1
  83. //{        
  84. //        TL0 = 0x00;         //設置定時初值
  85. //        TH0 = 0xb8;         //設置定時初值
  86. //
  87. //           display();
  88. ////display_shijian(); /*調用顯示時間函數*/
  89. ////        read_rtc();           /*調用讀時間函數*/
  90. //  if(keynum==0)                 /*如果按鍵沒有動作則執行以下指令*/
  91. //          {
  92. //                read_rtc();             /*調用讀時間函數*/
  93. //          }
  94. //}

  95. /*****延時函數*****/
  96. void delay(uchar z)          /*延時≈1毫秒*/
  97. {
  98.   uint x,y;
  99.   for(x=z;x>0;x--)
  100.   for(y=115;y>0;y--);
  101. }

  102. /*****按鍵掃描模塊*****/
  103. void tiaoshi(void)
  104. {
  105.   if(key1==0)            //如果設置鍵按下
  106.   {
  107.         delay(10);            //延時消抖
  108.         if(key1==0)            //判斷,防誤操作
  109.         {
  110.           while(!key1); //松手檢測
  111.           write_ds1302(0x8e,0x00); //關閉寫保護(可以寫操作)
  112.           write_ds1302(0x80,0x80); //晶振停振時鐘停止秒停
  113.       keynum++;                           //設置鍵按鍵計數自動加1*/
  114.          switch(keynum)                  //設置鍵按鍵次數統計*/
  115.          {
  116.            case 1:P2=smg_du[disp[1]];P1=smg_we[1];delay(100);break; /*按1次*//*調小時*//*數碼管第二位閃爍*//*時個位*/
  117.            case 2:P2=smg_du[disp[3]];P1=smg_we[3];delay(100);break; /*按2次*//*調分鐘*//*數碼管第四位閃爍*//*分個位*/
  118.            case 3:P2=smg_du[disp[5]];P1=smg_we[5];delay(100);break; /*按3次*//*調秒鐘*//*數碼管第六位閃爍*//*秒個位*/
  119.            case 4:keynum=0;write_ds1302(0x80,0x00);write_ds1302(0x8e,0x80);break;         /*按4次*//*退出設置*//*啟動晶振開始走時*//*開寫保護*/
  120.            default:break;
  121.          }                                                                                                        
  122.         }                  
  123.   }
  124.   if(keynum!=0)                  //如果keynum不是0說明設置鍵有動作
  125.   {                                          //則執行以下指令
  126.     if(key2==0)                  //如果加鍵被按下
  127.     {                                  //則執行以下指令
  128.           delay(10);          //延時消抖
  129.            while(!key2)   //松手檢測
  130.            switch(keynum) /*設置鍵按鍵計數*/
  131.            {
  132.             case 1:                  /*加鍵按一次*//*時加1*/
  133.              table_shijian[4]=read_ds1302(read_add[4]); //讀出當前的小時               
  134.              table_shijian[4]=((((table_shijian[4]&0xf0)>>4)*10)+(table_shijian[4]&0x0f)); //將當前的時轉換成十進制數
  135.          table_shijian[4]++;         
  136.          if(table_shijian[4]==24) table_shijian[4]=0;
  137.          table_shijian[4]=(((table_shijian[4]/10)<<4)|table_shijian[4]%10); //將時部分十進制數轉換為十六進制數
  138.              write_ds1302(write_add[4],table_shijian[4]);break; //寫入ds1302時位置
  139.                
  140.                 case 2:                  /*加鍵按一次*//*分加1*/
  141.              table_shijian[5]=read_ds1302(read_add[5]);                   //讀出當前的分鐘
  142.          table_shijian[5]=((((table_shijian[5]&0xf0)>>4)*10)+(table_shijian[5]&0x0f)); //將當前的分鐘轉換成十進制數
  143.          table_shijian[5]++;         
  144.          if(table_shijian[5]==60) table_shijian[5]=0;
  145.          table_shijian[5]=(((table_shijian[5]/10)<<4)|table_shijian[5]%10); //將分鐘部分十進制數轉換為十六進制數
  146.          write_ds1302(write_add[5],table_shijian[5]);break; //寫入ds1302分位置
  147.                
  148.                 case 3:                  /*加鍵按一次*//*秒加1*/
  149.              table_shijian[6]=read_ds1302(read_add[6]);  //讀出當前的秒
  150.          table_shijian[6]=((((table_shijian[6]&0xf0)>>4)*10)+(table_shijian[6]&0x0f)); //將當前的秒轉換成十進制數
  151.          table_shijian[6]++;         
  152.          if(table_shijian[6]==60) table_shijian[6]=0;
  153.          table_shijian[6]=(((table_shijian[6]/10)<<4)|table_shijian[6]%10); //將秒部分十進制數轉換為十六進制數
  154.          write_ds1302(write_add[6],table_shijian[6]);break; //寫入ds1302秒位置
  155.            }               
  156.     }                 
  157.   }
  158.   if(keynum!=0)                //如果keynum不是0說明設置鍵有動作
  159.   {                                         //則執行以下指令
  160.     if(key3==0)     //如果減鍵被按下
  161.     {                                //則執行以下指令
  162.           delay(10);    //延時消抖
  163.           while(!key3)  //松手檢測
  164.          switch(keynum) /*設置鍵按鍵計數*/
  165.          {
  166.           case 1:                /*減鍵按一次*//*時減1*/
  167.            table_shijian[4]=read_ds1302(read_add[4]); //讀出當前的時
  168.        table_shijian[4]=((((table_shijian[4]&0xf0)>>4)*10)+(table_shijian[4]&0x0f)); //將當前的時轉換成十進制數
  169.        table_shijian[4]--;         
  170.        if(table_shijian[4]==-1) table_shijian[4]=23;
  171.        table_shijian[4]=(((table_shijian[4]/10)<<4)|table_shijian[4]%10);   //將時部分十進制數轉換為十六進制數
  172.        write_ds1302(write_add[4],table_shijian[4]);break; //寫入ds1302時位置
  173.          
  174.           case 2:                /*減鍵按一次*//*分減1*/
  175.            table_shijian[5]=read_ds1302(read_add[5]); //讀出當前的分
  176.        table_shijian[5]=((((table_shijian[4]&0xf0)>>4)*10)+(table_shijian[5]&0x0f)); //將當前的分轉換成十進制數
  177.        table_shijian[5]--;         
  178.        if(table_shijian[5]==-1) table_shijian[5]=59;
  179.        table_shijian[5]=(((table_shijian[5]/10)<<4)|table_shijian[5]%10);    //將分部分十進制數轉換為十六進制數
  180.        write_ds1302(write_add[5],table_shijian[5]);break; //寫入ds1302分位置
  181.          
  182.           case 3:                /*減鍵按一次*//*秒減1*/
  183.            table_shijian[6]=read_ds1302(read_add[6]); //讀出當前的秒
  184.        table_shijian[6]=((((table_shijian[6]&0xf0)>>4)*10)+(table_shijian[6]&0x0f)); //將當前的秒轉換成十進制數
  185.        table_shijian[6]--;         
  186.        if(table_shijian[6]==-1) table_shijian[6]=59;
  187.        table_shijian[6]=(((table_shijian[6]/10)<<4)|table_shijian[6]%10);    //將秒部分十進制數轉換為十六進制數
  188.        write_ds1302(write_add[6],table_shijian[6]);break; //寫入ds1302秒位置
  189.          }                        
  190.     }                 
  191.   }
  192. }  

  193. /*****ds1302模塊*****/
  194. /*****寫一個字節*****/
  195. void write_ds1302byte(uchar com)   
  196. {
  197.     uchar i;                 //定義一個變量i
  198.         for(i=0;i<8;i++) //連續寫8個二進制位數據
  199.         {
  200.           clk=0;                 //拉低時鐘線,為脈沖上升沿寫入數據做好準備
  201.           io=com&0x01;         //取出com的第0位數據寫入1302//(數據和0x01與)每次傳輸低字節
  202.           com=com>>1;         //將com的數據位右移1位
  203.           clk=1;                 //時鐘線上升沿寫入數據
  204.     }
  205. }

  206. /*****寫一個字節命令和一個字節數據*****/
  207. void write_ds1302(uchar com,uchar dat)   
  208. {
  209. rst=0; _nop_(); //禁止數據傳輸//空操作(相當于短暫延時)
  210. clk=0; _nop_(); //確保寫數據前時鐘線被拉低//空操作
  211. rst=1; _nop_(); //啟動數據傳輸//空操作
  212. write_ds1302byte(com);         //寫命令地址
  213. write_ds1302byte(dat);         //寫數據
  214. rst=0; _nop_(); //禁止數據傳遞(操作完趕緊拉低防止誤操作)//空操作
  215. io=0; _nop_();         //釋放io
  216. clk=1; _nop_(); //將時鐘線電平置于已知狀態
  217. }

  218. /*****讀一個字節命令讀一個字節數據*****/
  219. uchar read_ds1302(uchar com)
  220. {
  221. uchar i,value;
  222. clk=1; _nop_();  //確保寫數據前時鐘線被拉高//空操作
  223. io=1; _nop_();          //數據線拉高
  224. rst=1; _nop_();  //啟動數據傳輸//空操作
  225. write_ds1302byte(com);        //寫入命令字后/進行讀操作之前要進行寫命令(地址),以確定是讀那個
  226. for(i=0;i<8;i++) //連續讀8個二進制位數據
  227. {
  228.   clk=0;                  //拉低時鐘線,形成脈沖下降沿讀數據
  229.   value=value>>1; //將value的各數據位右移1位,先讀出的是字節的最低位
  230.   if(io)                  //如果讀出的數據是1
  231.    value=value|0x80; //將1取出,寫在value的最高位
  232.   clk=1;                  //將clk拉高,為下次下降沿讀出數據做好準備
  233. }
  234. rst=0;                          //禁止數據傳輸
  235. return(value);          //將讀出的數據返回
  236. }

  237. /*****初始化DS1302*****/
  238. void ds1302_init(void)         
  239. {
  240.         uchar i,a,b;
  241. //        uchar CH;
  242.         write_ds1302(0x8e,0x00); //關閉寫保護(可以寫操作)
  243. //        write_ds1302(0x80,0x80); //裝初值前晶振停止,秒停
  244.         for(i=0;i<7;i++)
  245.         {
  246.       a=table_shijian[i]%10;   //個位
  247.       b=table_shijian[i]/10;   //十位
  248.       table_shijian[i]=a+b*16; //轉換為十六進制
  249.         }            
  250. // CH=read_ds1302(0x81); //先對ds1302進行讀回秒寄存器,
  251. //                                                
  252. // if(CH&0x80)                        //判斷秒寄存器最高位(CH)是否為1
  253. // {                                        //如為1,說明晶振停止工作,ds1302處于低功耗待命狀態,對它寫入初值
  254. //                                            //如為0,說明晶振開始振動,ds1302處于工作狀態,(說明在斷電時還起用了備用電池,所以ds1302還處于工作狀態)
  255. //                                            //如果每次上電要求都寫入初值,就無需這步操作,
  256. // for(i=0;i<7;i++)            //寫入數據(年周月日時分秒)
  257. // {
  258. //   write_ds1302(write_add[i],table_shijian[i]); //寫入命令,寫數據        
  259. // }
  260. // }
  261.         for(i=0;i<7;i++)         //連續寫7個數據(年周月日時分秒)
  262.     {
  263.       write_ds1302(write_add[i],table_shijian[i]); //寫入命令,寫數據//對號入座        
  264.     }


  265. //        write_ds1302(0x80,0x00); //啟動晶振開始走時,秒走
  266.         write_ds1302(0x90,0xa5); //使能充電,1個二極管,2K電阻
  267.         write_ds1302(0x8e,0x80); //打開寫保護(禁止寫操作)
  268. }

  269. //*****讀取時間*****/
  270. void read_rtc(void)         
  271. {
  272. uchar i;
  273. for(i=0;i<7;i++)         //連續讀7個數據(年周月日時分秒)
  274. {
  275.   table_shijian[i]=read_ds1302(read_add[i]); //數據對應寄存器的地址
  276. }
  277. }

  278. /************顯示處理**************/
  279. void display(void)
  280. {
  281.   disp[0]=table_shijian[4]/16; /*時的十位*/
  282.   disp[1]=table_shijian[4]%16; /*時的個位*/         
  283.   /*disp[2]=10;*/                                                   
  284.   disp[2]=table_shijian[5]/16; /*分的十位*/
  285.   disp[3]=table_shijian[5]%16; /*分的個位*/         
  286.   /*disp[5]=10; */                                            
  287.   disp[4]=table_shijian[6]/16; /*秒的十位*/
  288.   disp[5]=table_shijian[6]%16; /*秒的個位*/                  
  289. }                                                                                 
  290. /*****顯示時間*****/
  291. void display_shijian(void)      
  292. {
  293.   uchar i;
  294.   for(i=0;i<6;i++)          /*連續寫入6位,時時分分秒秒*/
  295.   {
  296.         P1=smg_we[i];       /*數碼管位選*/
  297.         P2=smg_du[disp[i]]; /*數碼管段選*/
  298.         delay(2); /*延時*/
  299.         P2=0xff;  /*消隱*/
  300. //        delay(2); /*延時*///這個延時影響數碼管閃爍
  301.   }
  302. }
復制代碼





分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:1 發表于 2015-1-14 09:39 來自手機 | 只看該作者
極有可能是精振頻率不準1天快12秒,可以嘗試采用高精度的,,晶體震蕩器。或者,在程序中修正誤差
回復

使用道具 舉報

板凳
ID:67519 發表于 2015-1-14 23:32 | 只看該作者
admin 發表于 2015-1-14 09:39
極有可能是精振頻率不準1天快12秒,可以嘗試采用高精度的,,晶體震蕩器。或者,在程序中修正誤差

晶振更換正在測試中,還有按鍵掃描函數如何修改,望指點...
回復

使用道具 舉報

地板
ID:72243 發表于 2015-1-15 00:27 | 只看該作者
我的晶振也不準,一天慢7秒左右

評分

參與人數 1黑幣 +30 收起 理由
admin + 30 回帖助人的獎勵!

查看全部評分

回復

使用道具 舉報

5#
ID:86421 發表于 2015-10-12 21:05 | 只看該作者
晶振不對的話就亂加
回復

使用道具 舉報

6#
ID:92285 發表于 2015-10-12 22:13 | 只看該作者
晶振應該有問題
回復

使用道具 舉報

7#
ID:92319 發表于 2015-10-13 11:48 | 只看該作者
極有可能是精振頻率不準1天快12秒,可以嘗試采用高精度的,,晶體震蕩器。或者,在程序中修正誤差等等
回復

使用道具 舉報

8#
ID:92363 發表于 2015-10-13 19:55 | 只看該作者
晶振應該有問題
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 国产精品色| 亚洲国产专区 | 国产亚洲精品久久19p | 国产成人av一区二区三区 | 日韩手机在线看片 | 亚洲欧美视频 | 国产清纯白嫩初高生视频在线观看 | 爱爱视频在线观看 | 色婷婷一区二区三区四区 | 国产精品久久久久久久久久久新郎 | 中文字幕在线第一页 | 久久一区精品 | 亚洲欧洲成人在线 | 久久精品一 | 国产免费一区二区 | 久久aⅴ乱码一区二区三区 亚洲国产成人精品久久久国产成人一区 | 国产一区二区精品在线 | 国产精品福利一区二区三区 | 国产精品高清一区二区 | 久久精品久久久久久 | 成人在线视频免费观看 | 成人性视频免费网站 | 久久久久久免费毛片精品 | 亚洲一区| 国产精品国产三级国产aⅴ原创 | 一区二区三区久久久 | 黄色一级大片在线免费看产 | 日本精品免费在线观看 | 一区二区高清 | 日韩视频在线播放 | 亚洲视频在线观看 | 免费看一级毛片 | 日韩亚洲欧美综合 | 91视视频在线观看入口直接观看 | 黄网站在线观看 | 一区二区av| 午夜在线免费观看 | 欧美一级视频免费看 | heyzo在线| 日韩精品在线免费 | 免费看黄色小视频 |