找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

帖子
查看: 12577|回復: 0
收起左側(cè)

單片機時鐘程序?qū)嶒瀳蟾?/span>

[復制鏈接]
ID:143490 發(fā)表于 2016-10-19 21:45 | 顯示全部樓層 |閱讀模式










單片機原理與應用


課程名稱:    單片機原理與應用               
設計題目:    LCD電子鐘                 
院    系:    電子信息工程學院                             
班    級:    自動化0706                    
設 計 者:    全宏宇                     
指導教師:                                 




一,設計目標
LCD顯示電子鐘的基本功能
1,實現(xiàn)時鐘功能;
2,實現(xiàn)鬧鈴功能;
3,實現(xiàn)秒表功能;
4,具有一定的計時精度。
LCD顯示電子鐘的基本要求
1,掌握單片機開發(fā)編程設計的基本流程;
2,了解Keil及Proteus軟件的基本使用;
3,了解LCD的基本使用;
4,學習單片機硬件制作。

二,具體實現(xiàn)
1,軟件平臺
1)Keil編程
Keil 的開發(fā)工具的使用的基本過程:
○1創(chuàng)建 C 或匯編語言的源程序;
○2編譯或匯編源文件;
○3糾正源文件中的錯誤;
○4從編譯器和匯編器連接目標文件;
○5測試連接的應用程序。
2)Proteus仿真
  Proteus軟件不僅具有其它EDA工具軟件的仿真功能,還能仿真單片機及外圍器件。它是目前最好的仿真單片機及外圍器件的工具。在編譯方面,它也支持IAR,Keil,PLAB等多種編譯器。

2,硬件開發(fā)平臺
JD51開發(fā)板的基本資料
○1 LED 電路,8 只獨立LED 發(fā)光管,可做指示或各種閃爍效果用。
○2 數(shù)碼管電路,4只共陽一體8 段數(shù)碼顯示管,可實現(xiàn)各種數(shù)據(jù)顯示,如計數(shù)、時鐘等。
○3蜂鳴器電路,可用于設計各種提示音、演奏音樂等。
○4鍵盤電路,學習按鍵控制相關(guān)編程。
○5 LCD 顯示電路,編程控制LCD 顯示。
○6串口電路,學習編程實現(xiàn)JD51 和PC 或其他符合該通信協(xié)議的電路之間的通信。
○7紅外電路,通過選配的紅外遙控器,學習紅外解碼并可實現(xiàn)紅外遙控JD51。
○8 溫度模塊電路,采用一線式溫度傳感器實現(xiàn)溫度的采集并可顯示在數(shù)碼管或者LCD 上,通過溫度數(shù)據(jù)處理便可實現(xiàn)溫度控制器功能。
○9除了以上提到的可編程電路本學習板還有一些常用的不可編程電路,包括電源電路、復位電路、晶振電路等。

    本次LCD電子鐘實驗用到其中的蜂鳴器,按鍵,LCD顯示接口。
3,總體設計
1)        基本資源的使用
本次實驗采用了89C52型單片機,1602LCD液晶顯示屏,蜂鳴器。為了實現(xiàn)時鐘,定時,鬧鐘,秒表的功能,用到了單片機的外部中斷,計時器中斷,及
I/O端口.
資源        功能
外部中斷        外部中斷INT1            模式選擇(時鐘,調(diào)時,秒表,鬧鐘)
        外部中斷INT0            秒表的暫停,清零
定時器        定時器T0            秒表,時鐘定時基準
        定時器T1            音樂鬧鈴的音符產(chǎn)生
I/O端口        P1,P2            LCD接口,蜂鳴器

2)軟件仿真
(1)程序設計的一些關(guān)鍵問題(具體參照后面的程序清單)
 ○1建立Keil工程時,注意對程序編譯環(huán)境進行設置;
 設置內(nèi)容包括器件,頻率,產(chǎn)生hex文件等。

  ○2LCD管腳及控制字;
LCD管腳的定義


 控制字

1602液晶模塊的讀寫操作,屏幕和光標的操作都是通過指令編程來實現(xiàn)的。
指令1:清顯示,指令碼01H,光標復位到地址00H位置
指令2:光標復位,光標返回到地址00H
指令3:光標和顯示位置設置I/D,光標移動方向,高電平右移,低電平左移,S:屏幕上所有文字是否左移或右移,高電平表示有效,低電平表示無效。
指令4:顯示開關(guān)控制。D:控制整體的顯示開與關(guān),高電平表示開顯示,低電平表示關(guān)顯示。C:控制光標的開與關(guān),高電平表示有光標,低電平表示無光標 B:控制光標是否閃爍,高電平閃爍,低電平不閃爍。
指令5:光標或顯示移位 S/C :高電平時顯示移動的文字,低電平時移動光標
指令6:功能設置命令 DL:高電平時為4位總線,低電平時為8位總線 N:低電平時為單行顯示,高電平時為雙行顯示,F(xiàn):低電平時顯示5X7的點陣字符,高電平時顯示5X10的顯示字符。
指令7:字符發(fā)生器RAM地址設置。
指令8:DDRAM地址設置。
指令9:讀忙信號和光標地址 BF:忙標志位,高電平表示忙,此時模塊不能接收命令或數(shù)據(jù),如果為低電平表示不忙。
  ○3LCD實現(xiàn)滾動顯示;
 方法一:采用LCD1602控制命令,顯示后畫面移動一個字符;
 方法二:循環(huán)使用顯示不同位置,形成滾動效果。
○5秒表
主要是產(chǎn)生計時基準0.01秒,有了基準之后需要解決的問題是如何實現(xiàn)有效的暫停,清零(達到精準動作),采用中斷是很不錯的結(jié)果。
 ○6鬧鈴
 主要是如何實現(xiàn)鬧鈴關(guān)閉的邏輯,if(f&&g)語句可以實現(xiàn)這一動作。
 ○7提高計時精度
  本程序除了調(diào)時模式外,其他模式的時候時鐘都在跑動,提高了因模式轉(zhuǎn)換而導致的時間精度降低。
(2)Proteus仿真
在Proteus中畫出如下電路圖,添加hex文件,進行虛擬仿真。

2)        開發(fā)板運行調(diào)試
  在JD51板上燒制程序,根據(jù)實際的效果,對中斷的反應時間,顯示效果做出了調(diào)整,整體效果不錯,只是音樂的效果不佳,主要是由于如果將蜂鳴器換成揚聲器效果會好些,還可以在程序中增加節(jié)拍來增加音樂效果。
4,硬件制作
根據(jù)仿真電路圖購買元件進行焊接,下載程序效果后,液晶顯示器顯示亂碼,檢查電路后已無連接錯誤,但功能依然沒有實現(xiàn),相關(guān)檢查在進行中。

三,設計體會
 本次課程設計系統(tǒng)地學習了單片編程開發(fā)及實際電路的制作。學習了Keil的C語言編程的基本知識,Proteus仿真軟件的模擬仿真,JD51開發(fā)實驗板的使用,本次課設,時間了較多的其他案例,比較全面的掌握了單片機的運營,包括編程,電路,LCD器件等,在知識上有了很多的長進。
 本次課程設計還有很多其他收獲,鍛煉了自學的能力,特別是動手實踐方面的東西,讓我深深感受到理論與實際的差距,實際當中會有一些小的問題,這些問題是意想不到的,需要去思考,去解決,這是很鍛煉人的。







四,程序
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define ulong unsigned long
#define uint  unsigned int
uchar idata     welcome[16]={"    clock       "};                //定義第一行顯示數(shù)組
uchar idata   lwelcome[16]={"      clock     "};                //定義第一行顯示數(shù)組
uchar idata   llwelcome[16]={"        clock   "};                //定義第一行顯示數(shù)組
uchar idata  lllwelcome[16]={"          clock "};                //定義第一行顯示數(shù)組

uchar  idata  sslcdtimer[16]={"    00:00:00    "};
uchar  idata tsslcdtimer[16]={"    00:00:00    "};
uchar  idata   lcdtimer[16]={"    00:00:00    "};                //定義第二行顯示數(shù)組
uchar  idata  mlcdtimer[16]={"    00:  :      "};                //定義第二行顯示數(shù)組
uchar  idata   hlcdtimer[16]={"      :00:      "};                //定義第二行顯示數(shù)組
uchar  idata  setlcdtimer[16]={"    00:01:00    "};
uchar timecount;
uchar temps;

bit timeflag;
bit sstimeflag;
sbit ring=P2^0;//蜂鳴鬧鈴

sbit e=P2^7;//LCD顯示器E                               
sbit rw=P2^6;//LCD顯示器RW
sbit rs=P2^5;//LCD顯示器RS
sbit P10=P1^0; //測試用閃燈

sbit Key=P3^2;//秒表暫停,清零
sbit Key0=P3^3;//調(diào)時,設定鬧鐘時間,秒表選擇
sbit Key1=P3^4;//調(diào)時,設定鬧鐘時間改變


uchar th1_f; //在中斷中裝載的T0的值高8位
uchar tl1_f; //在中斷中裝載的T0的值低8位
uint m=0;
uint n=0;
ulong i;
uint f=0,g=1;  
uint j,k;
uchar code freq[3][14]=
{
{0xF2,0x42,
0xF3,0xC1,
0xF5,0x17,
0xF5,0xB6,
0xF6,0xD0,
0xF7,0xD1,
0xF8,0xB6},
{0xF9,0x21,
0xF9,0xE0,
0xFA,0x8B,
0xFA,0xD7,
0xFB,0x68,
0xFB,0xE8,
0xFC,0x5B },
{0xFC,0x8D,
0xFC,0xEE,
0xFD,0x44,
0xFD,0x6D,
0xFD,0xB4,
0xFD,0xF4,
0xFE,0x2D},
};         //音樂頻率表,低音,中音,高音,系統(tǒng)振蕩頻率11.0592MHz

uint code song1[]={26,25,23,25,31,26,25,26,23,25,26,25,23,22,21,16,25,23,22,22,23,23,23,26,23,22,21,25,23,22,21,16,21,15,26,25,23,25,31,26,25,26,23,25,26,25,23,22,21,16,25,23,22,22,23,23,23,26,23,22,21,25,23,22,21,16,21,15};
//編制音樂


//**************************************************
//軟件延時函數(shù)(系統(tǒng)晶振為11.0592MHz),延時時間約為40μs
//入口條件:無符號整型變量del1,最終的延時時間為(del1*40)μs
//**************************************************
void delay(uint del1)
{
        uchar del2;
        for(;del1>0;del1--)
                for(del2=10;del2>0;del2--);
}
//**************************************************
//液晶顯示器判忙函數(shù)
//**************************************************
void busy()
{
        uchar temp;
        temp=0x00;
        rs=0;
        rw=1;
        while((temp&0x80)==0x80)
        {
                P0=0xff;
                e=1;
                temp=P0;
                e=0;
        }
}
//**************************************************
//向液晶顯示器寫命令函數(shù)
//**************************************************
void WR_Com(uchar temp)
{
        busy();
        rs=0;
        rw=0;
        P0=temp;
        e=1;
        e=0;
}
//**************************************************
//向液晶顯示器寫數(shù)據(jù)函數(shù)
//**************************************************
void WR_Data(uchar num)
{
        busy();
        rs=1;
        rw=0;
        P0=num;
        e=1;
        e=0;
}
//**************************************************
//向液晶顯示器寫入顯示數(shù)據(jù)函數(shù)
//入口條件:液晶顯示器行首地址(指示第一行還是第二行)和待顯示數(shù)組的首地址
//**************************************************
//void disp_lcdchar(uchar addr,uchar temp1)
//{
//    WR_Com(addr);
//        delay(100);
//        WR_Data(temp1);
//}
       

void disp_lcd(uchar addr,uchar *temp1)
{
        uchar i;
        WR_Com(addr);
        delay(100);
        for(i=0;i<16;i++)
        {
                WR_Data(temp1[i]);
                delay(100);
        }
}       
//**************************************************
//液晶顯示器初始化函數(shù)
//**************************************************
void lcd_ini()
{
        char i;
        for(i=3;i>0;i--)
        {
                P0=0x30;
                rs=0;
                rw=0;
                e=1;
                e=0;
                delay(100);
        }
        P0=0x38;
        rs=0;
        rw=0;
        e=1;
        e=0;
        delay(100);
}
//**************************************************
//液晶顯示器復位函數(shù)
//**************************************************
void lcd_Reset()
{
        WR_Com(0x01);
        delay(100);
        WR_Com(0x06);
        delay(100);
        WR_Com(0x0c);
        delay(100);
}

//**************************************************
//外部中斷函數(shù),秒表暫停,清零
//**************************************************
void modess() interrupt 0 using 0  
{       
    delay(10000);                                                                                                       
        n++;
        if(n==3)
        n=0;
}

//**************************************************
//外部中斷函數(shù),模式選擇
//**************************************************
void modepp() interrupt 2  using 1
{                                                                                                               
        delay(30000);
        m++;
        if(m==6)
        n=0;
        if(m==7)
        m=0;
}


//**************************************************
//定時/計數(shù)器中斷函數(shù),1S及0.01S
//**************************************************
void timer0() interrupt 1  using 2
{
        TH0=0xdc;
        TL0=0x23;
        sstimeflag=1;
        if(--timecount==0)
        {
                timecount=100;
                timeflag=1;
        }
}
//**************************************************
//定時/計數(shù)器中斷函數(shù),裝入音樂頻率計數(shù)初值
//**************************************************
void timer1() interrupt 3  using 3
{
  TL1=tl1_f;TH0=th1_f; //調(diào)入預定時值
  ring=!ring; //取反音樂輸出IO
}                        

                                                                                                                                                                                                                  
//**************************************************
//主函數(shù)
//**************************************************
void main()
{
    P10=1;
        lcd_ini();
        lcd_Reset();
/*        for(i=0;i<10;i++)
        {                                                                                        
          temps=welcome[i];
          disp_lcdchar(0x80+1,temps); //LCD 單字符從左到右顯示
          delay(10000);
         }*/
        disp_lcd(0x80,welcome);
    delay(10000);
        disp_lcd(0x80,lwelcome);
    delay(10000);
        disp_lcd(0x80,llwelcome);
    delay(10000);
        disp_lcd(0x80,lllwelcome);
        delay(10000);
        disp_lcd(0x80,llwelcome);
        delay(10000);
        disp_lcd(0x80,lwelcome);
        delay(10000);
        disp_lcd(0x80,welcome);        //LCD滾動顯示
        delay(10000);
        disp_lcd(0xc0,lcdtimer);
        P10=0;
        TMOD=0x11;
        TH0=0xdc;
        TL0=0x23;
        TR0=1;
    IE=0x86;
        timeflag=0;         //1秒計時標志
        sstimeflag=0; //0.01秒計時標志
        timecount=100;
        while(1)
        {
         while(m==6)//秒表
         {
            IE=0x87;
            if(n==0) //秒表跑動
                {
             if(sstimeflag==1)
             {
              sstimeflag=0;
              sslcdtimer[11]+=1;
                  if(sslcdtimer[11]>=0x3a)
                  {
                     sslcdtimer[11]=0x30;
                            sslcdtimer[10]+=1;
                          if(sslcdtimer[10]>=0x3a)
                          {
                           sslcdtimer[10]=0x30;
                           sslcdtimer[8]+=1;
                             if(sslcdtimer[8]>=0x3a)
                             {
                               sslcdtimer[8]=0x30;
                                   sslcdtimer[7]+=1;
                                   if(sslcdtimer[7]>=0x36)
                                      {
                                          sslcdtimer[7]=0x30;
                                          }
                          }
               }
            }
                         disp_lcd(0xc0,sslcdtimer);
          }
                  if(n==1)//秒表暫停
                  {
                   disp_lcd(0xc0,sslcdtimer);
                  }

                  if(n>=2)//秒表清零
                 {
                   disp_lcd(0xc0,tsslcdtimer);
                   for(i=0;i<16;i++)
                   sslcdtimer[i]=tsslcdtimer[i];
                 }
          }
   }
            while(m==0||m>=3) //時鐘程序,只要不是調(diào)時,就一直運行
           {
              IE=0x86;
                    if(timeflag==1)
                  {
                        timeflag=0;
                        lcdtimer[11]+=1;
                        if(lcdtimer[11]>=0x3a)
                        {
                                lcdtimer[11]=0x30;
                                lcdtimer[10]+=1;
                                if(lcdtimer[10]>=0x36)
                                {
                                        lcdtimer[10]=0x30;
                                        lcdtimer[8]+=1;
                                        if(lcdtimer[8]>=0x3a)
                                        {
                                                lcdtimer[8]=0x30;
                                                lcdtimer[7]+=1;
                                                  if(lcdtimer[7]>=0x36)
                                                {
                                                        lcdtimer[7]=0x30;
                                                        lcdtimer[5]+=1;
                                                   if(lcdtimer[5]>=0x3a)
                                                      {
                                                       lcdtimer[5]=0x30;
                                                           lcdtimer[4]+=1;
                                                            if(lcdtimer[4]>=0x33&&lcdtimer[5]>=0x35)
                                                        {
                                                         lcdtimer[5]=0x30;
                                                         lcdtimer[4]=0x30;
                                }
                                                }
                                                  }
                                        }
                                }
                    }
           }
                                           if(m==0)
                                    {
                                                     disp_lcd(0xc0,lcdtimer);
                                                                          if(!Key1)//關(guān)掉鬧鐘
                                                                          {
                                                                            g=0;
                                                                                }
                                                                          if(lcdtimer[8]==setlcdtimer[8]&&lcdtimer[7]==setlcdtimer[7]&&lcdtimer[5]==setlcdtimer[5]&&lcdtimer[4]==setlcdtimer[4])
                                                                                     f=1;  //開啟鬧鐘 ,播放音樂
                                                  if(f&&g)
                                                {
                                                            /*ring=1;
                                                            delay(10000);         
                                                                                            ring=0;
                                                                                             f=0; */
                                                        IE=0x8e;
                                                                                            j=song1[i]/10-1;
                                                    k=2*(song1[i]%10-1);
                                                th1_f=freq[j][k]; //取出對應的定時值送給T0
                                                tl1_f=freq[j][++k];
                                                TR1=1;
                                                                                                for(n=0;n<50000;n++); //音符間延時
                                                                                            i++;
                                                                                                TR1=0;
                                                                                                f=0;
                                                }
                                       }
        }
      while(m==1)          //調(diào)時分
        {
           if(!Key1)
           {
               delay(10000);
               timeflag=0;
               lcdtimer[8]+=1;
                          if(lcdtimer[8]>=0x3a)
                        {
                                lcdtimer[8]=0x30;
                                lcdtimer[7]+=1;
                                if(lcdtimer[7]>=0x36)
                                {
                                  lcdtimer[7]=0x30;
                                }
                        }
           }
                   disp_lcd(0xc0,lcdtimer);
                delay(8000);
                mlcdtimer[11]=lcdtimer[11];
                mlcdtimer[10]=lcdtimer[10];
                mlcdtimer[5]=lcdtimer[5];
                mlcdtimer[4]=lcdtimer[4];
                disp_lcd(0xc0,mlcdtimer);
    }

          while(m==2)  //調(diào)時時
         {
           if(!Key1)
           {
              delay(10000);
                  lcdtimer[5]+=1;
                   if(lcdtimer[5]>=0x3a)
                        {
                                lcdtimer[5]=0x30;
                                lcdtimer[4]+=1;       
                        }
                  if(lcdtimer[4]==0x32&&lcdtimer[5]>=0x34)
                           {
                                   lcdtimer[5]=0x30;
                                   lcdtimer[4]=0x30;                         
                           }
       }
                disp_lcd(0xc0,lcdtimer);
                delay(8000);
            hlcdtimer[11]=lcdtimer[11];
                hlcdtimer[10]=lcdtimer[10];
                hlcdtimer[8]=lcdtimer[8];
                hlcdtimer[7]=lcdtimer[7];
                disp_lcd(0xc0,hlcdtimer);
      }
                 while(m==3)//顯示鬧鈴時間
         {
           if(!Key1)
           {
              delay(10000);                 
       }
            disp_lcd(0xc0,setlcdtimer);
      }
                      while(m==4) //調(diào)鬧鈴分
        {
           if(!Key1)   
           {
               delay(10000);
               setlcdtimer[8]+=1;
                          if(setlcdtimer[8]>=0x3a)
                        {
                                setlcdtimer[8]=0x30;
                                setlcdtimer[7]+=1;
                                if(setlcdtimer[7]>=0x36)
                                {
                                  setlcdtimer[7]=0x30;
                                }
                        }
           }
                   disp_lcd(0xc0,setlcdtimer);
                delay(8000);
                mlcdtimer[11]=setlcdtimer[11];
                mlcdtimer[10]=setlcdtimer[10];
                mlcdtimer[5]=setlcdtimer[5];
                mlcdtimer[4]=setlcdtimer[4];
                disp_lcd(0xc0,mlcdtimer);
    }
          while(m==5)//調(diào)鬧鈴時
         {
           if(!Key1)
           {
              delay(10000);
                  setlcdtimer[5]+=1;
                   if(setlcdtimer[5]>=0x3a)
                        {
                                setlcdtimer[5]=0x30;
                                setlcdtimer[4]+=1;       
                        }
                  if(setlcdtimer[4]==0x32&&setlcdtimer[5]>=0x34)
                           {
                                   setlcdtimer[5]=0x30;
                                   setlcdtimer[4]=0x30;                         
                           }
       }
                disp_lcd(0xc0,setlcdtimer);
                delay(8000);
            hlcdtimer[11]=setlcdtimer[11];
                hlcdtimer[10]=setlcdtimer[10];
                hlcdtimer[8]=setlcdtimer[8];
                hlcdtimer[7]=setlcdtimer[7];
                disp_lcd(0xc0,hlcdtimer);
      }
  }
}       


回復

使用道具 舉報

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

本版積分規(guī)則

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

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

快速回復 返回頂部 返回列表