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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

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

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


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

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


原理圖和實物圖引腳一一對應,我們可以選擇1腳輸出,4腳接地(對角接通)4個按鍵的4號腳連接在一起并且引出一個插針到時候直接接單片機的GND完成接地,再把每個按鍵的1號腳用插針引出來,接代碼里定義的按鍵引腳。
在這里我給大家看一下DS12C887的芯片接法!

我從左邊最上邊開始逆時針轉一圈來說明各引腳的接法
從第四引腳開始接4-11為數據傳輸,接單片機的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
現在DS12C887模塊的準備工作都完成了。只剩下LCD1602的接線部分,原理圖如下

1602液晶上都有每個管腳的名稱,可以對照著原理圖來接線

從左向右,1腳接地,2腳接vcc,3腳接電位器的第二腳,rs接單片機的P3^5,rw接地,E接單片機的P3*4,D0-D7接單片機的P2口,A、K為背光電源,A接vcc,K接gnd。至此所有外接模塊安裝包括接口對應引腳都完成了。

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

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

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

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

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

電位器焊接背面圖.JPG (2.86 MB, 下載次數: 95)

電位器焊接背面圖.JPG

電位器阻值大小圖.JPG (1.45 MB, 下載次數: 105)

電位器阻值大小圖.JPG

電位器引腳圖.JPG (1.5 MB, 下載次數: 108)

電位器引腳圖.JPG

電位器焊接正面圖.JPG (2.05 MB, 下載次數: 112)

電位器焊接正面圖.JPG

DS12C887背面焊接圖.JPG (2.49 MB, 下載次數: 110)

DS12C887背面焊接圖.JPG

DS12C887正面焊接圖.JPG (1.71 MB, 下載次數: 110)

DS12C887正面焊接圖.JPG

評分

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

查看全部評分

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

使用道具 舉報

沙發
ID:897960 發表于 2021-6-17 16:39 | 只看該作者
有什么問題,大家可以在底下留言評論,我都會回復大家的
回復

使用道具 舉報

板凳
ID:328014 發表于 2021-6-20 20:34 | 只看該作者
好資料,51黑有你更精彩!!!你的DS12C887時間準確度怎么樣?一月大約有多少誤差呢
回復

使用道具 舉報

地板
ID:940278 發表于 2021-6-20 20:49 來自手機 | 只看該作者
Lzxhmxy1839 發表于 2021-6-17 16:39
有什么問題,大家可以在底下留言評論,我都會回復大家的

謝謝樓主

回復

使用道具 舉報

5#
ID:940278 發表于 2021-6-20 21:28 | 只看該作者
好資料,51黑這網站太棒了
回復

使用道具 舉報

6#
ID:941161 發表于 2021-6-20 23:01 | 只看該作者
太酷炫了,牛 51黑有你更精彩!!!
回復

使用道具 舉報

7#
ID:897960 發表于 2021-6-22 15:11 | 只看該作者
51hei團團 發表于 2021-6-20 20:34
好資料,51黑有你更精彩!!!你的DS12C887時間準確度怎么樣?一月大約有多少誤差呢

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

使用道具 舉報

8#
ID:897960 發表于 2021-6-22 15:12 | 只看該作者

沒事沒事,大家也是互相學習
回復

使用道具 舉報

9#
ID:897960 發表于 2021-6-22 15:12 | 只看該作者
此用戶不存在 發表于 2021-6-20 23:01
太酷炫了,牛 51黑有你更精彩!!!

加油,一起努力
回復

使用道具 舉報

10#
ID:58647 發表于 2021-7-6 18:20 | 只看該作者
這注釋,詳細,贊!
回復

使用道具 舉報

11#
ID:1011444 發表于 2022-5-23 13:42 | 只看該作者
程序注釋詳細,格式清晰,寫得好!
回復

使用道具 舉報

12#
ID:977804 發表于 2022-5-23 18:59 來自手機 | 只看該作者
12887還是很準確的,實際使用一個問題是引腳多,一個是備用電池難更換
回復

使用道具 舉報

13#
ID:109865 發表于 2023-6-3 08:16 來自手機 | 只看該作者
1重新上電后為啥時間數據沒有保存,問題出在哪,能不能給我指點一下
回復

使用道具 舉報

14#
ID:253767 發表于 2023-6-3 09:13 | 只看該作者
您太行了,厲害!
回復

使用道具 舉報

15#
ID:109865 發表于 2023-6-3 13:04 | 只看該作者
中斷使用的外部中斷1,但是代碼是interrupt 0,應該是interrupt 2,否則鬧鐘不好使
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 免费av在线网站 | 中文字幕亚洲精品 | 日本电影韩国电影免费观看 | 四虎影院免费在线 | 免费视频一区二区 | 一区二区成人在线 | 欧美男人天堂 | 国产在线1 | 成人网在线 | 性色综合| 国产精品美女久久久久久久久久久 | 国产精品久久亚洲 | 欧美日韩一区二区视频在线观看 | 怡红院免费的全部视频 | 91视频入口| 成人在线视频一区 | 91在线观看 | 秋霞电影一区二区三区 | 欧美一级免费看 | 国产在线精品一区二区 | 青青草一区二区三区 | 亚洲精品欧美精品 | 午夜精品一区二区三区免费视频 | 羞羞视频免费观 | 日日摸日日碰夜夜爽亚洲精品蜜乳 | 欧美精品乱码久久久久久按摩 | 日韩欧美国产精品一区二区三区 | 日韩在线小视频 | 久久精品国产一区二区电影 | 一区二区三区在线免费观看 | 国产一级特黄aaa大片评分 | 日韩中文字幕第一页 | 久久亚洲天堂 | 国产日韩91 | 久操福利 | 日产精品久久久一区二区福利 | 亚洲国产精品一区二区第一页 | 色爱区综合 | 久久国产精品一区二区三区 | 天堂一区二区三区四区 | 91精品午夜窝窝看片 |