在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ 數(shù)據(jù)庫/ 15.7 DS1302 的 BURST 模式
18. RS485 通信與 Modbus 協(xié)議
17.5 A/D 差分輸入信號
15.8 C 語言復(fù)合數(shù)據(jù)類型(結(jié)構(gòu)體,共用體,枚舉類型)
16.3 NEC 協(xié)議紅外遙控器
13.1 單片機(jī)通信時(shí)序解析
14.4 單片機(jī) EEPROM 單字節(jié)讀寫操作時(shí)序
13.3 多個(gè) .c 文件的初步認(rèn)識
18.2 Modbus 通信協(xié)議介紹
15.1 BCD 碼介紹
18.3 單片機(jī) Modbus 多機(jī)通信程序設(shè)計(jì)
18.1 單片機(jī) RS485 通信接口、控制線、原理圖及程序?qū)嵗?/span>
15. 實(shí)時(shí)時(shí)鐘 DS1302
14.7 單片機(jī) I2C 和 EEPROM 的綜合編程
17. 模數(shù)轉(zhuǎn)換與數(shù)模轉(zhuǎn)換
16.2 紅外遙控通信原理
13.2 1602 液晶整屏移動(dòng)程序
17.6 D/A 輸出
17.7 單片機(jī)信號發(fā)生器程序
16.4 溫度傳感器 DS18B20
14.6 單片機(jī)EEPROM的頁寫入
13.4 單片機(jī)計(jì)算器程序設(shè)計(jì)[詳細(xì)]
17.2 A/D(模數(shù)轉(zhuǎn)換)的主要指標(biāo)
17.4 PCF8591 應(yīng)用程序
17.1 A/D 和 D/A 的基本概念
17.3 PCF8591硬件接口(電路圖引腳圖)
14.3 單片機(jī) EEPROM 簡介
13.5 單片機(jī)串口通信原理和控制程序
15.5 DS1302 寄存器介紹
15.2 單片機(jī) SPI 通信接口
15.6 DS1302 通信時(shí)序介紹
14.5 單片機(jī) EEPROM 多字節(jié)讀寫操作時(shí)序
16. 紅外通信與 DS18B20 溫度傳感器
14.1 單片機(jī) I2C 時(shí)序介紹
15.3 實(shí)時(shí)時(shí)鐘芯片 DS1302 介紹
15.9 單片機(jī)電子時(shí)鐘程序設(shè)計(jì)
16.1 紅外光的基本原理
15.4 DS1302 的硬件信息
15.7 DS1302 的 BURST 模式
14.2 單片機(jī) I2C 尋址模式
14. 單片機(jī) I2C 總線與 EEPROM
13. 單片機(jī) 1602 液晶與串口的應(yīng)用實(shí)例

15.7 DS1302 的 BURST 模式

進(jìn)行產(chǎn)品開發(fā)的時(shí)候,邏輯的嚴(yán)謹(jǐn)性非常重要,如果一個(gè)產(chǎn)品或者程序邏輯上不嚴(yán)謹(jǐn),就有可能出現(xiàn)功能上的錯(cuò)誤。比如我們15.3.4節(jié)里的這個(gè)程序,我們再回顧一下,當(dāng)單片機(jī)定時(shí)器時(shí)間到了 200 ms 后,我們連續(xù)把 DS1302 的時(shí)間參數(shù)的7個(gè)字節(jié)讀了出來。但是不管怎么讀,都會(huì)有一個(gè)時(shí)間差,在極端的情況下就會(huì)出現(xiàn)這樣一種情況:假如我們當(dāng)前的時(shí)間是00:00:59,我們先讀秒,讀到的秒是59,然后再去讀分鐘,而就在讀完秒到還未開始讀分鐘的這段時(shí)間內(nèi),剛好時(shí)間進(jìn)位了,變成了00:01:00這個(gè)時(shí)間,我們讀到的分鐘就是01,顯示在液晶上就會(huì)出現(xiàn)一個(gè)00:01:59,這個(gè)時(shí)間很明顯是錯(cuò)誤的。出現(xiàn)這個(gè)問題的概率極小,但卻是實(shí)實(shí)在在可能存在的。

為了解決這個(gè)問題,芯片廠家肯定要給我們提供一種解決方案,這就是 DS1302 的突發(fā)模式。突發(fā)模式也分為 RAM 突發(fā)模式和時(shí)鐘突發(fā)模式,RAM 部分我們不講,我們只看和時(shí)鐘相關(guān)的 clock burst mode。

當(dāng)我們寫指令到 DS1302 的時(shí)候,只要我們將要寫的5位地址全部寫1,即讀操作用 0xBF,寫操作用 0xBE,這樣的指令送給 DS1302 之后,它就會(huì)自動(dòng)識別出來是 burst 模式,馬上把所有的8個(gè)字節(jié)同時(shí)鎖存到另外的8個(gè)字節(jié)的寄存器緩沖區(qū)內(nèi),這樣時(shí)鐘繼續(xù)走,而我們讀數(shù)據(jù)是從另外一個(gè)緩沖區(qū)內(nèi)讀取的。同樣的道理,如果我們用 burst 模式寫數(shù)據(jù),那么我們也是先寫到這個(gè)緩沖區(qū)內(nèi),最終 DS1302 會(huì)把這個(gè)緩沖區(qū)內(nèi)的數(shù)據(jù)一次性送到它的時(shí)鐘寄存器內(nèi)。

要注意的是,不管是讀還是寫,只要使用時(shí)鐘的 burst 模式,則必須一次性讀寫8個(gè)寄存器,要把時(shí)鐘的寄存器完全讀出來或者完全寫進(jìn)去。

下邊就提供一個(gè) burst 模式的例程給大家學(xué)習(xí)一下,程序的功能還是與上一節(jié)一樣的。 /*Lcd1602.c 文件程序源代碼***/ (此處省略,可參考之前章節(jié)的代碼)

/*****************************main.c 文件程序源代碼******************************/
#include <reg52.h>

sbit DS1302_CE = P1^7;
sbit DS1302_CK = P3^5;
sbit DS1302_IO = P3^4;

bit flag200ms = 0; //200ms 定時(shí)標(biāo)志
unsigned char T0RH = 0; //T0 重載值的高字節(jié)
unsigned char T0RL = 0; //T0 重載值的低字節(jié)

void ConfigTimer0(unsigned int ms);
void InitDS1302();
void DS1302BurstRead(unsigned char *dat);
extern void InitLcd1602();
extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);

void main(){
    unsigned char psec=0xAA; //秒備份,初值 AA 確保首次讀取時(shí)間后會(huì)刷新顯示
    unsigned char time[8]; //當(dāng)前時(shí)間數(shù)組
    unsigned char str[12]; //字符串轉(zhuǎn)換緩沖區(qū)

    EA = 1; //開總中斷
    ConfigTimer0(1); //T0 定時(shí) 1ms
    InitDS1302(); //初始化實(shí)時(shí)時(shí)鐘
    InitLcd1602(); //初始化液晶

    while (1){
        if (flag200ms){ //每 200ms 讀取依次時(shí)間
            flag200ms = 0;
            DS1302BurstRead(time); //讀取 DS1302 當(dāng)前時(shí)間

            if (psec != time[0]){ //檢測到時(shí)間有變化時(shí)刷新顯示
                str[0] = '2'; //添加年份的高 2 位:20
                str[1] = '0';
                str[2] = (time[6] >> 4) + '0'; //“年”高位數(shù)字轉(zhuǎn)換為 ASCII 碼
                str[3] = (time[6]&0x0F) + '0'; //“年”低位數(shù)字轉(zhuǎn)換為 ASCII 碼
                str[4] = '-'; //添加日期分隔符
                str[5] = (time[4] >> 4) + '0'; //“月”
                str[6] = (time[4]&0x0F) + '0';
                str[7] = '-';
                str[8] = (time[3] >> 4) + '0'; //“日”
                str[9] = (time[3]&0x0F) + '0';
                str[10] = '\0';
                LcdShowStr(0, 0, str); //顯示到液晶的第一行

                str[0] = (time[5]&0x0F) + '0'; //“星期”
                str[1] = '\0';
                LcdShowStr(11, 0, "week");
                LcdShowStr(15, 0, str); //顯示到液晶的第一行

                str[0] = (time[2] >> 4) + '0'; //“時(shí)”
                str[1] = (time[2]&0x0F) + '0';
                str[2] = ':'; //添加時(shí)間分隔符
                str[3] = (time[1] >> 4) + '0'; //“分”
                str[4] = (time[1]&0x0F) + '0';
                str[5] = ':';
                str[6] = (time[0] >> 4) + '0'; //“秒”
                str[7] = (time[0]&0x0F) + '0';
                str[8] = '\0';
                LcdShowStr(4, 1, str); //顯示到液晶的第二行

                psec = time[0]; //用當(dāng)前值更新上次秒數(shù)
            }
        }
    }
}

/* 發(fā)送一個(gè)字節(jié)到 DS1302 通信總線上 */
void DS1302ByteWrite(unsigned char dat){
    unsigned char mask;
    for (mask=0x01; mask!=0; mask<<=1){ //低位在前,逐位移出
        if ((mask&dat) != 0){ //首先輸出該位數(shù)據(jù)
            DS1302_IO = 1;
        }else{
            DS1302_IO = 0;
        }
        DS1302_CK = 1; //然后拉高時(shí)鐘
        DS1302_CK = 0; //再拉低時(shí)鐘,完成一個(gè)位的操作
    }
    DS1302_IO = 1; //最后確保釋放 IO 引腳
}
/* 由 DS1302 通信總線上讀取一個(gè)字節(jié) */
unsigned char DS1302ByteRead(){
    unsigned char mask;
    unsigned char dat = 0;

    for (mask=0x01; mask!=0; mask<<=1){ //低位在前,逐位讀取
        if (DS1302_IO != 0){ //首先讀取此時(shí)的 IO 引腳,并設(shè)置 dat 中的對應(yīng)位
            dat |= mask;
        }
        DS1302_CK = 1; //然后拉高時(shí)鐘
        DS1302_CK = 0; //再拉低時(shí)鐘,完成一個(gè)位的操作
    }
    return dat; //最后返回讀到的字節(jié)數(shù)據(jù)
}
/* 用單次寫操作向某一寄存器寫入一個(gè)字節(jié),reg-寄存器地址,dat-待寫入字節(jié) */
void DS1302SingleWrite(unsigned char reg, unsigned char dat){
    DS1302_CE = 1; //使能片選信號
    DS1302ByteWrite((reg<<1)|0x80); //發(fā)送寫寄存器指令
    DS1302ByteWrite(dat); //寫入字節(jié)數(shù)據(jù)
    DS1302_CE = 0; //除能片選信號
}
/* 用單次讀操作從某一寄存器讀取一個(gè)字節(jié),reg-寄存器地址,返回值-讀到的字節(jié) */
unsigned char DS1302SingleRead(unsigned char reg){
    unsigned char dat;

    DS1302_CE = 1; //使能片選信號
    DS1302ByteWrite((reg<<1)|0x81); //發(fā)送讀寄存器指令
    dat = DS1302ByteRead(); //讀取字節(jié)數(shù)據(jù)
    DS1302_CE = 0; //除能片選信號
    return dat;
}
/* 用突發(fā)模式連續(xù)寫入 8 個(gè)寄存器數(shù)據(jù),dat-待寫入數(shù)據(jù)指針 */
void DS1302BurstWrite(unsigned char *dat){
    unsigned char i;

    DS1302_CE = 1;
    DS1302ByteWrite(0xBE); //發(fā)送突發(fā)寫寄存器指令

    for (i=0; i<8; i++){ //連續(xù)寫入 8 字節(jié)數(shù)據(jù)
        DS1302ByteWrite(dat[i]);
    }
    DS1302_CE = 0;
}
/* 用突發(fā)模式連續(xù)讀取 8 個(gè)寄存器的數(shù)據(jù),dat-讀取數(shù)據(jù)的接收指針 */
void DS1302BurstRead(unsigned char *dat){
    unsigned char i;

    DS1302_CE = 1;
    DS1302ByteWrite(0xBF); //發(fā)送突發(fā)讀寄存器指令
    for (i=0; i<8; i++){ //連續(xù)讀取 8 個(gè)字節(jié)
        dat[i] = DS1302ByteRead();
    }
    DS1302_CE = 0;
}
/* DS1302 初始化,如發(fā)生掉電則重新設(shè)置初始時(shí)間 */
void InitDS1302(){
    unsigned char dat;
    unsigned char code InitTime[] = { //2013 年 10 月 8 日 星期二 12:30:00
        0x00,0x30,0x12, 0x08, 0x10, 0x02, 0x13
    };

    DS1302_CE = 0; //初始化 DS1302 通信引腳
    DS1302_CK = 0;
    dat = DS1302SingleRead(0); //讀取秒寄存器

    if ((dat & 0x80) != 0){ //由秒寄存器最高位 CH 的值判斷 DS1302 是否已停止
        DS1302SingleWrite(7, 0x00); //撤銷寫保護(hù)以允許寫入數(shù)據(jù)
        DS1302BurstWrite(InitTime); //設(shè)置 DS1302 為默認(rèn)的初始時(shí)間
    }
}
/* 配置并啟動(dòng) T0,ms-T0 定時(shí)時(shí)間 */
void ConfigTimer0(unsigned int ms){
    unsigned long tmp; //臨時(shí)變量

    tmp = 11059200 / 12; //定時(shí)器計(jì)數(shù)頻率
    tmp = (tmp * ms) / 1000; //計(jì)算所需的計(jì)數(shù)值
    tmp = 65536 - tmp; //計(jì)算定時(shí)器重載值
    tmp = tmp + 12; //補(bǔ)償中斷響應(yīng)延時(shí)造成的誤差
    T0RH = (unsigned char)(tmp>>8); //定時(shí)器重載值拆分為高低字節(jié)
    T0RL = (unsigned char)tmp;
    TMOD &= 0xF0; //清零 T0 的控制位
    TMOD |= 0x01; //配置 T0 為模式 1
    TH0 = T0RH; //加載 T0 重載值
    TL0 = T0RL;
    ET0 = 1; //使能 T0 中斷
    TR0 = 1; //啟動(dòng) T0
}
/* T0 中斷服務(wù)函數(shù),執(zhí)行 200ms 定時(shí) */
void InterruptTimer0() interrupt 1{
    static unsigned char tmr200ms = 0;
    TH0 = T0RH; //重新加載重載值
    TL0 = T0RL;
    tmr200ms++;
    if (tmr200ms >= 200){ //定時(shí) 200ms
        tmr200ms = 0;
        flag200ms = 1;
    }
}