找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4671|回復(fù): 14
收起左側(cè)

利用單片機最小系統(tǒng)外接DS12C887在LCD1602上顯示實時時鐘

  [復(fù)制鏈接]
ID:897960 發(fā)表于 2021-6-15 14:44 | 顯示全部樓層 |閱讀模式
- 我在上一篇文章中焊接了單片機最小系統(tǒng)板,并且成功驅(qū)動了LCD1602,我沒有在最后展示LCD顯示部分,就放到這篇文章在外接DS12C887的情況下和大家分享一下。
- 需要準(zhǔn)備的模塊如下:
- 1.單片機的最小系統(tǒng)板(最好有復(fù)位電路)另外20引腳(地)和40引腳vcc要多引出來6個(后面接杜邦線很多地方要用)
- 2.DS12C887時鐘芯片(24腳的)
- 3.LCD1602模塊
這里的DS12C887買回不能直接用,得像51芯片一樣焊接個底座出來,旁邊兩列焊接兩列排針,作為芯片的引腳。焊接好的效果圖如下


因為要驅(qū)動LCD1602,電位器也是必不可少的,我把電位器單獨焊接在了另外一塊板子上,這個焊接地方?jīng)]有要求,合理安排空間即可,焊接電位器也要利用排針引出三個角,對于3296型電位器的各引腳說明如下1腳VCC,3腳GND,2腳接輸出。電位器的大小選擇位10k,如圖

還需要準(zhǔn)備4個輕觸按鍵,因為設(shè)置時鐘時,需要選擇功能、增大鍵、減小鍵、鬧鐘查看鍵(我的板子上沒有焊接蜂鳴器,所以鬧鐘到點后,不會響,蜂鳴器是一個比較簡單的模塊,代碼里面都有定義,我在焊接的時候把他先忽視了,需要的話,外加上蜂鳴器模塊,看一下程序里的引腳定義就可以)
4個輕觸按鍵的接法從上到下排列,分別為功能選擇、增大、減小、鬧鐘查看。此處的焊接為選擇每個按鍵的兩個對角引腳,每個按鍵選擇的兩個引腳要相同,從上到下在板子上安插好,
按鍵圖.png 按鍵原理圖.png

原理圖和實物圖引腳一一對應(yīng),我們可以選擇1腳輸出,4腳接地(對角接通)4個按鍵的4號腳連接在一起并且引出一個插針到時候直接接單片機的GND完成接地,再把每個按鍵的1號腳用插針引出來,接代碼里定義的按鍵引腳。
在這里我給大家看一下DS12C887的芯片接法!
DS12C887實物圖.png DS12C887引腳圖.png
我從左邊最上邊開始逆時針轉(zhuǎn)一圈來說明各引腳的接法
從第四引腳開始接4-11為數(shù)據(jù)傳輸,接單片機的P0口,12腳接單片機20腳的GND。
13腳cs接P1^4
14腳as接P1^5
15腳rw接P1^6
17腳ds接P1^7
18腳RESET接VCC
19腳IRQ接P3^3
24腳接VCC
現(xiàn)在DS12C887模塊的準(zhǔn)備工作都完成了。只剩下LCD1602的接線部分,原理圖如下
1602接口.png
1602液晶上都有每個管腳的名稱,可以對照著原理圖來接線
1602實物圖.JPG
從左向右,1腳接地,2腳接vcc,3腳接電位器的第二腳,rs接單片機的P3^5,rw接地,E接單片機的P3*4,D0-D7接單片機的P2口,A、K為背光電源,A接vcc,K接gnd。至此所有外接模塊安裝包括接口對應(yīng)引腳都完成了。

```c
/*總體要求*/
/*在1602上顯示年月日星期時分秒,并且按照秒來實時更新顯示
  可以鬧鐘設(shè)定,到點報警功能,報警響起時,任意鍵可以取消報警
  四個按鍵,根據(jù)功能可以調(diào)節(jié)參數(shù),分別為功能鍵,數(shù)值增大鍵,數(shù)值減少鍵,鬧鐘查看鍵,
  每次按鍵按下,蜂鳴器都會滴一聲,
  利用DS12C887實現(xiàn)斷電后,再次上電,時間仍可以準(zhǔn)確顯示 */
  /*另外這個程序中文部分是學(xué)習(xí)了一個半月C語言的人的理解,難免有錯誤的地方
  如果你想移植程序,除了開頭的各種腳需要修改,程序里面1602和DS12C887的寫指令寫數(shù)據(jù),讀指令讀數(shù)據(jù)的IO口也要修改
  應(yīng)該是有4~6處,一定要注意,不然你的程序不會亮起來,然后初始化部分,記得初始化后去掉,但是仿真的時候不要去掉,去掉沒法顯示*/
  /*非常非常非常重要的一個細(xì)節(jié),總線上要加    AD[0..7]         這個名字,如果沒有永遠(yuǎn)也仿真不起來*/
#include<reg52.h>                         //52系列單片機機頭文件
#define uchar unsigned char               //宏定義 定義一個無符號字符型數(shù)據(jù)
#define uint  unsigned int                       //宏定義 定義一個無符號整型數(shù)據(jù)
sbit lcdrs=P3^5;                          //自定義數(shù)據(jù)/命令選擇端口
sbit lcden=P3^4;                          //自定義使能信號
//sbit dula=P2^6;
//sbit wela=P2^7;                                          /*P0口接液晶1602和時鐘芯片DS12C887的AD0-AD7*/
sbit beep=P2^3;                           //蜂鳴器。有的按鍵接rd為低電平,就需要也定義一下rd,我這里面四個按鍵采用的是接地的結(jié)構(gòu)!
sbit dscs=P1^4;                                                          //定義地址選通輸入端 (讀到那里去)
sbit dsas=P1^5;                                                          //定義芯片片選端           (讀哪個芯片)
sbit dsrw=P1^6;                                                          //定義讀數(shù)據(jù)允許輸入腳,這里mot接地        (讓不讓讀的開關(guān))
sbit dsds=P1^7;                                                  //定義中斷請求輸出
sbit dsirq=P3^3;                                                           //定義讀允許輸入           (讓讀以后,我來輸入數(shù)據(jù))
sbit lcdrd=P3^7;                                                

sbit s1=P1^0;                                  //功能鍵        
sbit s2=P1^1;                                                          //數(shù)值增大鍵
sbit s3=P1^2;                                                          //數(shù)值減少鍵
sbit s4=P1^3;                                                          //鬧鐘查看鍵
                                                                                  //因為功能鍵要8次才能推出,這里可以加一個直接退出按鍵,可以放在外部中斷上
bit    flag1, flag_ri;                                      //定義兩個位變量
uchar  count,s1num,flag,t0_num;                             //定義幾個無符號字符型數(shù)據(jù),用到時再解釋定義干啥用的
char   miao,shi,fen,year,month,day,week,amiao,afen,ashi;    //定義幾個字符型數(shù)據(jù),這個基本上都能理解。
uchar  code table[]=" 20  -  -      ";                          //讓液晶固定顯示的內(nèi)容
uchar  code table1[]="      :  :  ";                                //讓液晶固定顯示的內(nèi)容
void   write_ds(uchar, uchar);                                            //函數(shù)申明           寄存器初始化
void   set_alarm(uchar, uchar, uchar);                            //函數(shù)申明           設(shè)定鬧鐘
void   read_alarm();                                                                //函數(shù)申明           讀報警器
void   set_time();                                                                    //函數(shù)申明       寄存器初始化
void   delay(uint z)                                                                //延時函數(shù)
{                                                                                 
  uint x,y;                                                                  //定義兩個無符號整形數(shù)
  for(x=z;x>0;x--)                                                  //如果x>0,則y執(zhí)行110次
     for(y=110;y>0;y--);                                  //本小段為單位是1ms的延時
}
void di()                                                                  //蜂鳴器報警
{
beep=0;                                                                  //低電平有效,蜂鳴器開始蜂鳴
delay(100);                                                          //延時100毫秒,響0.1秒
beep=1;                                                                  //蜂鳴器停止鳴叫
}
void write_com(uchar com)                                   //寫液晶命令函數(shù)
{
  lcdrs=0;                                                                   //rs低電平,表示要寫命令
  lcden=0;                                                                   //en低電平,表示為了下面送入數(shù)據(jù),防止此時還是高電平,無法制造高脈沖
  P2=com;                                                                   //D0-D7我接的是P0上面,數(shù)據(jù)送給它
  delay(3);                                                                   //延時3ms
  lcden=1;                                                                   //en高電平,延時三秒        再變成低電平,完成一次高脈沖,使數(shù)據(jù)送入液晶顯示屏
  delay(3);                                                                   //表示接下來,液晶顯示屏可以過來讀數(shù)據(jù)了
  lcden=0;
}
void write_date(uchar date)                                   //寫液晶數(shù)據(jù)函數(shù)
{
lcdrs=1;                                                                   //高電平表示要寫數(shù)據(jù)
lcden=0;                                                                   //en低電平,表示為了下面送入數(shù)據(jù),防止此時還是高電平,無法制造高脈沖
P2=date;                                                                   //D0-D7我接的是P0上面,數(shù)據(jù)送給它
delay(3);                                                                   //延時3ms
lcden=1;                                                                   //en高電平,延時三秒        再變成低電平,完成一次高脈沖,使數(shù)據(jù)送入液晶顯示屏
delay(3);                                                                   //表示接下來,液晶顯示屏可以過來讀數(shù)據(jù)了
lcden=0;
}
void init()                                //液晶初始化
{
  uchar  num;                                                           //定義一個字符
  EA=1;                                                                           //打開全局中斷控制
  EX1=1;                                                                   //打開外部中斷1中斷
  IT1=1;                                                                   //設(shè)置負(fù)跳變沿觸發(fā)中斷
  flag=0;                                                                   // 自定義字符全部歸零,為了方便實用
  flag1=0;
  s1num=0;                                                                        //鍵盤按下的次數(shù)
  week=1;                                                                   //星期顯示最低也是周一的一
  lcden=0;                                                                   //使能信號定義為零,表示還沒有數(shù)據(jù)
  lcdrd=0;
//  dula=0;//關(guān)閉數(shù)碼管顯示
//        wela=0;
  write_ds(0x0A,0x20);                                           //首次使用ds12c887時使用,以后不必在寫。打開振蕩器
  write_ds(0x0B,0x26);                                            // 設(shè)置24小時模式,數(shù)據(jù)二進(jìn)制格式,開啟鬧鐘中斷。
                                            //0A,0B表示地址,20,26翻譯成二進(jìn)制是00100000,00100110對應(yīng)著對著寄存器A和B從D7-D0
  set_time();                                                           //設(shè)置默認(rèn)上電時間
  write_com(0x38);                                                   //設(shè)置16x2顯示,5x7點陣,8位數(shù)據(jù)接口
  write_com(0x0c);                                                   //設(shè)置開顯示,不顯示光標(biāo)
  write_com(0x06);                                                   //寫一個字符后,地址指針自動加1
  write_com(0x01);                                                   //顯示清0,數(shù)據(jù)指針清0

  write_com(0x80);                                                   //設(shè)置數(shù)據(jù)指針位置,此處時數(shù)據(jù)指針第一行,第一處
  for(num=0;num<15;num++)                                   //<15原因是第一行顯示的數(shù)字或者空格一共14個
  {
    write_date(table[num]);                                   //把要顯示的數(shù)據(jù)送入到液晶的第一行
        delay(1);                                                           //延遲一毫秒
  }

    write_com(0x80+0x40);                                   //設(shè)置數(shù)據(jù)指針位置,此處時數(shù)據(jù)指針第二行,第一處
    for(num=0;num<11;num++)                                   //<11原因是第二行顯示的數(shù)字或者空格一共10個
  {
    write_date(table1[num]);                                   //把要顯示的數(shù)據(jù)送入到液晶的第二行
        delay(1);                                                           //延遲一毫秒
  }
}
void write_sfm(uchar add,char date)                   //1602液晶刷新時分秒函數(shù)4為時,7為分,10為秒          ,4.7.10均是顯示位置
{   
   char shi,ge;                                                           //定義兩個數(shù),來表示十位數(shù)和個位數(shù)
   shi=date/10;                                                           // 要送去顯示的十位
   ge=date%10;                                                           //要送去顯示的個位  
   write_com(0x80+0x40+add);                                   //時間是在第二行顯示,所以是加0X40,在add處顯示
   write_date(0x30+shi);                                   //shi和ge都是整形數(shù)值,但是液晶1602是內(nèi)置ASCII表格,0在第048位
   write_date(0x30+ge);                                           //轉(zhuǎn)成十六進(jìn)制就是0x30,
}
/*這個地方可能會有人迷糊,設(shè)置時分秒,怎么只設(shè)置十位和個,好像給人的感覺就是只設(shè)置時位,和分位,秒位怎么不設(shè)置,
實際上是,這里寫入并顯示的是  把時的十位和個位,分的十位和個位,秒的十位和個位,分別送去進(jìn)行運算 ,然后先寫命令確定位置,
再寫數(shù)據(jù),用來顯示,下面一個子函數(shù)也是同樣的道理*/
void write_nyr(uchar add,char date)                   //1602液晶刷新年月日函數(shù),3為年,6為月9為天         ,369也分別是位置
{   
   char shi,ge;                                                           //定義兩個數(shù),來表示十位數(shù)和個位數(shù)
   shi=date/10;                                                           // 要送去顯示的十位
   ge=date%10;                                                           //要送去顯示的個位  
   write_com(0x80+add);                                   //時間是在第二行顯示,所以是加0X40,在add處顯示
   write_date(0x30+shi);                                   //shi和ge都是整形數(shù)值,但是液晶1602是內(nèi)置ASCII表格,0在第048位
   write_date(0x30+ge);                                           //轉(zhuǎn)成十六進(jìn)制就是0x30,
}   /*實際上到了主函數(shù),時分秒,年月日會有六個子函數(shù)進(jìn)行分別調(diào)用,這里用兩個子函數(shù)來表示,不能用一個的原因是顯示的內(nèi)容不在一行,
主要是寫入命令的位置不一樣,大家可以觀察一下*/
void write_week(char we)                                        //寫液晶1602星期顯示函數(shù)   
{
  write_com(0x80+12);                                                //讓we在0x80+12這個位置顯示
  switch(we)                                                                //多分支結(jié)構(gòu)的條件選擇語句,we等于幾就去執(zhí)行幾號分支
  {
   case 1:write_date('M');                                   //寫入M。整個的意思是如果we等于1,則顯示MON,即星期一
          delay(5);                                                   //延時5毫秒后寫入O
                  write_date('O');                                   //寫入O
          delay(5);                                                   //延時5毫秒后寫入N
                write_date('N');                                   //寫入N
          break;                                                   //間斷,為了和后面分開
   case 2:write_date('T');                                   //寫入T。整個的意思是如果we等于2,則顯示TUE,即星期二
          delay(5);                                                   //延時5毫秒后寫入U
                  write_date('U');                                   //寫入U
          delay(5);                                                   //延時5毫秒后寫入E
                write_date('E');                                   //寫入E
          break;                                                   // 間斷,為了和后面分開
   case 3:write_date('W');                                   //寫入W。整個的意思是如果we等于3,則顯示W(wǎng)ED,即星期三
          delay(5);                                                   //延時5毫秒后寫入E
                  write_date('E');                                   //寫入E
          delay(5);                                                   //延時5毫秒后寫入D
                write_date('D');                                   //寫入D
          break;                                                   //間斷,為了和后面分開
   case 4:write_date('T');                                   //寫入T。整個的意思是如果we等于4,則顯示THU,即星期四
          delay(5);                                                   //延時5毫秒后寫入H
                  write_date('H');                                   //寫入H
          delay(5);                                                   //延時5毫秒后寫入U
                write_date('U');                                   //寫入U
          break;                                                   //間斷,為了和后面分開
   case 5:write_date('F');                                   //寫入F。整個的意思是如果we等于5,則顯示FRI,即星期五
          delay(5);                                                   //延時5毫秒后寫入R
                  write_date('R');                                   //寫入R
          delay(5);                                                   //延時5毫秒后寫入I
                write_date('I');                                   //寫入I
          break;                                                   //間斷,為了和后面分開
   case 6:write_date('S');                                   //寫入S。整個的意思是如果we等于6,則顯示SAT,即星期六
          delay(5);                                                   //延時5毫秒后寫入A
                  write_date('A');                                   //寫入A
          delay(5);                                                   //延時5毫秒后寫入T
                write_date('T');                                   //寫入T
          break;                                                   //間斷,為了和后面分開
   case 7:write_date('S');                                   //寫入S。整個的意思是如果we等于7,則顯示SUN,即星期日
          delay(5);                                                   //延時5毫秒后寫入U
                  write_date('U');                                   //寫入U
          delay(5);                                                   //延時5毫秒后寫入N
                write_date('N');                                   //寫入N
          break;                                                   //間斷,為了和后面分開
        
   }
}
void keyscan()                                                           //數(shù)字時鐘按鍵掃描函數(shù)
{
   if(flag_ri==1)                                                   //如果標(biāo)志位,鬧鐘等于1,則蜂鳴器會響 ,這一句和按鍵掃描沒有關(guān)系,主要是為了任意鍵可以消除
                                           //鬧鐘的報警,可以理解為,為鬧鐘取消而增加的一個掃描小程序。
   {
        if((s1==0)||(s2==0)||(s3==0)||(s4==0))        //如果s1-s4有一個為零,低電平         ||這個符號是關(guān)系運算符, 或的意思,有一個是低電平,則進(jìn)行下一步。
        {
         delay(5);                                                                //延時去抖動
         if((s1==0)||(s2==0)||(s3==0)||(s4==0))        //再次確認(rèn),如果s1-s4有一個為零,低電平
         {
           while(!(s1&&s2&&s3&&s4));                        /*/如果他們運算的結(jié)果為0         ,當(dāng)鬧鐘響起,就會進(jìn)入這個按鍵掃描程序,這沒有按下鍵盤的時候,
           就會運行到這里,進(jìn)行判斷循環(huán),一直等在,四個按鍵,有一個為0,這個語句就會判斷為假,進(jìn)行下一步運算,&&這個符號是關(guān)系運算的 與,
           一個值為零,則整體結(jié)果運算為0*/
           di();                                                            //則蜂鳴器會響,鬧鐘有自己的蜂鳴程序,這里有個DI主要原因是,每次按鍵 都會響,這是事先規(guī)定號的
           flag_ri=0;                                                        //清除報警標(biāo)志
         }
        }
   }

  if(s1==0)                                                                          //檢測按鍵s1
  {
   delay(5);                                                                  //延時5毫秒,也可叫延時去抖動。
   if(s1==0)                                                                  //再次檢測按鍵s1
   {
    s1num++;                                                                  //定義為鍵盤按下的次數(shù)
        if(flag1 == 1)                                                          //這個是用來鬧鐘的,如果等予1,說明現(xiàn)在是在設(shè)置鬧鐘值,從下面來看這個只能調(diào)節(jié)每天的鬧鐘,不能調(diào)節(jié)年月
           if(s1num == 4)                                                 //因為只能調(diào)節(jié)時分秒,讓他們在里面循環(huán)
              s1num=1;                                                          //這個地方我卡了幾天,大家要綜合前后文,明白flag1是鬧鐘被按下了,flag是為了跳出主程序循環(huán),為了設(shè)置時間
        flag=1;                                                                      //按鍵計數(shù)以后,則這個位變量變成1,
        while(!s1);                                                                  /*!s1 的意思是取s1相反的數(shù),是用來測試判斷按鍵按下后有沒有松開,松開則計數(shù)一次后,電平
                                                                       變成高電平,說明此時已經(jīng)松開,也確定了s1num的具體數(shù)值,也就是按了幾下*/
        di();                                                                          //每按下一次則響一聲
        switch(s1num)                                                          //判斷是按了幾下,則選擇什么位置光標(biāo)點閃爍。
        {
                case 1:write_com(0x80+0x40+10);                  //很明顯這是顯示屏第二行的顯示指令,10  說明光標(biāo)調(diào)節(jié)的是秒
                       write_com(0x0f);                       /*/不管你按的再快,光標(biāo)也會從第一步開始,所以把 開顯示,顯示光標(biāo),光標(biāo)閃爍  這個lcd的這個
                                                                                             指令設(shè)置放在這里        */
                           break;                                                  //會不停的跳出,再去問現(xiàn)在是按了幾下了,按了幾下,就會進(jìn)入對應(yīng)的里面,下面都是一樣的不解釋了。
                case 2:write_com(0x80+0x40+7);               /*這個就是光標(biāo)在分鐘上閃爍,(不光時分秒都是在他們的十位閃爍,
                                                       如果送的是兩位數(shù),LCD的指針可以自動加一,把個位也給顯示了)*/
                           break;
                case 3:write_com(0x80+0x40+4);               //這個是在小時的位置顯示閃爍
                           break;
                case 4:write_com(0x80+12);                           //這就是進(jìn)入顯示屏第一行了,在顯示星期的位置,第十位,最右邊,是調(diào)節(jié)星期的位置。
                           break;
                case 5:write_com(0x80+9);                             //日
                           break;
                case 6:write_com(0x80+6);                             //月
                           break;
                case 7:write_com(0x80+3);                               //年
                           break;
                case 8:s1num=0;                                                          //把按鍵數(shù)置零,等這個小程序運行完,則光標(biāo)不在閃縮,一切正常運行。相當(dāng)于不選擇任何位置。
                       write_com(0x0c);                                          //設(shè)置開顯示,不顯示光標(biāo)
                           flag=0;                                                          //等于0就是回到主程序的正常運行(可以參看以下主程序,更能方便理解)
                                /*下面的幾句基本一樣,明白一個就全明白了,這個地方主要是查表,查寄存器A,功能列表有時分秒,鬧鐘的也有時分秒,年月日他們分別
                                對應(yīng)的寄存器地址,比如秒對應(yīng)的是00H,分鐘對應(yīng)的是02H,所以0,2,4,6,7,8,9都是地址,往這個里面寫,就是寫的時分秒,
                                可能有人問,既然是00H,02H,為什么寫成0,2等等,其實是因為十六進(jìn)制和十進(jìn)制在0~9,書寫雖然有區(qū)別,但是結(jié)果都一樣*/
                           write_ds(0,miao);                                   
                           write_ds(2,fen);
                           write_ds(4,shi);
                           write_ds(6,week);
                           write_ds(7,day);
                           write_ds(8,month);
                           write_ds(9,year);
                           break;                                   //跳出
        }
   }
  }
  if(s1num!=0)                                            //測試不等于 0,也就是只有當(dāng)s1按下時才能檢測和用來啟動s2和s3.
  {
   if(s2==0)                                               //問S2按鍵有沒有按下
   {
        delay(1);                                                                                 //延時1毫秒
        if(s2==0)                                                                                 //再次來檢測
        {
          while(!s2);                                                                          //給s2取反
          di();                                                                                         //滴一聲
          switch(s1num)                                                                         //根據(jù)s1按下的次數(shù),來確定調(diào)節(jié)哪個位置
          {                                                                                                    //下面給大家解釋一組,應(yīng)該可以全部明白
           case 1:miao++;                                                                 //按鍵s2按一下,這里就會加一          設(shè)置秒鐘
                  if(miao==60)                                                          //如果加到了60 ,秒就會變成0
                             miao=0;
                     write_sfm(10,miao);                         //把秒的值經(jīng)過運算,送到LCD相應(yīng)的位置去顯示
                         write_com(0x80+0x40+10);                /*這一句是調(diào)用寫指令,因為指針把秒顯示完畢后,光標(biāo)就會在秒的個位,
                                                                 所以這一句是把光標(biāo)在拉回來,因為不能正好一下子就把秒的值設(shè)置的正好*/
                         break;                                                         //然后跳出,等待按鍵再次按下
           case 2:fen++;                                                     //設(shè)置分鐘
                  if(fen==60)                                             //分,秒都用到60,生活中并沒有60,這里也不能設(shè)置成59,但是可以改程序為>59.道理是一樣的
                             fen=0;
                         write_sfm(7,fen);
                         write_com(0x80+0x40+7);
                         break;
           case 3:shi++;                                                      //設(shè)置時鐘
                  if(shi==24)                                               //和上面一樣的道理
                             shi=0;
                          write_sfm(4,shi);
                          write_com(0x80+0x40+4);
                          break;
           case        4:week++;                                                  //設(shè)置星期
                  if(week ==8)                                              //當(dāng)按下第八次的時候,則8就會變成1
                             week=1;
                          write_week(week);
                          write_com(0x80+12);
                          break;
          case 5:day++;                                                            //設(shè)置天數(shù)
                 if(day==32)                          
                            day=1;
                         write_nyr(9,day);
                         write_com(0x80+9);
                         break;
         case 6:month++;                                               //設(shè)置月數(shù)
                if(month==13)
                           month=1;
                        write_nyr(6,month);
                        write_com(0x80+6);
                        break;
        case 7:year++;                                                            //設(shè)置年
               if(year==100)
                      year=0;
                         write_nyr(3,year);
                         write_com(0x80+3);
                         break;         
          }
    }
   }
   if(s3==0)                                               //上面是增大鍵,下面就是減少鍵
   {
        delay(1);                                               //延遲1毫秒
        if(s3==0)                                              //再次判斷有沒有按下
        {
          while(!s3);                                     //取相反數(shù),看看是不是為真
          di();
          switch(s1num)                                          //根據(jù)按鍵1,就可以確定光標(biāo)在什么位置,下面介紹和上面基本上一樣,
          {                                                                      //只不過沒有60了,反而有59,可以好好理解一下,其實很簡單這個地方,就不解釋了
           case 1:miao--;                                                   //設(shè)置秒鐘
                  if(miao==-1)
                             miao=59;
                     write_sfm(10,miao);
                         write_com(0x80+0x40+10);
                         break;
           case 2:fen--;                                                  //設(shè)置分鐘
                  if(fen==-1)
                             fen=59;
                         write_sfm(7,fen);
                         write_com(0x80+0x40+7);
                         break;
           case 3:shi--;                                                      //設(shè)置小時
                  if(shi==-1)
                             shi=23;
                          write_sfm(4,shi);
                          write_com(0x80+0x40+4);
                          break;
           case        4:week--;                                                      //設(shè)置星期
                  if(week==-0)
                             week=7;
                          write_week(week);
                          write_com(0x80+12);
                          break;
           case 5:day--;                                                      //設(shè)置天數(shù)
                  if(day==0)
                             day=31;
                           write_nyr(9,day);
                          write_com(0x80+9);
                          break;
           case 6:month--;                                                       //設(shè)置月數(shù)
                 if(month==0)
                            month=12;
                         write_nyr(6,month);
                         write_com(0x80+6);
                         break;
            case 7:year--;                                                         //設(shè)置年
                 if(year==-1)
                      year=99;
                         write_nyr(3,year);
                         write_com(0x80+3);
                         break;         
          }
    }
   }
  }
  if(s4==0)                                                         //這個地方是鬧鐘設(shè)置鍵
  {
   delay(5);                                                     //延時5毫秒
   if(s4==0)                                                     //再次判斷是否按下
   {
        flag1=~flag1;                                            //如果按下,則按鍵1程序,進(jìn)入時分秒的循環(huán),這里的講解和前面相呼應(yīng)。
        while(!s4);                                                     //取反是不是為真
        di();                                                             //為真說明,有按鍵按下,響一聲,
        s1num=0;                                                                                                
        /*調(diào)試仿真時發(fā)現(xiàn)如果按下了按鍵一  在按鬧鐘,然后取消鬧鐘,在按按鍵一,會不出現(xiàn)光標(biāo),為了讓鬧鐘和按鍵一不沖突,我添加這一句
        每當(dāng)我按下按鍵一,不管按幾次,只要按下按鍵4,都會讓光標(biāo)變成0位 */
        if(flag1==0)                                             //如果等于0,說明按得第二下,屬于退出鬧鐘設(shè)置。
        {
         flag=0;                                                                                                 //程序運行到這一步,說明運行完這個程序,就要回到主程序了,
                                                                 //把按鍵1標(biāo)志指令以后,本程序結(jié)束,可以進(jìn)入主程序,否則還要在去按鍵1,按幾下     
         write_com(0x80+0x40);                                                                         //把指針選擇第二行,第一位,
         write_date(' ');                                                                                 //寫入兩個空的符號,主要是為了區(qū)別狀態(tài),是調(diào)整時間還是設(shè)置鬧鐘
         write_date(' ');
         write_com(0x0c);                                                                                  //關(guān)閉光標(biāo)閃爍
         write_ds(1,miao);                                                                                  //把時分秒送到DS12C887,程序正常運行
         write_ds(3,fen);                                                                                  //這個時候的135要注意,可以看出是新設(shè)置鬧鐘值
         write_ds(5,shi);
        }
        else                                                                                                           //如果flag不等于0,則進(jìn)入這個程序,實際上程序都是先運行這個
        {                                                                                                                   //進(jìn)入鬧鐘設(shè)置
         read_alarm();                                                                                           //讀鬧鐘原來的數(shù)據(jù)
         miao=amiao;                                                                                           //分別送入時分秒
         fen=afen;
         shi=ashi;
         write_com(0x80+0x40);                                                                           //寫指令,把指針,也就是光標(biāo)位置放在第二排第一位
         write_date('R');                                                                                   //分別送入R  I送去顯示,可以區(qū)分現(xiàn)在是在調(diào)整時間,還是修改鬧鐘
         write_date('I');
         write_com(0x80+0x40+3);                                                                   /*這個地方還有一個指針,就會讓很多人不理解,其實這個地方設(shè)計很巧妙
                                                                   3號位置,正好是時鐘前面一位,然后再那邊閃爍,接著等待按鍵1,來選擇調(diào)整時分秒,
                                                                                                                           按一下變換一個位置,在3號位閃爍還不影響開始時的鬧鐘值*/
                                                                    
         write_sfm(4,ashi);                                                                                   //送到液晶去顯示
         write_sfm(7,afen);
         write_sfm(10,amiao);
        }
   }
  }
}
void write_ds(uchar add,uchar date)                                   //寫DS12C887函數(shù)
{
dscs=0;                                                                                                           //根據(jù)時序圖,把相應(yīng)的腳變化高低,片選端,低電平有效
dsas=1;                                                                                                           //地址選通輸入端
dsds=1;                                                                                                           //讀允許輸入腳
dsrw=1;                                                                                                                //寫輸入腳
P0=add;                                                                                                                //寫地址
dsas=0;
dsrw=0;
P0=date;                                                                                                            //寫命令
dsrw=1;
dsas=1;
dscs=1;
}
uchar read_ds(uchar add)                                                                           //讀DS12C887函數(shù)        ,這里沒有用void要注意
{
uchar ds_date;                                                                                                   //定義一個無符號函數(shù)
dsas=1;                                                                                                           //根據(jù)時序圖,進(jìn)行高低電平設(shè)置
dsds=1;
dsrw=1;
dscs=0;
P0=add;                                                                                                           //寫地址,確定要讀什么位置的值
dsas=0;
dsds=0;
P0=0xff;                                                                                                           //先把P1進(jìn)行置高,清理數(shù)據(jù)
ds_date=P0;                                                                                                        //把新的得到了  12c887里面的數(shù)值,賦值給ds_date
dsds=1;                                                                                                                //根據(jù)時序圖繼續(xù)設(shè)置電平
dsas=1;
dscs=1;
return ds_date;                                                                                           //誰調(diào)用它,什么位置調(diào)用的,就會把這個新得到的值在返回給他,
                                                                                                                           //看得出來只有讀鬧鐘值是調(diào)用了。
}
void set_time()                                                                                           //首次操作12c887時給寄存器初始化,完成后,要把這一段用 給屏蔽起來
{
write_ds(0,0);                                                                                                  //根據(jù)寄存器A,相當(dāng)于        所有的位置,全部顯示00。
write_ds(1,0);
write_ds(2,0);
write_ds(3,0);
write_ds(4,0);
write_ds(5,0);
write_ds(6,0);
write_ds(7,0);
write_ds(8,0);
write_ds(9,0);
}         
void read_alarm()                                                                                          //讀取鬧鐘值
{
amiao=read_ds(1);                                                                                           //根據(jù)寄存器A,分別把鬧鐘值讀出來,并且賦值給時分秒
afen=read_ds(3);
ashi=read_ds(5);
}
void main()                                                                                                         //主程序
{
init();                                                                                                          //調(diào)用初始化函數(shù)
while(1)                                                                                                          //為真不斷循環(huán),等待鬧鐘中斷
{
keyscan();                                                                                                           //按鍵子程序,不斷地掃描
if(flag_ri==1)                                                                                                   //如果有鬧鐘,則進(jìn)入這里
{
  di();
  delay(100);                                                                                                        //一直響 滴滴
  di();
  delay(500);
}
if((flag==0) && (flag1==0))                                                                   //如果按鍵標(biāo)志位和鬧鐘標(biāo)志位都為0,則繼續(xù)
{
  keyscan();                                                                                                   //按鍵繼續(xù)掃描
  year=read_ds(9);                                                                                           //把DS12C887里面的數(shù)值不斷讀取
  month=read_ds(8);
  day=read_ds(7);
  week=read_ds(6);
  shi=read_ds(4);
  fen=read_ds(2);
  miao=read_ds(0);
  write_sfm(10,miao);                                                                                   //這里把DS12c887的值不斷地寫入到lcd1602
  write_sfm(7,fen);
  write_sfm(4,shi);
  write_week(week);
  write_nyr(3,year);
  write_nyr(6,month);
  write_nyr(9,day);
}
}
}                                                                                                                        
void exter()interrupt 0                                                                            //中斷1程序
{
uchar c;                                                                                                                //定義一個無符號數(shù)值
flag_ri=1;                                                                                                                //鬧鐘中斷時間到了
c=read_ds(0x0c);                                                                                                //讀取c寄存器的值,表示響應(yīng)了中斷
}
在這里插入代碼片
電位器焊接背面圖.JPG
電位器阻值大小圖.JPG
電位器引腳圖.JPG
電位器焊接正面圖.JPG
DS12C887背面焊接圖.JPG
DS12C887正面焊接圖.JPG

評分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

回復(fù)

使用道具 舉報

ID:897960 發(fā)表于 2021-6-17 16:39 | 顯示全部樓層
有什么問題,大家可以在底下留言評論,我都會回復(fù)大家的
回復(fù)

使用道具 舉報

ID:328014 發(fā)表于 2021-6-20 20:34 | 顯示全部樓層
好資料,51黑有你更精彩!!!你的DS12C887時間準(zhǔn)確度怎么樣?一月大約有多少誤差呢
回復(fù)

使用道具 舉報

ID:940278 發(fā)表于 2021-6-20 20:49 來自手機 | 顯示全部樓層
Lzxhmxy1839 發(fā)表于 2021-6-17 16:39
有什么問題,大家可以在底下留言評論,我都會回復(fù)大家的

謝謝樓主

回復(fù)

使用道具 舉報

ID:940278 發(fā)表于 2021-6-20 21:28 | 顯示全部樓層
好資料,51黑這網(wǎng)站太棒了
回復(fù)

使用道具 舉報

ID:941161 發(fā)表于 2021-6-20 23:01 | 顯示全部樓層
太酷炫了,牛 51黑有你更精彩!!!
回復(fù)

使用道具 舉報

ID:897960 發(fā)表于 2021-6-22 15:11 | 顯示全部樓層
51hei團(tuán)團(tuán) 發(fā)表于 2021-6-20 20:34
好資料,51黑有你更精彩!!!你的DS12C887時間準(zhǔn)確度怎么樣?一月大約有多少誤差呢

ds12c887的誤差的話,官方話我就不說了,我在實驗的時候是是很準(zhǔn)確的,肉眼幾乎分辨不來
回復(fù)

使用道具 舉報

ID:897960 發(fā)表于 2021-6-22 15:12 | 顯示全部樓層

沒事沒事,大家也是互相學(xué)習(xí)
回復(fù)

使用道具 舉報

ID:897960 發(fā)表于 2021-6-22 15:12 | 顯示全部樓層
此用戶不存在 發(fā)表于 2021-6-20 23:01
太酷炫了,牛 51黑有你更精彩!!!

加油,一起努力
回復(fù)

使用道具 舉報

ID:58647 發(fā)表于 2021-7-6 18:20 | 顯示全部樓層
這注釋,詳細(xì),贊!
回復(fù)

使用道具 舉報

ID:1011444 發(fā)表于 2022-5-23 13:42 | 顯示全部樓層
程序注釋詳細(xì),格式清晰,寫得好!
回復(fù)

使用道具 舉報

ID:977804 發(fā)表于 2022-5-23 18:59 來自手機 | 顯示全部樓層
12887還是很準(zhǔn)確的,實際使用一個問題是引腳多,一個是備用電池難更換
回復(fù)

使用道具 舉報

ID:109865 發(fā)表于 2023-6-3 08:16 來自手機 | 顯示全部樓層
1重新上電后為啥時間數(shù)據(jù)沒有保存,問題出在哪,能不能給我指點一下
回復(fù)

使用道具 舉報

ID:253767 發(fā)表于 2023-6-3 09:13 | 顯示全部樓層
您太行了,厲害!
回復(fù)

使用道具 舉報

ID:109865 發(fā)表于 2023-6-3 13:04 | 顯示全部樓層
中斷使用的外部中斷1,但是代碼是interrupt 0,應(yīng)該是interrupt 2,否則鬧鐘不好使
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

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

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表