久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

DS1302通信時序介紹

 蒲公英的夢WCF 2018-09-07

  DS1302 我們前邊也有提起過,,是三根線,分別是 CE,、I/O 和 SCLK,,其中 CE 是使能線,SCLK 是時鐘線,,I/O 是數(shù)據(jù)線,。前邊我們介紹過了 SPI 通信,同學(xué)們發(fā)現(xiàn)沒發(fā)現(xiàn),,這個 DS1302的通信線定義和 SPI 怎么這么像呢?


  事實上,,DS1302 的通信是 SPI 的變異種類,它用了 SPI 的通信時序,,但是通信的時候沒有完全按照 SPI 的規(guī)則來,,下面我們一點點解剖 DS1302 的變異 SPI 通信方式。先看一下單字節(jié)寫入操作,,如圖 15-11 所示,。


                 



  圖 15-11 和圖 15-12 的通信時序,其中 CE 和 SSEL 的使能控制是反的,,對于通信寫數(shù)據(jù),,都是在 SCK 的上升沿,從機進行采樣,,下降沿的時候,,主機發(fā)送數(shù)據(jù),。DS1302 的時序里,單片機要預(yù)先寫一個字節(jié)指令,,指明要寫入的寄存器的地址以及后續(xù)的操作是寫操作,,然后再寫入一個字節(jié)的數(shù)據(jù)。


  對于單字節(jié)讀操作,,我就不做對比了,,把 DS1302 的時序圖貼出來,大家自己看一下即可,,如圖 15-13 所示,。


                  



  讀操作有兩處需要特別注意的地方。第一,,DS1302 的時序圖上的箭頭都是針對 DS1302來說的,,因此讀操作的時候,先寫第一個字節(jié)指令,,上升沿的時候 DS1302 來鎖存數(shù)據(jù),,下降沿我們用單片機發(fā)送數(shù)據(jù)。到了第二個字?jǐn)?shù)據(jù),,由于我們這個時序過程相當(dāng)于CPOL=0/CPHA=0,,前沿發(fā)送數(shù)據(jù),后沿讀取數(shù)據(jù),,第二個字節(jié)是 DS1302 下降沿輸出數(shù)據(jù),,我們的單片機上升沿來讀取,因此箭頭從 DS1302 角度來說,,出現(xiàn)在了下降沿,。


  第二個需要注意的地方就是,我們的單片機沒有標(biāo)準(zhǔn)的 SPI 接口,,和 I2C 一樣需要用 IO口來模擬通信過程,。在讀 DS1302 的時候,理論上 SPI 是上升沿讀取,,但是程序是用 IO 口模擬的,,所以數(shù)據(jù)的讀取和時鐘沿的變化不可能同時了,必然就有一個先后順序,。通過實驗發(fā)現(xiàn),,如果先讀取 IO 線上的數(shù)據(jù),再拉高 SCLK 產(chǎn)生上升沿,,那么讀到的數(shù)據(jù)一定是正確的,,而顛倒順序后數(shù)據(jù)就有可能出錯。這個問題產(chǎn)生的原因還是在于 DS1302 的通信協(xié)議與標(biāo)準(zhǔn)SPI 協(xié)議存在的差異造成的,如果是標(biāo)準(zhǔn) SPI 的數(shù)據(jù)線,,數(shù)據(jù)會一直保持到下一個周期的下降沿才會變化,,所以讀取數(shù)據(jù)和上升沿的先后順序就無所謂了;但 DS1302 的 IO 線會在時鐘上升沿后被 DS1302 釋放,也就是撤銷強推挽輸出變?yōu)槿跸吕瓲顟B(tài),,而此時在 51 單片機引腳內(nèi)部上拉的作用下,,IO 線上的實際電平會慢慢上升,從而導(dǎo)致在上升沿產(chǎn)生后再讀取 IO 數(shù)據(jù)的話就可能會出錯,。因此這里的程序我們按照先讀取 IO 數(shù)據(jù),再拉高 SCLK 產(chǎn)生上升沿的順序,。


  下面我們就寫一個程序,,先將 2013 年 10 月 8 號星期二 12 點 30 分 00 秒這個時間寫到DS1302 內(nèi)部,讓 DS1302 正常運行,,然后再不停的讀取 DS1302 的當(dāng)前時間,,并顯示在我們的液晶屏上。


  /***************************Lcd1602.c 文件程序源代碼*****************************/

  (此處省略,,可參考之前章節(jié)的代碼)




  1. /*****************************main.c 文件程序源代碼******************************/  
  2. #include   
  3.   
  4. sbit DS1302_CE = P1^7;  
  5. sbit DS1302_CK = P3^5;  
  6. sbit DS1302_IO = P3^4;  
  7. bit flag200ms = 0; //200ms 定時標(biāo)志  
  8. unsigned char T0RH = 0; //T0 重載值的高字節(jié)  
  9. unsigned char T0RL = 0; //T0 重載值的低字節(jié)  
  10.   
  11. void ConfigTimer0(unsigned int ms);  
  12. void InitDS1302();  
  13. unsigned char DS1302SingleRead(unsigned char reg);  
  14. extern void InitLcd1602();  
  15. extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);  
  16.   
  17. void main(){  
  18.     unsigned char i;  
  19.     unsigned char psec=0xAA; //秒備份,,初值 AA 確保首次讀取時間后會刷新顯示  
  20.     unsigned char time[8]; //當(dāng)前時間數(shù)組  
  21.     unsigned char str[12]; //字符串轉(zhuǎn)換緩沖區(qū)  
  22.     EA = 1; //開總中斷  
  23.     ConfigTimer0(1); //T0 定時 1ms  
  24.     InitDS1302(); //初始化實時時鐘  
  25.     InitLcd1602(); //初始化液晶  
  26.      
  27.     while (1){  
  28.         if (flag200ms){ //每 200ms 讀取一次時間  
  29.             flag200ms = 0;  
  30.             for (i=0; i<>//讀取 DS1302 當(dāng)前時間  
  31.                 time[i] = DS1302SingleRead(i);  
  32.             }  
  33.             if (psec != time[0]){ //檢測到時間有變化時刷新顯示  
  34.                 str[0] = '2'//添加年份的高 2 位:20  
  35.                 str[1] = '0';  
  36.                 str[2] = (time[6] >> 4) + '0'//“年”高位數(shù)字轉(zhuǎn)換為 ASCII 碼  
  37.                 str[3] = (time[6]&0x0F) + '0'//“年”低位數(shù)字轉(zhuǎn)換為 ASCII 碼  
  38.                 str[4] = '-'//添加日期分隔符  
  39.                 str[5] = (time[4] >> 4) + '0'//“月”  
  40.                 str[6] = (time[4]&0x0F) + '0';  
  41.                 str[7] = '-';  
  42.                 str[8] = (time[3] >> 4) + '0'//“日”  
  43.                 str[9] = (time[3]&0x0F) + '0';  
  44.                 str[10] = '\0';  
  45.                 LcdShowStr(0, 0, str); //顯示到液晶的第一行  
  46.                 str[0] = (time[5]&0x0F) + '0'//“星期”  
  47.                 str[1] = '\0';  
  48.                 LcdShowStr(11, 0, 'week');  
  49.                 LcdShowStr(15, 0, str); //顯示到液晶的第一行  
  50.                 str[0] = (time[2] >> 4) + '0'//“時”  
  51.                 str[1] = (time[2]&0x0F) + '0';  
  52.                 str[2] = ':'//添加時間分隔符  
  53.                 str[3] = (time[1] >> 4) + '0'//“分”  
  54.                 str[4] = (time[1]&0x0F) + '0';  
  55.                 str[5] = ':';  
  56.                 str[6] = (time[0] >> 4) + '0'//“秒”  
  57.                 str[7] = (time[0]&0x0F) + '0';  
  58.                 str[8] = '\0';  
  59.                 LcdShowStr(4, 1, str); //顯示到液晶的第二行  
  60.                 psec = time[0]; //用當(dāng)前值更新上次秒數(shù)  
  61.             }  
  62.         }  
  63.     }  
  64. }  
  65. /* 發(fā)送一個字節(jié)到 DS1302 通信總線上 */  
  66. void DS1302ByteWrite(unsigned char dat){  
  67.     unsigned char mask;  
  68.   
  69.     for (mask=0x01; mask!=0; mask<>//低位在前,逐位移出  
  70.         if ((mask&dat) != 0){ //首先輸出該位數(shù)據(jù)  
  71.             DS1302_IO = 1;  
  72.         }else{  
  73.             DS1302_IO = 0;  
  74.         }  
  75.         DS1302_CK = 1; //然后拉高時鐘  
  76.         DS1302_CK = 0; //再拉低時鐘,,完成一個位的操作  
  77.     }  
  78.     DS1302_IO = 1; //最后確保釋放 IO 引腳  
  79. }  
  80. /* 由 DS1302 通信總線上讀取一個字節(jié) */  
  81. unsigned char DS1302ByteRead(){  
  82.     unsigned char mask;  
  83.     unsigned char dat = 0;  
  84.      
  85.     for (mask=0x01; mask!=0; mask<>//低位在前,,逐位讀取  
  86.         if (DS1302_IO != 0){ //首先讀取此時的 IO 引腳,并設(shè)置 dat 中的對應(yīng)位  
  87.             dat |= mask;  
  88.         }  
  89.         DS1302_CK = 1; //然后拉高時鐘  
  90.         DS1302_CK = 0; //再拉低時鐘,,完成一個位的操作  
  91.     }  
  92.     return dat; //最后返回讀到的字節(jié)數(shù)據(jù)  
  93. }  
  94. /* 用單次寫操作向某一寄存器寫入一個字節(jié),,reg-寄存器地址,dat-待寫入字節(jié) */  
  95. void DS1302SingleWrite(unsigned char reg, unsigned char dat){  
  96.     DS1302_CE = 1; //使能片選信號  
  97.     DS1302ByteWrite((reg<>//發(fā)送寫寄存器指令  
  98.     DS1302ByteWrite(dat); //寫入字節(jié)數(shù)據(jù)  
  99.     DS1302_CE = 0; //除能片選信號  
  100. }  
  101. /* 用單次讀操作從某一寄存器讀取一個字節(jié),,reg-寄存器地址,,返回值-讀到的字節(jié) */  
  102. unsigned char DS1302SingleRead(unsigned char reg){  
  103.     unsigned char dat;  
  104.     DS1302_CE = 1; //使能片選信號  
  105.     DS1302ByteWrite((reg<>//發(fā)送讀寄存器指令  
  106.     dat = DS1302ByteRead()//讀取字節(jié)數(shù)據(jù)  
  107.     DS1302_CE = 0; //除能片選信號  
  108.     return dat;  
  109. }  
  110. /* DS1302 初始化,如發(fā)生掉電則重新設(shè)置初始時間 */  
  111. void InitDS1302(){  
  112.     unsigned char i;  
  113.     unsigned char code InitTime[] = { //2013 年 10 月 8 日 星期二 12:30:00  
  114.         0x00,0x30,0x12, 0x08, 0x10, 0x02, 0x13  
  115.     };  
  116.      
  117.     DS1302_CE = 0; //初始化 DS1302 通信引腳  
  118.     DS1302_CK = 0;  
  119.     i = DS1302SingleRead(0); //讀取秒寄存器  
  120.      
  121.     if ((i & 0x80) != 0){ //由秒寄存器最高位 CH 的值判斷 DS1302 是否已停止  
  122.         DS1302SingleWrite(7, 0x00); //撤銷寫保護以允許寫入數(shù)據(jù)  
  123.         for (i=0; i<>//設(shè)置 DS1302 為默認(rèn)的初始時間  
  124.             DS1302SingleWrite(i, InitTime[i]);  
  125.         }  
  126.     }  
  127. }  
  128. /* 配置并啟動 T0,,ms-T0 定時時間 */  
  129. void ConfigTimer0(unsigned int ms){  
  130.     unsigned long tmp; //臨時變量  
  131.     tmp = 11059200 / 12; //定時器計數(shù)頻率  
  132.     tmp = (tmp * ms) / 1000; //計算所需的計數(shù)值  
  133.     tmp = 65536 - tmp; //計算定時器重載值  
  134.     tmp = tmp + 12; //補償中斷響應(yīng)延時造成的誤差  
  135.     T0RH = (unsigned char)(tmp>>8); //定時器重載值拆分為高低字節(jié)  
  136.     T0RL = (unsigned char)tmp;  
  137.     TMOD &= 0xF0; //清零 T0 的控制位  
  138.     TMOD |= 0x01; //配置 T0 為模式 1  
  139.     TH0 = T0RH; //加載 T0 重載值  
  140.     TL0 = T0RL;  
  141.     ET0 = 1; //使能 T0 中斷  
  142.     TR0 = 1; //啟動 T0  
  143. }  
  144. /* T0 中斷服務(wù)函數(shù),,執(zhí)行 200ms 定時 */  
  145. void InterruptTimer0() interrupt 1{  
  146.     static unsigned char tmr200ms = 0;  
  147.     TH0 = T0RH; //重新加載重載值  
  148.     TL0 = T0RL;  
  149.     tmr200ms++;  
  150.     if (tmr200ms >= 200){ //定時 200ms  
  151.         tmr200ms = 0;  
  152.         flag200ms = 1;  
  153.     }  
  154. }  
/*****************************main.c 文件程序源代碼******************************/#include sbit DS1302_CE = P1^7;sbit DS1302_CK = P3^5;sbit DS1302_IO = P3^4;bit flag200ms = 0; //200ms 定時標(biāo)志unsigned char T0RH = 0; //T0 重載值的高字節(jié)unsigned char T0RL = 0; //T0 重載值的低字節(jié)void ConfigTimer0(unsigned int ms);void InitDS1302();unsigned char DS1302SingleRead(unsigned char reg);extern void InitLcd1602();extern void LcdShowStr(unsigned char x, unsigned char y, unsigned char *str);void main(){ unsigned char i; unsigned char psec=0xAA; //秒備份,初值 AA 確保首次讀取時間后會刷新顯示 unsigned char time[8]; //當(dāng)前時間數(shù)組 unsigned char str[12]; //字符串轉(zhuǎn)換緩沖區(qū) EA = 1; //開總中斷 ConfigTimer0(1); //T0 定時 1ms InitDS1302(); //初始化實時時鐘 InitLcd1602(); //初始化液晶 while (1){ if (flag200ms){ //每 200ms 讀取一次時間 flag200ms = 0; for (i=0; i<7; i++){="" 讀取="" ds1302="" 當(dāng)前時間="" time[i]="DS1302SingleRead(i);" }="" if="" (psec="" !="time[0]){" 檢測到時間有變化時刷新顯示="" 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'; //“時” str[1] = (time[2]&0x0F) + '0'; str[2] = ':'; //添加時間分隔符 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ā)送一個字節(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;" 然后拉高時鐘="" ds1302_ck="0;" 再拉低時鐘,,完成一個位的操作="" }="" ds1302_io="1;" 最后確保釋放="" io="" 引腳}/*="" 由="" ds1302="" 通信總線上讀取一個字節(jié)="" */unsigned="" char="" ds1302byteread(){="" unsigned="" char="" mask;="" unsigned="" char="" dat="0;" for="" (mask="0x01;" mask!="0;"><=1){ 低位在前,逐位讀取="" if="" (ds1302_io="" !="0){" 首先讀取此時的="" io="" 引腳,,并設(shè)置="" dat="" 中的對應(yīng)位="" dat="" |="mask;" }="" ds1302_ck="1;" 然后拉高時鐘="" ds1302_ck="0;" 再拉低時鐘,,完成一個位的操作="" }="" return="" dat;="" 最后返回讀到的字節(jié)數(shù)據(jù)}/*="" 用單次寫操作向某一寄存器寫入一個字節(jié),reg-寄存器地址,,dat-待寫入字節(jié)="" */void="" ds1302singlewrite(unsigned="" char="" reg,="" unsigned="" char="" dat){="" ds1302_ce="1;" 使能片選信號=""><1)|0x80); 發(fā)送寫寄存器指令="" ds1302bytewrite(dat);="" 寫入字節(jié)數(shù)據(jù)="" ds1302_ce="0;" 除能片選信號}/*="" 用單次讀操作從某一寄存器讀取一個字節(jié),,reg-寄存器地址,返回值-讀到的字節(jié)="" */unsigned="" char="" ds1302singleread(unsigned="" char="" reg){="" unsigned="" char="" dat;="" ds1302_ce="1;" 使能片選信號=""><1)|0x81); 發(fā)送讀寄存器指令="" dat="DS1302ByteRead()//讀取字節(jié)數(shù)據(jù)" ds1302_ce="0;" 除能片選信號="" return="" dat;}/*="" ds1302="" 初始化,如發(fā)生掉電則重新設(shè)置初始時間="" */void="" initds1302(){="" unsigned="" char="" i;="" unsigned="" char="" code="" inittime[]="{" 2013="" 年="" 10="" 月="" 8="" 日="" 星期二="" 12:30:00="" 0x00,0x30,0x12,="" 0x08,="" 0x10,="" 0x02,="" 0x13="" };="" ds1302_ce="0;" 初始化="" ds1302="" 通信引腳="" ds1302_ck="0;" i="DS1302SingleRead(0);" 讀取秒寄存器="" if="" ((i="" &="" 0x80)="" !="0){" 由秒寄存器最高位="" ch="" 的值判斷="" ds1302="" 是否已停止="" ds1302singlewrite(7,="" 0x00);="" 撤銷寫保護以允許寫入數(shù)據(jù)="" for="" (i="0;"><7; i++){="" 設(shè)置="" ds1302="" 為默認(rèn)的初始時間="" ds1302singlewrite(i,="" inittime[i]);="" }="" }}/*="" 配置并啟動="" t0,,ms-t0="" 定時時間="" */void="" configtimer0(unsigned="" int="" ms){="" unsigned="" long="" tmp;="" 臨時變量="" tmp="11059200" 12;="" 定時器計數(shù)頻率="" tmp="(tmp" *="" ms)="" 1000;="" 計算所需的計數(shù)值="" tmp="65536" -="" tmp;="" 計算定時器重載值="" tmp="tmp" +="" 12;="" 補償中斷響應(yīng)延時造成的誤差="" t0rh="(unsigned" char)(tmp="">>8); //定時器重載值拆分為高低字節(jié) T0RL = (unsigned char)tmp; TMOD &= 0xF0; //清零 T0 的控制位 TMOD |= 0x01; //配置 T0 為模式 1 TH0 = T0RH; //加載 T0 重載值 TL0 = T0RL; ET0 = 1; //使能 T0 中斷 TR0 = 1; //啟動 T0}/* T0 中斷服務(wù)函數(shù),,執(zhí)行 200ms 定時 */void InterruptTimer0() interrupt 1{ static unsigned char tmr200ms = 0; TH0 = T0RH; //重新加載重載值 TL0 = T0RL; tmr200ms++; if (tmr200ms >= 200){ //定時 200ms tmr200ms = 0; flag200ms = 1; }}

 

  前邊學(xué)習(xí)了 I2C 和 EEPROM 的底層讀寫時序,那么 DS1302 的底層讀寫時序程序的實現(xiàn)方法是與之類似的,,這里就不過多解釋了,,大家自己認(rèn)真揣摩一下。



    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多