新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 1602液晶顯示DS1302+S51時鐘+溫度顯示

        1602液晶顯示DS1302+S51時鐘+溫度顯示

        作者: 時間:2016-11-10 來源:網絡 收藏
        /*============================================================

        使用1602液晶顯示DS1302+S51時鐘+溫度顯示 zhaojun 2007/06/29

        本文引用地址:http://www.104case.com/article/201611/317334.htm

        ==============================================================
        聲明:1. 1602驅動程序照搬 明皓 的,非常好用
        2. DS1302驅動程序是參考網友修改而來

        NS1602R(16*2)模擬口線接線方式
        連接線圖:
        ---------------------------------------------------
        | LCM-----51  | LCM-----51  | LCM------51 |
        | ----------------------------------------------- |
        | DB0-----P0.0 | DB4-----P0.4 | RS-------P2.0 |
        | DB1-----P0.1 | DB5-----P0.5 | RW-------P2.1 |
        | DB2-----P0.2 | DB6-----P0.6 | E--------P2.2 |
        | DB3-----P0.3 | DB7-----P0.7 | VLCD接1K電阻到GND |
        ---------------------------------------------------
        DS1302 接線圖

        Vcc2 CLK I/O /RST

        | | | |
        ---------------
        | 8 7 6 5 |
        | DS1302 |
        | |
        | 1 2 3 4 |
        ---------------
        | | | |
        VCC1 GND

        1. 腳接+5V 2,3. 腳32768HZ晶振 4. 腳接地 5. 腳接S51的P1.2 6. 腳接S51的P1.1 7. 接S51的P1.0
        8. 腳接后備電源,可以接老計算機主板上的3.6V電池,也可以通過二級管隔離接一個大容量電解電容
        電壓在2.5V以上即可維持

        按鍵說明:1. 共三個鍵,低電平有效
        2. P1.4 和 P1.5 同時按:初始化
        3. P1.6 端口按鍵:選擇要調整的項目
        4. P1.5 端口按鍵:增加;P1.4端口按鍵:減少


        [注:AT89S51使用12M晶振]
        原理圖:

        源代碼:

        =================定義與申明=============================================================*/

        #include "regx51.h"
        #include "string.h"
        #include "intrins.h"

        #define uchar unsigned char
        #define uint unsigned int
        typedef unsigned char byte;
        typedef unsigned int word;

        //*********** 1602引腳定義引腳
        #define LCM_RS P2_0 // 數據/命令選擇信號
        #define LCM_RW P2_1 // 讀/寫選擇信號
        #define LCM_E P2_2 // 使能信號

        //*********** DS1302 時間顯示定義部分
        sbit T_CLK=P1^0; //串行時鐘輸入
        sbit T_IO =P1^1; //串行數據端口
        sbit T_RST=P1^2; //復位端口

        //*********** 18B20溫度顯示定義部分
        sbit DQ=P3^3; //18B20 接P33口

        sbit ACC0=ACC^0;
        sbit ACC7=ACC^7;

        #define LCM_Data P0 //顯示數據端口
        #define Busy 0x80 //用于檢測LCM狀態字中的Busy標識

        uchar id,timecount; //全局變量
        bit flag,sflag; //flag是時鐘冒號閃爍標志,sflag是溫度負號顯示標志
        bit sec,min,hour,year,mon,day,weekk; //閃爍標志位

        //*********************函數申明
        void Disp_line1(void); // 顯示屏幕第一行
        void Disp_line2(void); // 顯示屏幕第二行
        void id_case1_key(); // id為1時的下一級選擇
        void Set(uchar,uchar); // 根據選擇調整相應項目
        void RTInputByte(uchar); /* 輸入 1Byte */
        uchar RTOutputByte(void); /* 輸出 1Byte */
        void W1302(uchar, uchar); // 向DS1302寫入一個字節
        uchar R1302(uchar); // 從DS1302讀出一個字節
        void Set1302(uchar * ); // 設置時間

        //******* 1602LCD驅動 **********************************************************
        void WriteDataLCM(uchar WDLCM); //寫數據
        void WriteCommandLCM(uchar WCLCM,BuysC); //寫指令
        uchar ReadStatusLCM(void); //讀狀態
        void LCMInit(void); //LCM初始化
        void DisplayOneChar(uchar X, uchar Y, uchar DData); //按指定位置顯示一個字符
        void DisplayListChar(uchar X, uchar Y, uchar code *DData); //按指定位置顯示一串字符
        void Delay5Ms(void); //5ms延時
        void Delay400Ms(void); //400ms延時
        Read_Temperature(char,char);//溫度顯示
        void mychar(void); //顯示自定義字符
        void adjust_res(char res); //res 分別等于 0x1f, 0x3f, 0x5f 溫度讀數分辨率分別對應
        // 0.5, 0.25, 0.125
        //初始化后設置為:07年07月04日 星期3 12點00分00秒
        // 12:00:00 XX. C
        // 07/07/04 Week.3
        unsigned char inittime[7]={0x00,0x00,0x12,0x04,0x07,0x03,0x07};
        // 秒 分鐘 小時 日 月 星期 年

        uchar code week[]={"Week."};//星期顯示

        //========================= 主函數 =======================================================

        /*****************************************************
        函 數 名:main()
        功 能:主函數
        說 明:
        入口參數:無
        返 回 值:無
        *****************************************************/
        void main(void)
        {
        Delay400Ms(); //啟動等待,等LCM講入工作狀態
        LCMInit(); //LCM初始化
        Delay5Ms(); //延時片刻(可不要)
        mychar(); //顯示自定義字符

        TMOD=0x01; //選擇定時模式
        TH0=(65535-50000)/256;//取定時初值
        TL0=(65535-50000)%256;
        EA=1; //開中斷
        TR0=1;
        ET0=1;
        W1302(0x90,0xa5); //打開充電二級管 一個二級管串聯一個2K電阻
        W1302(0x8e,0x80); //寫保護,禁止寫操作
        adjust_res(0x5f); //調整18B20的分辨率 0x1f:0.5; 0x3f:0.25; 0x5f:0.125

        while(1)
        {
        if ((P1_4|P1_5)==0) // 初始化 同時按下P1_4、P1_5
        {
        Delay5Ms(); // 適當延時,消除抖動
        if ((P1_4|P1_5)==0) Set1302(inittime); // 顯示初始值
        }
        if (P1_6==0) // 設置和選擇項目鍵
        {
        Delay5Ms(); // 適當延時,消除抖動
        if(P1_6==0){id++;if(id>7) id=0;} // 7個可調節項目循環調節
        while(P1_6==0);
        }
        switch(id) // 跳轉到對應的項目進行設置
        {
        case 0:
        sec=0;
        Disp_line1(); Disp_line2();
        break;
        case 1: //調節年
        year=1;//設置年閃爍標志位
        Disp_line1(); Disp_line2();
        id_case1_key();
        break;
        case 2: //調節月
        year=0;mon=1;//設置月閃爍標志位
        Disp_line1(); Disp_line2();
        id_case1_key();
        break;
        case 3: //調節日
        mon=0;day=1;//設置日閃爍標志位
        Disp_line1(); Disp_line2();
        id_case1_key();
        break;
        case 4: //調節星期
        day=0;weekk=1;//設置星期閃爍標志位
        Disp_line1(); Disp_line2();
        id_case1_key();
        break;
        case 5: //調節小時
        weekk=0;hour=1;//設置小時閃爍標志位
        Disp_line1(); Disp_line2();
        id_case1_key();
        break;
        case 6: //調節分鐘
        hour=0;min=1;//設置分鐘閃爍標志位
        Disp_line1(); Disp_line2();
        id_case1_key();
        break;
        case 7: //調節秒
        min=0;sec=1;//設置秒鐘閃爍標志位
        Disp_line1(); Disp_line2();
        id_case1_key();
        break;
        }
        }
        }
        //================================== 定時中斷 =============================================

        /*****************************************************
        函 數 名:void t0()
        功 能:時間工作時,冒號閃爍
        說 明:T0中斷入口,方式1
        入口參數:無
        返 回 值:無
        *****************************************************/
        void t0(void) interrupt 1 using 0
        {
        TH0=(65535-50000)/256; //取50ms定時初值
        TL0=(65535-50000)%256;
        timecount++;
        if(timecount>9)
        {
        timecount=0; //計時到,從先開始
        flag=~flag; //標志位取反
        }
        }
        //==================================== 項目設置 ===========================================

        /*****************************************************
        函 數 名:void id_case1_key()
        功 能:項目設置加減控制
        說 明:P1.5和P1.4 <==> +和-
        入口參數:無
        返 回 值:無
        *****************************************************/
        //id為1時的下一級選擇
        void id_case1_key()
        {
        if (P1_5==0) //P1_5有按下,則數值增加(+)
        {
        Delay5Ms(); //適當延時,消除抖動
        if(P1_5==0) Set(id,0); //根據選擇調整相應項目
        if(id!=7) while(P1_5==0);
        }
        if (P1_4==0) //P1_4有按下,則數值減少(-)
        {
        Delay5Ms(); //適當延時,消除抖動
        if(P1_4==0) Set(id,1); //根據選擇調整相應項目
        if(id!=7) while(P1_4==0);
        }
        }
        /*****************************************************
        函 數 名:void Set()
        功 能:項目設置
        說 明:sel_1=0時,數值加;sel_1=1時,數值減
        入口參數:sel和sel_1
        返 回 值:無
        *****************************************************/
        //根據選擇調整相應項目并寫入DS1302
        void Set(uchar sel,uchar sel_1)
        {
        signed char address,item;
        signed char max,mini;
        //偶數指令是寫,奇數指令是讀
        //最大值與最小值限定
        if(sel==7) {address=0x80; max=00;mini=0;} //秒
        if(sel==6) {address=0x82; max=59;mini=0;} //分鐘
        if(sel==5) {address=0x84; max=23;mini=0;} //小時
        if(sel==3) {address=0x86; max=31;mini=1;} //日
        if(sel==2) {address=0x88; max=12;mini=1;} //月
        if(sel==1) {address=0x8c; max=99;mini=0;} //年
        if(sel==4) {address=0x8a; max=07;mini=1;} //星期
        //先從1302中讀出數據,把數據轉換成十進制進行加減設置;后從先轉換回來寫入1302中
        item=R1302(address+1)/16*10+R1302(address+1)%16;//從1302中讀出1字節,再轉換成十進制
        if (sel_1==0) item++; else item--; //sel_1=0則加,sel_1=1則減
        if(item>max) item=mini; //大于最大值,則賦最小值(循環)
        if(item
        W1302(0x8e,0x00); //允許寫操作
        W1302(address,item/10*16+item%10);//把調節好的十進制數據轉換成十六進制后寫入1302中
        W1302(0x8e,0x80); //寫保護,禁止寫操作
        }
        //=======================================================================================

        /*****************************************************
        函 數 名:void Disp_line1()
        功 能:顯示時間和溫度 (XX:XX:XX XX.X C)
        說 明:第一行顯示數據處理
        入口參數:無
        返 回 值:無
        *****************************************************/
        //屏幕顯示第一行: 時間和溫度顯示
        void Disp_line1(void)
        {
        Read_Temperature(10,0); //溫度顯示
        //冒號閃爍
        if(flag==0)
        {DisplayOneChar(3,0,0x3a); DisplayOneChar(6,0,0x3a);}
        else
        {DisplayOneChar(3,0,0x20); DisplayOneChar(6,0,0x20);}

        if(sec==1) //秒閃爍標志位
        {
        if(flag==1)
        {
        DisplayOneChar(7,0,R1302(0x81)/16+0x30); //顯示秒十位
        DisplayOneChar(8,0,R1302(0x81)%16+0x30); //顯示秒個位
        }
        else
        {
        DisplayOneChar(7,0,0x20); //顯示秒十位
        DisplayOneChar(8,0,0x20); //顯示秒個位
        }
        }
        else
        {
        DisplayOneChar(7,0,R1302(0x81)/16+0x30); //顯示秒十位
        DisplayOneChar(8,0,R1302(0x81)%16+0x30); //顯示秒個位
        }

        if(min==1) //分鐘閃爍標志位
        {
        if(flag==1)
        {
        DisplayOneChar(4,0,R1302(0x83)/16+0x30); //顯示分鐘十位
        DisplayOneChar(5,0,R1302(0x83)%16+0x30); //顯示分鐘個位
        }
        else
        {
        DisplayOneChar(4,0,0x20); //顯示分鐘十位
        DisplayOneChar(5,0,0x20); //顯示分鐘個位
        }
        }
        else
        {
        DisplayOneChar(4,0,R1302(0x83)/16+0x30); //顯示分鐘十位
        DisplayOneChar(5,0,R1302(0x83)%16+0x30); //顯示分鐘個位
        }

        if(hour==1) //小時閃爍標志位
        {
        if(flag==1)
        {
        DisplayOneChar(1,0,R1302(0x85)/16+0x30);//顯示小時十位
        DisplayOneChar(2,0,R1302(0x85)%16+0x30);//顯示小時個位
        }
        else
        {
        DisplayOneChar(1,0,0x20); //顯示小時十位
        DisplayOneChar(2,0,0x20); //顯示小時個位
        }
        }
        else
        {
        DisplayOneChar(1,0,R1302(0x85)/16+0x30);//顯示小時十位
        DisplayOneChar(2,0,R1302(0x85)%16+0x30);//顯示小時個位
        }
        }
        /*****************************************************
        函 數 名:void Disp_line2()
        功 能:顯示日期和星期 (XX/XX/XX Week.X)
        說 明:第二行顯示數據處理
        入口參數:無
        返 回 值:無
        *****************************************************/
        // 屏幕顯示第二行 日期和星期
        void Disp_line2(void)
        {
        DisplayOneChar(3,1,0x2f); //顯示固定字符
        DisplayOneChar(6,1,0x2f);
        DisplayListChar(10,1,week);

        if(year==1) //年閃爍標志位
        {
        if(flag==1)
        {
        DisplayOneChar(1,1,R1302(0x8d)/16+0x30);//顯示年十位
        DisplayOneChar(2,1,R1302(0x8d)%16+0x30);//顯示年個位
        }
        else
        {
        DisplayOneChar(1,1,0x20); //顯示年十位
        DisplayOneChar(2,1,0x20); //顯示年個位
        }
        }
        else
        {
        DisplayOneChar(1,1,R1302(0x8d)/16+0x30);//顯示年十位
        DisplayOneChar(2,1,R1302(0x8d)%16+0x30);//顯示年個位
        }

        if(mon==1) //月閃爍標志位
        {
        if(flag==1)
        {
        DisplayOneChar(4,1,R1302(0x89)/16+0x30);//顯示月十位
        DisplayOneChar(5,1,R1302(0x89)%16+0x30);//顯示月個位
        }
        else
        {
        DisplayOneChar(4,1,0x20); //顯示月十位
        DisplayOneChar(5,1,0x20); //顯示月個位
        }
        }
        else
        {
        DisplayOneChar(4,1,R1302(0x89)/16+0x30);//顯示月十位
        DisplayOneChar(5,1,R1302(0x89)%16+0x30);//顯示月個位
        }

        if(day==1) //日閃爍標志位
        {
        if(flag==1)
        {
        DisplayOneChar(7,1,R1302(0x87)/16+0x30);//顯示日十位
        DisplayOneChar(8,1,R1302(0x87)%16+0x30);//顯示日個位
        }
        else
        {
        DisplayOneChar(7,1,0x20); //顯示日十位
        DisplayOneChar(8,1,0x20); //顯示日個位
        }
        }
        else
        {
        DisplayOneChar(7,1,R1302(0x87)/16+0x30);//顯示日十位
        DisplayOneChar(8,1,R1302(0x87)%16+0x30);//顯示日個位
        }

        if(weekk==1) //星期閃爍標志位
        {
        if(flag==1)
        {
        DisplayOneChar(15,1,R1302(0x8b)%16+0x30);//顯示星期
        }
        else
        {
        DisplayOneChar(15,1,0x20); //顯示星期
        }
        }
        else
        {
        DisplayOneChar(15,1,R1302(0x8b)%16+0x30);//顯示星期
        }
        }
        //================================ LCM1602控制部分 =======================================

        /*****************************************************
        函 數 名:void WriteDataLCM()
        功 能:向LCM1602中寫入數據
        說 明:將形參WDLCM中的數據寫入LCM中
        入口參數:WDLCM
        返 回 值:無
        *****************************************************/
        //寫數據
        void WriteDataLCM(uchar WDLCM)
        {
        ReadStatusLCM(); //檢測忙
        LCM_Data = WDLCM;//寫入數據到LCM
        LCM_RS = 1;
        LCM_RW = 0;
        LCM_E = 0; //若晶振速度太高可以在這后加小的延時
        LCM_E = 0; //延時
        LCM_E = 1;
        }
        /*****************************************************
        函 數 名:void WriteCommandLCM()
        功 能:向LCM1602中寫入指令
        說 明:向LCM中寫入指令;如果BuysC=0時,忽略忙檢測,如果BuysC=1時,不忽略忙檢測
        入口參數:WCLCM,BuysC
        返 回 值:無
        *****************************************************/
        //寫指令
        void WriteCommandLCM(uchar WCLCM,BuysC) //BuysC為0時忽略忙檢測
        {
        if (BuysC) ReadStatusLCM(); //根據需要檢測忙
        LCM_Data = WCLCM; //寫入指令
        LCM_RS = 0;
        LCM_RW = 0;
        LCM_E = 0;
        LCM_E = 0;
        LCM_E = 1;
        }
        /*****************************************************
        函 數 名:uchar ReadStatusLCM()
        功 能:讀狀態
        說 明:判斷LCM的工作狀態;也可以不用此函數,用一段延時程序代替
        入口參數:無
        返 回 值:LCM_Data
        *****************************************************/
        //讀狀態
        uchar ReadStatusLCM(void)
        {
        LCM_Data = 0xFF; //LCM數據口先置1
        LCM_RS = 0;
        LCM_RW = 1;
        LCM_E = 0;
        LCM_E = 0;
        LCM_E = 1;
        while (LCM_Data & Busy); //檢測忙信號.如果忙,則不執行
        return(LCM_Data);//不忙返回讀取數據
        }
        /*****************************************************
        函 數 名:void LCMInit()
        功 能:初始化LCM1602
        說 明:LCM在工作前先要對顯示屏初始化,否則模塊無法正常工作
        入口參數:無
        返 回 值:五
        *****************************************************/
        //LCM初始化
        void LCMInit(void)
        {
        LCM_Data = 0;
        WriteCommandLCM(0x38,0); // 三次顯示模式設置,不檢測忙信號
        Delay5Ms();
        WriteCommandLCM(0x38,0); // 0x38指令表示:8位數據顯示模式,倆行多顯示
        Delay5Ms();
        WriteCommandLCM(0x38,0);
        Delay5Ms();
        WriteCommandLCM(0x38,1); // 顯示模式設置,開始要求每次檢測忙信號
        WriteCommandLCM(0x08,1); // 關閉顯示
        WriteCommandLCM(0x01,1); // 顯示清屏
        WriteCommandLCM(0x06,1); // 顯示光標移動設置
        WriteCommandLCM(0x0C,1); // 顯示開及光標設置
        }
        /*****************************************************
        函 數 名:void DisplayOneChar()
        功 能:按指定坐標中寫入數據
        說 明:X-橫坐標,Y-縱坐標
        入口參數:X,Y,DData
        返 回 值:
        *****************************************************/
        //按指定位置顯示一個字符
        void DisplayOneChar(uchar X, uchar Y, uchar DData)
        {
        Y &= 0x01;
        X &= 0x0F; //限制X不能大于15,Y不能大于1
        if (Y) X |= 0x40; //當要顯示第二行時地址碼+0x40;
        X |= 0x80; //算出指令碼
        WriteCommandLCM(X, 0); //這里不檢測忙信號,發送地址碼
        WriteDataLCM(DData);
        }
        /*****************************************************
        函 數 名:void DisplayListChar()
        功 能:向指定坐標中寫入字符串
        說 明:X-橫坐標,Y-縱坐標
        入口參數:X,Y,*DData
        返 回 值:
        *****************************************************/
        //按指定位置顯示一串字符 ***原來的遇到空格0x20就不顯示***
        void DisplayListChar(uchar X, uchar Y, uchar code *DData)
        {
        uchar ListLength,j;
        ListLength = strlen(DData);//strlen:讀取字符串的長度
        Y &= 0x1;
        X &= 0xF; //限制X不能大于15,Y不能大于1
        if (X <= 0xF) //X坐標應小于0xF
        {
        for(j=0;j {
        DisplayOneChar(X, Y, DData[j]); //顯示單個字符
        X++;//橫坐標加1,縱坐標不變
        }
        }
        }
        //=================================== 自定義字符 ==========================================

        /*****************************************************
        函 數 名:void mychar()
        功 能:自定義字符--CGRAM
        說 明:LCM1602字符庫中沒有溫度符號,自定義溫度符號
        入口參數:無
        返 回 值:無
        定義形式:1602中定義CGRAM的形式如下:
        ---------------------------------------------------------------------------
        | CGRAM地址設置 | 自定義的代碼 |
        | DB7 DB6 | DB5 DB4 DB3 | DB2 DB1 DB0 | DB7 DB6 DB5 DB4 DB3 DB2 DB1 DB0 |
        | 0 1 | 0 0 0 | X X X | 0 0 0 0 * 0 0 0 |
        | 0 1 | 0 0 1 | X X X | 0 0 0 0 * 0 0 1 |
        | ... | ... | ... | ... ... |
        | 0 1 | 1 1 0 | X X X | 0 0 0 0 * 1 1 0 |
        | 0 1 | 1 1 1 | X X X | 0 0 0 0 * 1 1 1 |
        ---------------------------------------------------------------------------
        1. 1602共能定義8個5x8字符;
        2. CGRAM地址設置: X X X--DB2 DB1 DB0對應寫入地址,1~8行;
        DB5 DB4 DB3對應自定義字符代碼;DB7 DB6為指令碼,不可變.
        3. 自定義的代碼: 高4位DB7 DB6 DB5 DB4為0000時它的低3位DB2 DB1 DB0對應于第1-8個,DB3為無關項。
        4. 自定義的代碼的DB2 DB1 DB0對應于CGRAM地址的DB5 DB4 DB3。
        *****************************************************/
        void mychar()
        {
        //---------自定義字符代碼--01H-------------------
        WriteCommandLCM(0x48,0); //第1行
        WriteDataLCM(0x02);//
        WriteCommandLCM(0x49,0); //第2行
        WriteDataLCM(0x05);//
        WriteCommandLCM(0x4a,0); //第3行 1------**--
        WriteDataLCM(0x05);// 2----**--**
        WriteCommandLCM(0x4b,0); //第4行 3----**--**
        WriteDataLCM(0x02);// 4------**--
        WriteCommandLCM(0x4c,0); //第5行 5----------
        WriteDataLCM(0x00);// 6----------
        WriteCommandLCM(0x4d,0); //第6行 7----------
        WriteDataLCM(0x00);// 8----------
        WriteCommandLCM(0x4e,0); //第7行
        WriteDataLCM(0x00);//
        WriteCommandLCM(0x4f,0); //第8行
        WriteDataLCM(0x00);//
        //-----------------------------------------------
        }
        //======================================= 延時函數部分 ====================================

        /*****************************************************
        函 數 名:void Delay5Ms()
        功 能:5ms延時
        說 明:軟件消除按鍵抖動和適當的延時
        入口參數:無
        返 回 值:無
        *****************************************************/
        //5ms延時
        void Delay5Ms(void)
        {
        uint TempCyc = 5552; //放入延時數據
        while(TempCyc--);
        }
        /*****************************************************
        函 數 名:void Delay400Ms()
        功 能:400ms延時
        說 明:
        入口參數:無
        返 回 值:無
        *****************************************************/
        //400ms延時
        void Delay400Ms(void)
        {
        uchar TempCycA = 5;
        uint TempCycB;
        while(TempCycA--)
        {
        TempCycB=7269;
        while(TempCycB--);
        };
        }
        //================================== 時鐘芯片控制部分 ======================================

        /*****************************************************
        函 數 名:RTInputByte()
        功 能:實時時鐘寫入一字節
        說 明:往DS1302寫入1Byte數據 (內部函數)
        入口參數:d 寫入的數據
        返 回 值:無
        *****************************************************/
        void RTInputByte(uchar d)
        {
        uchar i;
        ACC = d;
        for(i=8; i>0; i--)
        {
        T_IO = ACC0; /*相當于匯編中的 RRC */
        T_CLK = 1;
        T_CLK = 0;
        ACC = ACC >> 1;
        }
        }
        /*****************************************************
        函 數 名:RTOutputByte()
        功 能:實時時鐘讀取一字節
        說 明:從DS1302讀取1Byte數據 (內部函數)
        入口參數:無
        返 回 值:ACC
        設 計:zhaojun 日 期:2007-06-29
        修 改: 日 期:
        *****************************************************/
        uchar RTOutputByte(void)
        {
        uchar i;
        for(i=8; i>0; i--)
        {
        ACC = ACC >>1; /*相當于匯編中的 RRC */
        ACC7 = T_IO;
        T_CLK = 1;
        T_CLK = 0;
        }
        return(ACC); //返回讀取值
        }
        /*****************************************************
        函 數 名:W1302()
        功 能:往DS1302寫入數據
        說 明:先寫地址,后寫命令/數據 (內部函數)
        調 用:RTInputByte() , RTOutputByte()
        入口參數:ucAddr: DS1302地址, ucData: 要寫的數據
        返 回 值:無
        *****************************************************/
        void W1302(uchar ucAddr, uchar ucDa)
        {
        T_RST = 0;
        T_CLK = 0;
        T_RST = 1;
        RTInputByte(ucAddr); /* 地址,命令 */
        RTInputByte(ucDa); /* 寫1Byte數據*/
        T_CLK = 1;
        T_RST = 0;
        }
        /******************************************************
        函 數 名:R1302()
        功 能:讀取DS1302某地址的數據
        說 明:先寫地址,后讀命令/數據 (內部函數)
        調 用:RTInputByte() , RTOutputByte()
        入口參數:ucAddr: DS1302地址
        返 回 值:ucData :讀取的數據
        *******************************************************/
        uchar R1302(uchar ucAddr)
        {
        uchar ucData;
        T_RST = 0;
        T_CLK = 0;
        T_RST = 1;
        RTInputByte(ucAddr); /* 地址,命令 */
        ucData = RTOutputByte(); /* 讀1Byte數據 */
        T_CLK = 1;
        T_RST = 0;
        return(ucData);
        }

        /*******************************************************
        函 數 名:Set1302()
        功 能:設置初始時間
        說 明:先寫地址,后讀命令/數據(寄存器多字節方式)
        調 用:W1302()
        入口參數:pClock: 設置時鐘數據地址 格式為: 秒 分 時 日 月 星期 年
        7Byte (BCD碼)1B 1B 1B 1B 1B 1B 1B
        返 回 值:無
        ********************************************************/
        void Set1302(uchar *pClock)
        {
        uchar i;
        uchar ucAddr = 0x80;
        W1302(0x8e,0x00); /* 控制命令,WP=0,寫操作?*/
        for(i =7; i>0; i--)
        {
        W1302(ucAddr,*pClock); /* 秒 分 時 日 月 星期 年 */
        pClock++;
        ucAddr +=2;
        }
        W1302(0x8e,0x80); /* 控制命令,WP=1,寫保護?*/
        }
        //================================= 溫度顯示控制部分 ===============================================

        /*****************************************************
        函 數 名:void delay()
        功 能:DS18B20延時
        說 明:DS18B20時序延時
        入口參數:useconds
        返 回 值:無
        *****************************************************/
        //*********** 18B20驅動 **************************
        //延時
        void delay(word useconds)
        {
        for(;useconds>0;useconds--);
        }
        /*****************************************************
        函 數 名:byte ow_reset()
        功 能:DS18B20復位
        說 明:DS18B20使用時先要復位
        入口參數:無
        返 回 值:presence
        *****************************************************/
        //復位
        byte ow_reset(void)
        {
        byte presence;
        DQ = 0; //拉低總線
        delay(29); // 保持 480us
        DQ = 1; // 釋放總線
        delay(3); // 等待回復
        presence = DQ; // 讀取信號
        delay(25); // 等待結束信號
        return(presence); // 返回 0:正常 1:不存在
        }
        /*****************************************************
        函 數 名:byte read_byte()
        功 能:從 1-wire 總線上讀取一個字節
        說 明:讀總線上的數據有嚴格的時序
        入口參數:
        返 回 值:value
        *****************************************************/
        byte read_byte(void)
        {
        byte i;
        byte value = 0;
        for (i=8;i>0;i--)
        {
        value>>=1;
        DQ = 0;
        DQ = 1;
        delay(1);
        if(DQ)value|=0x80;
        delay(6);
        }
        return(value);
        }
        /*****************************************************
        函 數 名:void write_byte()
        功 能:向 1-WIRE 總線上寫一個字節
        說 明:寫總線上的數據有嚴格的時序
        入口參數:val
        返 回 值:無
        *****************************************************/
        void write_byte(char val)
        {
        byte i;
        for (i=8; i>0; i--) // 一次寫一位
        {
        DQ = 0; //
        DQ = val&0x01;
        delay(5); //
        DQ = 1;
        val=val/2;
        }
        delay(5);
        }
        /*****************************************************
        函 數 名:Read_Temperature()
        功 能:讀取和顯示溫度
        說 明:
        入口參數:xx,yy
        返 回 值:無
        *****************************************************/
        Read_Temperature(char xx,char yy)
        {
        uchar i,tl_temp;
        uint x;
        uchar ct[8];
        union //共用體
        {
        byte c[2];
        int x;
        }temp;

        ow_reset(); // DS18B20復位
        write_byte(0xCC); // Skip ROM
        write_byte(0x44); // 轉換溫度
        ow_reset();
        write_byte(0xCC); // Skip ROM
        write_byte(0xbe); // 讀取寄存器
        temp.c[1]=read_byte(); // 讀出溫度低8位
        temp.c[0]=read_byte(); // 讀出溫度高8位

        // 零下溫度判斷
        sflag=0; //溫度零下標志 0:零上,1:零下
        if((temp.c[0]&0xf8)!=0x00)
        {
        sflag=1; // 零下標志位置1
        temp.c[1]=~temp.c[1]; // 低8位取反
        temp.c[0]=~temp.c[0]; // 高8位取反
        tl_temp=temp.c[1]+1; // 低8位加1
        temp.c[1]=tl_temp; // 計算后重新存入數組
        if(tl_temp>255) temp.c[0]++; // 如果低8位大于255,向高8位進1
        }

        x=((temp.c[0]&0x07)*256+temp.c[1])*.625;
        for(i=0;i<8;i++)
        {
        ct[i]=0;
        }
        i=0;
        while(x/10)
        {
        ct[i]=x%10;
        x=x/10;
        i++;
        }
        ct[i]=x;

        if(sflag==1) DisplayOneChar(xx-1,yy,0x2d);
        else DisplayOneChar(xx-1,yy,0x20);
        DisplayOneChar(xx, yy,ct[2]+0x30); // 顯示溫度十位數
        DisplayOneChar(xx+1,yy,ct[1]+0x30); // 顯示溫度個位數
        DisplayOneChar(xx+2,yy,0x2e); // 顯示小數點
        DisplayOneChar(xx+3,yy,ct[0]+0x30); // 顯示溫度小數位
        DisplayOneChar(xx+4,yy,0x01); // 顯示自定義字符
        DisplayOneChar(xx+5,yy,0x43); // 顯示字符"C"
        }
        /*****************************************************
        函 數 名:void adjust_res()
        功 能:溫度分辨率調整
        說 明:此函數可以對溫度的顯示進行精度調節.
        入口參數:res
        返 回 值:無
        *****************************************************/
        void adjust_res(char res) // res 分別等于 0x1f, 0x3f, 0x5f 溫度讀數分辨率分別對應
        // 0.5, 0.25, 0.125
        {
        ow_reset(); // 復位
        write_byte(0xcc); // 跳過Rom
        write_byte(0x4e); // 寫暫存器
        write_byte(0x02); // 寫TH
        write_byte(0x01); // 寫TL
        write_byte(res); // 溫度轉換分辨率設置
        ow_reset(); // 復位
        write_byte(0xcc); // 跳過Rom
        write_byte(0x48); // 把暫存器內容寫到EPRam中
        }
        //==========================程序結束======================================================



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 隆安县| 武宁县| 辽宁省| 辽源市| 建瓯市| 林西县| 紫阳县| 永安市| 依安县| 英山县| 巍山| 孙吴县| 崇阳县| 湘乡市| 柳州市| 红河县| 新龙县| 板桥市| 白银市| 天峻县| 赞皇县| 民丰县| 贵定县| 客服| 华宁县| 于都县| 清原| 福建省| 南华县| 蚌埠市| 彭州市| 江都市| 吉首市| 绿春县| 花莲县| 双辽市| 安福县| 仁布县| 台南县| 台安县| 辽源市|