欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 21035|回復(fù): 9
收起左側(cè)

51單片機(jī)I2C詳解與程序源碼

  [復(fù)制鏈接]
ID:338578 發(fā)表于 2018-5-26 12:09 | 顯示全部樓層 |閱讀模式
I2C是由Philips公司發(fā)明的一種串行數(shù)據(jù)通信協(xié)議,僅使用兩根信號(hào)線:SerialClock(簡(jiǎn)稱SCL)和SerialData(簡(jiǎn)稱SDA)。I2C是總線結(jié)構(gòu),1個(gè)Master,1個(gè)或多個(gè)Slave,各Slave設(shè)備以7位地址區(qū)分,地址后面再跟1位讀寫位,表示讀(=1)或者寫(=0),所以我們有時(shí)也可看到8位形式的設(shè)備地址,此時(shí)每個(gè)設(shè)備有讀、寫兩個(gè)地址,高7位地址其實(shí)是相同的。
I2C數(shù)據(jù)格式如下:
無數(shù)據(jù):SCL=1,SDA=1;
開始位(Start):當(dāng)SCL=1時(shí),SDA由1向0跳變;
停止位(Stop):當(dāng)SCL=1時(shí),SDA由0向1跳變;
數(shù)據(jù)位:當(dāng)SCL由0向1跳變時(shí),由發(fā)送方控制SDA,此時(shí)SDA為有效數(shù)據(jù),不可隨意改變SDA;
當(dāng)SCL保持為0時(shí),SDA上的數(shù)據(jù)可隨意改變;
地址位:定義同數(shù)據(jù)位,但只由Master發(fā)給Slave;
應(yīng)答位(ACK):當(dāng)發(fā)送方傳送完8位時(shí),發(fā)送方釋放SDA,由接收方控制SDA,且SDA=0;
否應(yīng)答位(NACK):當(dāng)發(fā)送方傳送完8位時(shí),發(fā)送方釋放SDA,由接收方控制SDA,且SDA=1。

當(dāng)數(shù)據(jù)為單字節(jié)傳送時(shí),格式為:
開始位,8位地址位(含1位讀寫位),應(yīng)答,8位數(shù)據(jù),應(yīng)答,停止位。
當(dāng)數(shù)據(jù)為一串字節(jié)傳送時(shí),格式為:
開始位,8位地址位(含1位讀寫位),應(yīng)答,8位數(shù)據(jù),應(yīng)答,8位數(shù)據(jù),應(yīng)答,……,8位數(shù)據(jù),應(yīng)答,停止位。

需要注意的是:
1,SCL一直由Master控制,SDA依照數(shù)據(jù)傳送的方向,讀數(shù)據(jù)時(shí)由Slave控制SDA,寫數(shù)據(jù)時(shí)由Master控制SDA。當(dāng)8位數(shù)據(jù)傳送完畢之后,應(yīng)答位或者否應(yīng)答位的SDA控制權(quán)與數(shù)據(jù)位傳送時(shí)相反。
2,開始位“Start”和停止位“Stop”,只能由Master來發(fā)出。
3,地址的8位傳送完畢后,成功配置地址的Slave設(shè)備必須發(fā)送“ACK”。否則否則一定時(shí)間之后Master視為超時(shí),將放棄數(shù)據(jù)傳送,發(fā)送“Stop”。
4,當(dāng)寫數(shù)據(jù)的時(shí)候,Master每發(fā)送完8個(gè)數(shù)據(jù)位,Slave設(shè)備如果還有空間接受下一個(gè)字節(jié)應(yīng)該回答“ACK”,Slave設(shè)備如果沒有空間接受更多的字節(jié)應(yīng)該回答“NACK”,Master當(dāng)收到“NACK”或者一定時(shí)間之后沒收到任何數(shù)據(jù)將視為超時(shí),此時(shí)Master放棄數(shù)據(jù)傳送,發(fā)送“Stop”。
5,當(dāng)讀數(shù)據(jù)的時(shí)候,Slave設(shè)備每發(fā)送完8個(gè)數(shù)據(jù)位,如果Master希望繼續(xù)讀下一個(gè)字節(jié),Master應(yīng)該回答“ACK”以提示Slave準(zhǔn)備下一個(gè)數(shù)據(jù),如果Master不希望讀取更多字節(jié),Master應(yīng)該回答“NACK”以提示Slave設(shè)備準(zhǔn)備接收Stop信號(hào)。
6,當(dāng)Master速度過快Slave端來不及處理時(shí),Slave設(shè)備可以拉低SCL不放(SCL=0將發(fā)生“線與”)以阻止Master發(fā)送更多的數(shù)據(jù)。此時(shí)Master將視情況減慢或結(jié)束數(shù)據(jù)傳送。

在實(shí)際應(yīng)用中,并沒有強(qiáng)制規(guī)定數(shù)據(jù)接收方必須對(duì)于發(fā)送的8位數(shù)據(jù)做出回應(yīng),尤其是在Master和Slave端都是用GPIO軟件模擬的方法來實(shí)現(xiàn)的情況下,編程者可以事先約定數(shù)據(jù)傳送的長(zhǎng)度,slave不檢查NACK,有時(shí)可以起到減少系統(tǒng)開銷的效果。但是如果slave方是硬件i2c要求一定要標(biāo)準(zhǔn)的NACK,master方是GPIO軟件模擬i2c并沒有正確的發(fā)送NACK,就會(huì)出現(xiàn)“slave收不到stop”導(dǎo)致i2c掛死。

在正常情況下,I2C總線協(xié)議能夠保證總線正常的讀寫操作。但是,當(dāng)I2C主設(shè)備異常復(fù)位時(shí)(看門狗動(dòng)作,板上電源異常導(dǎo)致復(fù)位芯片動(dòng)作,手動(dòng)按鈕復(fù)位等等)有可能導(dǎo)致I2C總線死鎖產(chǎn)生。下面詳細(xì)說明一下總線死鎖產(chǎn)生的原因。

    在I2C主設(shè)備進(jìn)行讀寫操作的過程中.主設(shè)備在開始信號(hào)后控制SCL產(chǎn)生8個(gè)時(shí)鐘脈沖,然后拉低SCL信號(hào)為低電平,在這個(gè)時(shí)候,從設(shè)備輸出應(yīng)答信號(hào),將SDA信號(hào)拉為低電平。如果這個(gè)時(shí)候主設(shè)備異常復(fù)位,SCL就會(huì)被釋放為高電平。此時(shí),如果從設(shè)備沒有復(fù)位,就會(huì)繼續(xù)I2C的應(yīng)答,將SDA一直拉為低電平,直到SCL變?yōu)榈碗娖剑艜?huì)結(jié)束應(yīng)答信號(hào)。而對(duì)于I2C主設(shè)備來說.復(fù)位后檢測(cè)SCL和SDA信號(hào),如果發(fā)現(xiàn)SDA信號(hào)為低電平,則會(huì)認(rèn)為I2C總線被占用,會(huì)一直等待SCL和SDA信號(hào)變?yōu)楦唠娖健_@樣,I2C主設(shè)備等待從設(shè)備釋放SDA信號(hào),而同時(shí)I2C從設(shè)備又在等待主設(shè)備將SCL信號(hào)拉低以釋放應(yīng)答信號(hào),兩者相互等待,I2C總線進(jìn)人一種死鎖狀態(tài)。同樣,當(dāng)I2C進(jìn)行讀操作,I2C從設(shè)備應(yīng)答后輸出數(shù)據(jù),如果在這個(gè)時(shí)刻I2C主設(shè)備異常復(fù)位而此時(shí)I2C從設(shè)備輸出的數(shù)據(jù)位正好為0,也會(huì)導(dǎo)致I2C總線進(jìn)入死鎖狀態(tài)。

方法

    (1)盡量選用帶復(fù)位輸人的I2C從器件。

    (2)將所有的從I2C設(shè)備的電源連接在一起,通過MOS管連接到主電源,而MOS管的導(dǎo)通關(guān)斷由I2C主設(shè)備來實(shí)現(xiàn)。
    (3)在I2C從設(shè)備設(shè)計(jì)看門狗的功能。

    (4)在I2C主設(shè)備中增加I2C總線恢復(fù)程序。

        每次I2C主設(shè)備復(fù)位后,如果檢測(cè)到SDA數(shù)據(jù)線被拉低,則控制I2C中的SCL時(shí)鐘線產(chǎn)生9個(gè)時(shí)鐘脈沖(針對(duì)8位數(shù)據(jù)的情況,“9個(gè)clk可以激活”的方法來自NXP的文檔,NXP(Philips)作為I2C總線的鼻祖,這樣的說法是可信的),這樣I2C從設(shè)備就可以完成被掛起的讀操作,從死鎖狀態(tài)中恢復(fù)過來。

        這種方法有很大的局限性,因?yàn)榇蟛糠种髟O(shè)備的I2C模塊由內(nèi)置的硬件電路來實(shí)現(xiàn),軟件并不能夠直接控制SCL信號(hào)模擬產(chǎn)生需要時(shí)鐘脈沖。

        或者,發(fā)送I2C_Stop條件也能讓從設(shè)備釋放總線。

        如果是GPIO模擬I2C總線實(shí)現(xiàn),那么在I2C操作之前,加入I2C總線狀態(tài)檢測(cè)I2C_Probe,如果總線被占用,則可嘗試恢復(fù)總線,待總線釋放后,再進(jìn)行操作。要保證I2C操作最小單元的完整性,不被其他事件(中斷、高優(yōu)先級(jí)線程,等)打斷。

  (5)在I2C總線上增加一個(gè)額外的總線恢復(fù)設(shè)備。這個(gè)設(shè)備監(jiān)視I2C總線。當(dāng)設(shè)備檢測(cè)到SDA信號(hào)被拉低超過指定時(shí)間時(shí),就在SCL總線上產(chǎn)生9個(gè)時(shí)鐘脈沖,使I2C從設(shè)備完成讀操作,從死鎖狀態(tài)上恢復(fù)出來。總線恢復(fù)設(shè)備需要有具有編程功能,一般可以用單片機(jī)或CPLD實(shí)現(xiàn)這一功能。

  (6)在I2C上串人一個(gè)具有死鎖恢復(fù)的I2C緩沖器,如Linear公司的LTC4307是一個(gè)雙向的I2C總線緩沖器,并且具有I2C總線死鎖恢復(fù)的功能。LTC4307總線輸入側(cè)連接主設(shè)備,總線輸出側(cè)連接所有從設(shè)備。當(dāng)LTC4307檢測(cè)到輸出側(cè)SDA或SCL信號(hào)被拉低30ms時(shí),就自動(dòng)斷開I2C總線輸入側(cè)與輸出側(cè)的連接.并且在輸出側(cè)SCL信號(hào)上產(chǎn)生16個(gè)時(shí)鐘脈沖來釋放總線。當(dāng)總線成功恢復(fù)后,LTC4307會(huì)再次連接輸入輸出側(cè),使總線能夠正常工作。


  1. void I2Cstart()//開始標(biāo)志  
  2. {     
  3.     SDA=1;  
  4.     SCL=1;  
  5.     SDA=0;  
  6.     delay1ms(4);  
  7.     SCL=0;  
  8.     delay1ms(4);  
  9. }  
  10. void I2Cstop()//結(jié)束標(biāo)志  
  11. {  
  12.     SCL=0;  
  13.     delay1ms(4);  
  14.     SDA=0;  
  15.     delay1ms(4);  
  16.     SCL=1;  
  17.     delay1ms(4);  
  18.     SDA=1;  
  19.     delay1ms(4);  
  20. }  
  21. unsigned char I2Creadack()  
  22. {  
  23.     unsigned char i,byte;  
  24.     byte=0;  
  25.     for(i=0;i<8;i++)  
  26.     {  
  27.         SCL=0;  
  28.         SDA=1;  
  29.         delay1ms(4);  
  30.         byte<<=1;  
  31.         if(SDA==1)  
  32.         {  
  33.             byte|=0x01;  
  34.             delay1ms(4);  
  35.         }  
  36.     }  
  37.     SCL=0;  
  38.     delay1ms(4);  
  39.     SDA=0;  
  40.     delay1ms(4);  
  41.     SCL=1;  
  42.     delay1ms(4);  
  43.     SCL=0;  
  44.     return byte;  
  45. }  
  46. void I2Csend(unsigned char byte)//I2C寫數(shù)據(jù)的過程  
  47. {  
  48.   
  49.     unsigned char mask,i;  
  50.     for(i=0;i<8;i++)  
  51.     {     
  52.         SCL=0;  
  53.         if((mask&byte)==0)  
  54.         {  
  55.             SDA=0;  
  56.         }  
  57.         else  
  58.         {  
  59.             SDA=1;  
  60.         }  
  61.         mask>>=1;  
  62.         delay1ms(4);  
  63.         SCL=1;//給足夠時(shí)間讓數(shù)據(jù)讀取  
  64.         delay1ms(4);  
  65.   
  66.     }  
  67.     SCL=0;  
  68.     SDA=1;      //因?yàn)榭偩上有一個(gè)信號(hào)為低則低  
  69.     delay1ms(4);  
  70.     SCL=1;  
  71.     delay1ms(4);//等待應(yīng)答位  
  72.     SCL=0;  
  73. }  
  74. unsigned char I2Cread(void)  
  75. {  
  76.     unsigned char i,byte;  
  77.     byte =0;  
  78.     for(i=0;i<8;i++)  
  79.     {  
  80.         SCL=0;  
  81.         SDA=1;//讀數(shù)據(jù)必須拉高  
  82.         delay1ms(4);  
  83.         SCL=1;//數(shù)據(jù)穩(wěn)定  
  84.         delay1ms(4);  
  85.         byte<<=1;  
  86.         if(SDA==1)  
  87.         {  
  88.             byte|=0x01;  
  89.         }  
  90.         delay1ms(4);  
  91.     }  
  92.     SCL=0;  
  93.     delay1ms(4);  
  94.     SDA=0;//發(fā)送的應(yīng)答位  
  95.     delay1ms(4);  
  96.     SCL=1;  
  97.     delay1ms(4);  
  98.     SCL=0;  
  99.     return byte;  
  100. }  
  101. unsigned char I2Cread_eeprom(unsigned char addr)//I2C讀取數(shù)據(jù)  
  102. {  
  103.     unsigned char datebyte,datebyte2;  
  104.     I2Cstart();  
  105.     I2Csend(0xa0);//寫數(shù)據(jù)  
  106.     I2Csend(addr);  
  107.     I2Cstart();  
  108.     I2Csend(0xa1);//讀數(shù)據(jù)  
  109.     datebyte2=I2Creadack();  
  110.     datebyte=I2Cread();  
  111.     I2Cstop();  
  112.     return datebyte;  
  113.   
  114. }  
  115.   
  116. void write_eeprom(unsigned char addr,unsigned char datebyte)  
  117. {  
  118.     I2Cstart();  
  119.     I2Csend(0xa0);  
  120.     I2Csend(addr);  
  121.     I2Csend(datebyte);  
  122.     I2Cstop();  
  123. }  
復(fù)制代碼


i2c.zip

723 Bytes, 下載次數(shù): 179, 下載積分: 黑幣 -5

示例程序

評(píng)分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:184273 發(fā)表于 2018-8-22 15:39 | 顯示全部樓層
多謝樓主分享!
回復(fù)

使用道具 舉報(bào)

ID:585781 發(fā)表于 2019-7-22 14:41 | 顯示全部樓層
這個(gè)i2c協(xié)議真厲害
回復(fù)

使用道具 舉報(bào)

ID:476487 發(fā)表于 2019-9-24 10:45 | 顯示全部樓層
講解真詳細(xì),謝謝樓主分享
回復(fù)

使用道具 舉報(bào)

ID:18797 發(fā)表于 2019-10-4 17:47 | 顯示全部樓層
謝謝,進(jìn)一步增強(qiáng)了對(duì)IIC的認(rèn)識(shí)
回復(fù)

使用道具 舉報(bào)

6#
無效樓層,該帖已經(jīng)被刪除
ID:558533 發(fā)表于 2019-10-15 08:54 | 顯示全部樓層
謝謝樓主,
回復(fù)

使用道具 舉報(bào)

ID:476274 發(fā)表于 2020-2-16 20:32 | 顯示全部樓層
不錯(cuò),學(xué)習(xí)下
回復(fù)

使用道具 舉報(bào)

9#
無效樓層,該帖已經(jīng)被刪除
ID:891939 發(fā)表于 2021-4-1 00:23 | 顯示全部樓層
請(qǐng)問  if((mask&byte)==0)   此語句怎么理解?mask沒初始化,它和參數(shù)byte按位與結(jié)果不都是0x00嗎?
回復(fù)

使用道具 舉報(bào)

ID:24486 發(fā)表于 2024-3-13 20:56 | 顯示全部樓層
xxx1949 發(fā)表于 2021-4-1 00:23
請(qǐng)問  if((mask&byte)==0)   此語句怎么理解?mask沒初始化,它和參數(shù)byte按位與結(jié)果不都是0x00嗎?

講解真詳細(xì),謝謝樓主分享
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

快速回復(fù) 返回頂部 返回列表