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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7834|回復(fù): 20
打印 上一主題 下一主題
收起左側(cè)

關(guān)于I2C總線讀寫應(yīng)答機制

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:266429 發(fā)表于 2021-10-26 10:06 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
I2C總線中的應(yīng)答機制,屬于該總線規(guī)格中的關(guān)鍵內(nèi)容,本來并不復(fù)雜,也很容易理解,但問題在于現(xiàn)有的教材基本都是含糊不清,有的甚至?xí)鹫`解。因此,有必要詳細(xì)說明。
先說明兩個I2C總線中很重要的規(guī)則:
1. 總線在正常工作期間,從器件對時鐘線無控制權(quán),即從器件的時鐘端口輸出應(yīng)始終保持在高電位,時鐘線的狀態(tài),只能由主器件進(jìn)行操作;至于數(shù)據(jù)線,則主器件與從器件都有權(quán)參與操作。
2. 總線正常工作時,時鐘線處于高電位期間,不允許改變數(shù)據(jù)線的狀態(tài),即此時無論主器件還是從器件,都不能對其數(shù)據(jù)端口進(jìn)行狀態(tài)改變,除非是起始和終止操作。
記住這兩個規(guī)則,很重要。
以下均通過AT24C的驗證。

一、應(yīng)答原理
I2C總線,有點像我們用的對講機,盡管可以雙向通訊,但雙方不能同時說話,于是,就必須設(shè)有應(yīng)答機制,而且,這個應(yīng)答機制,必須是雙方互動的,一方的話說完了,就要問對方收到?jīng)]有,對方如果收到了這個問話,還得要再回個話。

二、向從器件寫入時的應(yīng)答機制
I2C與這種對講機的應(yīng)答的具體方式還是有些不一樣的,規(guī)定是這樣:在主機向從機發(fā)送數(shù)據(jù)時,規(guī)定每次發(fā)送一字節(jié)后就進(jìn)行應(yīng)答,主機每發(fā)送一字節(jié)數(shù)據(jù)后就停一下等待從機的反應(yīng),從機在收到一字節(jié)后的反應(yīng)就是將其自身的數(shù)據(jù)端輸出低電位,也就是向主機發(fā)出信號說自己剛收到一字節(jié),并等待主機的回應(yīng);主機接下來的操作就是拉高自身的數(shù)據(jù)端口電位,再檢測端口電位是否為低,如果檢測到為低,則認(rèn)為從機已經(jīng)收到了一個字節(jié),然后要告訴從機我知道了也就是給從機一個回應(yīng),回應(yīng)的方法是將時鐘線操作一個完整的總線時鐘周期即先拉高再拉低;從器件在收到主器件的這個回應(yīng)后,就將其自身數(shù)據(jù)端口的電位拉高即交出對數(shù)據(jù)線的控制權(quán),這樣就完成了一次完整的應(yīng)答。
以上的時序是不能弄錯的,比如主器件在發(fā)送完成一字節(jié)數(shù)據(jù)后,拉高數(shù)據(jù)線端以檢測從器件的應(yīng)答信號的操作,按I2C總線的規(guī)則必須先將時鐘線拉低才能再改變數(shù)據(jù)線,而一字節(jié)從發(fā)送到完成應(yīng)答,時鐘線的操作只能是9個總線周期,這9個總線周期中減除最后一個完整的應(yīng)答總線時鐘周期,那這個拉低的時間只能是安排在第8個周期。
另外,我們可以做一個實驗,就是監(jiān)測數(shù)據(jù)線的電位高低變化,從實驗結(jié)果來看,在寫數(shù)據(jù)時,如果發(fā)送的數(shù)據(jù)的第0位為1的話,在時鐘線第8個總線周期的高電位時,數(shù)據(jù)線的電位也為高電位;而接下來時鐘線電位一旦變低,則數(shù)據(jù)線的電位也同時變?yōu)榈碗娖剑簿褪钦f,這時從器件將對其自身的數(shù)據(jù)端口輸出低電位,這個就是從器件在寫入數(shù)據(jù)時的應(yīng)答信號,這個信號是在第8個總線時鐘周期的低電位時發(fā)出的,而非有些教材說的在第9個時鐘周期時發(fā)出。

三、從發(fā)送方與接收方的角度來說明
對于i2c總線來說,在數(shù)據(jù)傳輸時,無論是主器件還是從器件,無論是讀還是寫,接收方在收到一字節(jié)數(shù)據(jù)后,規(guī)定是在時鐘線處于低電位時,立即在其數(shù)據(jù)端輸出低電平,而發(fā)送方則立即在其數(shù)據(jù)端口輸出高電平,然后發(fā)送方對數(shù)據(jù)線的電位進(jìn)行檢測,所以,我們在編寫程序時,對于讀和寫的應(yīng)答,程序是不一樣的,寫入時,程序是將數(shù)據(jù)線拉高;讀取時,是將數(shù)據(jù)線拉低。如果你在讀取時仍編寫成拉高數(shù)據(jù)線的電位,那就沒法連續(xù)讀取數(shù)據(jù)了。
以上操作之后,時鐘線發(fā)出第9個周期來完成雙方的互動式應(yīng)答并復(fù)位主從器件的數(shù)據(jù)端口輸出值,即接收方釋放對數(shù)據(jù)線的控制權(quán),將這個控制權(quán)交還給發(fā)送方,以便發(fā)送方向數(shù)據(jù)線輸出數(shù)據(jù)。根據(jù)總線正常工作期間,時鐘線處于高電位時不得改變數(shù)據(jù)線狀態(tài)的規(guī)則,接收方只能在第9個周期的低電位期間向其自身的數(shù)據(jù)端口輸出高電位。

四、從接收方應(yīng)答的必須動作的角度來說明
我們再換一個角度來作說明,數(shù)據(jù)接收器件的應(yīng)答有兩個動作,一個是發(fā)出表示自己收到了一字節(jié)的信號,就是向其數(shù)據(jù)端口輸出低電平,第二個動作是釋放數(shù)據(jù)端口。這兩個動作的發(fā)生時間均需由主器件的時鐘線發(fā)出的信號來控制,其發(fā)生的時序只能分配在第8、第9這最后兩個時鐘周期中執(zhí)行,具體是第一個動作在第8個時鐘周期時執(zhí)行,第二個動作是在第9個時鐘周期時執(zhí)行。按照總線正常工作期間,時鐘線處于高電位時不得改變數(shù)據(jù)線的狀態(tài)的原則,這兩個動作只能在時鐘線處于低電位時執(zhí)行。
所以,讀數(shù)據(jù)操作時,從器件在發(fā)送完成一字節(jié)數(shù)據(jù)后,在第8個總線時鐘周期中時鐘線處于低電位時,會立即釋放數(shù)據(jù)線的控制權(quán),然后等待主器件的繼續(xù)讀取或停止指令。

五、讀指令發(fā)出后的應(yīng)答機制
按照讀取數(shù)據(jù)時,先在時鐘線低電位時期放數(shù)據(jù),再拉高時鐘線進(jìn)行讀取的規(guī)定,則我們可以知道,在主器件讀取第一個字節(jié)的操作中,一旦從器件收到一字節(jié)的讀取指令,從器件就會與主器件互動進(jìn)行應(yīng)答,這個應(yīng)答自然是按寫狀態(tài)進(jìn)行操作,然后在第9個總線時鐘周期的低電平時期,從器件就會把所要讀取的這一字節(jié)數(shù)據(jù)的第7位數(shù)據(jù)放在數(shù)據(jù)線上,然后主器件就會拉高時鐘線電位后進(jìn)行讀取,然后拉低時鐘線以讓從器件放上第6位數(shù)據(jù),依此順推。
讀數(shù)據(jù)時,第一個應(yīng)答信號中各動作后的電位變化如下:
i2cstart();//再次啟動總線,開始讀
I2cSendByte(0xa1); //向從器件寫入讀指令,讀取某一存儲單元中為10010110的數(shù)據(jù)。此動作后,數(shù)據(jù)線為低
   I2CSDA=1;delayms(1);//此動作后,數(shù)據(jù)線仍為低
I2CSCL=1;delayms(1);//此動作后,數(shù)據(jù)線仍為低
I2CSCL=0;delayms(1); //此動作后,數(shù)據(jù)線變?yōu)楦撸f明應(yīng)答一完成,從器件即將第7位數(shù)據(jù)(為1)放在了數(shù)據(jù)線上
說明一下,以上試驗,是本人在數(shù)據(jù)端口和時鐘端口分別接了一個燈(串了限流電阻)進(jìn)行觀察所得。

六、關(guān)于非應(yīng)答信號的質(zhì)疑
前面說過了,數(shù)據(jù)發(fā)送方在發(fā)送完成一字節(jié)后,會立即釋放對數(shù)據(jù)線的控制權(quán),所以,有些教材中“當(dāng)主器件接收數(shù)據(jù)時,在最后一個數(shù)據(jù)字節(jié),必須發(fā)送一個非應(yīng)答位,使受控器件釋放數(shù)據(jù)線,以便主器件產(chǎn)生一個停止信號來終止總線數(shù)據(jù)傳輸”的說法是有問題的,因為最后一個字節(jié)發(fā)出去之后,受控器件已經(jīng)主動釋放了數(shù)據(jù)線。當(dāng)然了,你也可以這樣做,并不影響程序的運行,但我們不能這樣理解。
我們知道,每一次的數(shù)據(jù)傳輸之后,從器件的存儲器單元地址指針值都會加1,這個從器件存儲單元地址值加1的時序時間,是在從器件發(fā)送或接收到一個完整的字節(jié)后就立即進(jìn)行的,與有無應(yīng)答操作無關(guān),所以,讀取最后一個數(shù)據(jù)后,我們根本無需進(jìn)行所謂的非應(yīng)答操作,而是可以直接發(fā)出停止信號退出總線。關(guān)于這一點,你可以進(jìn)行試驗,在直接退出后,緊跟著輸入一個讀指令進(jìn)行讀一個從器件單元中的數(shù)據(jù)的操作,一是看看這個退出是否是正常退出,二是看看讀出的結(jié)果是上一次操作中的最后一個單元的數(shù)據(jù)還是下一個單元的數(shù)據(jù)。

七、中斷應(yīng)答
對于從器件這個情況比較少見,但也不是不可能發(fā)生,而主器件則不奇怪。
主器件對于自身中斷的處理比較容易,沒什么特殊的。
從器件在收到一字節(jié)數(shù)據(jù)后,如果暫時不想繼續(xù)接收數(shù)據(jù)比如其要先處理中斷,則可以將其時鐘線置低電位以獲取對時鐘的控制權(quán)。因此,嚴(yán)格來說,主器件每向從器件發(fā)送完成一字節(jié)后,主器件都應(yīng)該檢測時鐘線及數(shù)據(jù)線的電位,以判斷從器件的狀態(tài)并確定其下一步的動作。

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏4 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

沙發(fā)
ID:266429 發(fā)表于 2021-10-26 21:15 | 只看該作者
讀應(yīng)答有以下四個動作:
i2csda=0;delayus(4);
   i2cscl=1;delayus(4);
   i2cscl=0;delayus(4);
   i2csda=1;delayus(4);
最后一個動作是主器件釋放對數(shù)據(jù)線的控制權(quán),千萬別忘了。
回復(fù)

使用道具 舉報

無效樓層,該帖已經(jīng)被刪除
地板
ID:262 發(fā)表于 2021-10-27 17:26 | 只看該作者
好資料,51黑有你更精彩!!!
回復(fù)

使用道具 舉報

5#
ID:266429 發(fā)表于 2021-10-27 19:45 | 只看該作者
本篇有些內(nèi)容,顯然與教材是相沖突的,反正,要么教材錯了,要么我錯了,到底誰對誰錯呢?希望大家吱個聲。
回復(fù)

使用道具 舉報

6#
ID:123289 發(fā)表于 2021-10-28 10:40 | 只看該作者
總結(jié)的很優(yōu)秀,值得對I2C通訊認(rèn)識模糊的人認(rèn)真讀一下。
給個
回復(fù)

使用道具 舉報

7#
ID:401564 發(fā)表于 2021-10-28 11:26 | 只看該作者
二、向從器件寫入時的應(yīng)答機制
這個就是在第9個時鐘周期的時候,輸出應(yīng)答位的,說破天了也是第9個
24Cxx是上升沿寫入的,在寫入完8個位的數(shù)據(jù)之后,SCL是低電平
然后把CSL拉高,這就是一個上升沿,就是第9個時鐘周期,如果再把時鐘拉低,那就是時鐘周期已經(jīng)完成,從機就不再響應(yīng)了

至于釋放數(shù)據(jù)線主要權(quán)什么,SDA=1;之類的,這僅僅只是8051端口的操作而已
有的別的單片機不是這樣操作,不存在把數(shù)據(jù)線拉高的說話
先學(xué)會看時序圖,配合時序看別人的代碼,這就行了,IIC很簡單
回復(fù)

使用道具 舉報

8#
ID:123289 發(fā)表于 2021-10-28 15:00 | 只看該作者
【七、中斷應(yīng)答】這一點能考慮到的人不多。
在I2C通訊過程序中,無論是哪一方,發(fā)生了中斷,中斷服務(wù)返回后(可能執(zhí)行了一段時間),如何確保雙方的通訊接續(xù)上去而不受影響。是需要事先做預(yù)案的。
回復(fù)

使用道具 舉報

9#
ID:266429 發(fā)表于 2021-10-29 11:49 | 只看該作者
Y_G_G 發(fā)表于 2021-10-28 11:26
二、向從器件寫入時的應(yīng)答機制
這個就是在第9個時鐘周期的時候,輸出應(yīng)答位的,說破天了也是第9個
24Cxx是 ...

第9個周期是發(fā)送器件的回應(yīng)周期,目的是通知接收器件釋放對數(shù)據(jù)線的控制權(quán);第8個周期才是接收器件的回應(yīng)周期,告訴對方我收到一個字節(jié)了。
我都是站在這個總線協(xié)議設(shè)計者的角度來思考驗證的。很疑惑教材的說法,反正我在讀應(yīng)答編程時,如果與寫應(yīng)答的程序相同的話,在AT24C上是沒法連續(xù)讀數(shù)據(jù)的。
回復(fù)

使用道具 舉報

10#
ID:401564 發(fā)表于 2021-10-29 14:01 | 只看該作者
慢慢思考 發(fā)表于 2021-10-29 11:49
第9個周期是發(fā)送器件的回應(yīng)周期,目的是通知接收器件釋放對數(shù)據(jù)線的控制權(quán);第8個周期才是接收器件的回 ...

你數(shù)一下是不是第9個

寫入的時候一樣的是第九個時鐘教材是有人審核的,不可能幾乎所有的教材都是錯的
隨便找個時序圖來看,它也是第9個
是最后一個字節(jié)發(fā)送完之后,時鐘是低電平,然后,時鐘線拉高,之后是等待SDA低電平
24Cxx是上升沿寫入,所以,這已經(jīng)是第9個時鐘了,你隨便找一個IIC的寫函數(shù)看一下是不是這樣的
  • for(i = 0;i < 8;i++)
  • //        {
  • //                if(dat & 0x80)        IIC_SDA = 1;        //判斷發(fā)送位,先發(fā)送高位
  • //                else        IIC_SDA = 0;
  • //                IIC_Delay();
  • //                IIC_SCL = 1;        //為SCL下降做準(zhǔn)備
  • //                IIC_Delay();
  • //                IIC_SCL = 0;        //時鐘是低電平
  • //                dat<<=1;
  • //        }
  •         IIC_SDA = 1;        //釋放數(shù)據(jù)線
  •         IIC_Delay();
  •         IIC_SCL = 1;        //這是不是一個時鐘的上升沿?,這就是第8個時鐘完成之后的第9個時鐘!!!
  •         IIC_Delay();
  •         iic_ack |= IIC_SDA;        //讀入應(yīng)答位
  •         IIC_SCL = 0;
  •         return iic_ack;        //返回應(yīng)答信號


回復(fù)

使用道具 舉報

11#
ID:624769 發(fā)表于 2021-10-29 17:17 | 只看該作者
Y_G_G 發(fā)表于 2021-10-29 14:01
你數(shù)一下是不是第9個

寫入的時候一樣的是第九個時鐘教材是有人審核的,不可能幾乎所有的教材都是錯的

16 和17 應(yīng)該交換一下吧?

雖然有個 Delay 在前面, 即便SCL高電平也已經(jīng)能讀到ACK了,但是從規(guī)范上來講,應(yīng)該先拉低時鐘,然后再讀ACK才可以吧?
回復(fù)

使用道具 舉報

12#
ID:401564 發(fā)表于 2021-10-29 20:41 | 只看該作者
188610329 發(fā)表于 2021-10-29 17:17
16 和17 應(yīng)該交換一下吧?

雖然有個 Delay 在前面, 即便SCL高電平也已經(jīng)能讀到ACK了,但是從規(guī)范上來 ...

低電平等于時鐘完成了,讀取不到電平狀態(tài),協(xié)議上也是高電平的時候讀取的


回復(fù)

使用道具 舉報

13#
ID:266429 發(fā)表于 2021-10-31 22:30 | 只看該作者
Y_G_G 發(fā)表于 2021-10-29 14:01
你數(shù)一下是不是第9個

寫入的時候一樣的是第九個時鐘教材是有人審核的,不可能幾乎所有的教材都是錯的

我先問一句:按教材的做法,能連續(xù)讀取數(shù)據(jù)么?這個實驗本來極其簡單,分分鐘的事。
回復(fù)

使用道具 舉報

14#
ID:266429 發(fā)表于 2021-11-1 10:17 | 只看該作者
Y_G_G 發(fā)表于 2021-10-29 14:01
你數(shù)一下是不是第9個

寫入的時候一樣的是第九個時鐘教材是有人審核的,不可能幾乎所有的教材都是錯的

假設(shè)教材上寫的方案行得通,如果讓你來設(shè)計這個總線協(xié)議,你覺得哪種方案更合理?
總線協(xié)議,說起來總歸是純?nèi)藶樵O(shè)計的東西,對于人為設(shè)計的東西,我們應(yīng)該都可以質(zhì)疑并找出更合理的方案,然后你自己就可以申請專利了,當(dāng)然,I2C總線這么簡單的東西,就不要想了,當(dāng)初弄出這東西的人,都是一群高智商的人。
I2C總線的這個問題,本來只是個非常簡單的問題,而且是個非常有意義的問題,沒想到參與討論的人這么少,只能嘆口氣了。
回復(fù)

使用道具 舉報

15#
ID:401564 發(fā)表于 2021-11-1 10:49 | 只看該作者
慢慢思考 發(fā)表于 2021-11-1 10:17
假設(shè)教材上寫的方案行得通,如果讓你來設(shè)計這個總線協(xié)議,你覺得哪種方案更合理?
總線協(xié)議,說起來總歸 ...

你看了我的代碼圖片沒有,你怎么數(shù),它都是第9個時鐘
就算是你自己寫的,只要是能連續(xù)讀取的,它也是第9個時鐘,你把你的代碼文件上傳,C也行,匯編也行
我?guī)湍愀淖⑨?我讓你找出第9個出來
協(xié)議這種東西,你怎么設(shè)計才是合理的?
你搞低作為應(yīng)答,就有人就會問"你為什么不把高電平作為應(yīng)答呢?"
那我高電平作為應(yīng)答,那還是有人會問"你為什么不把低電平作為應(yīng)答呢?
回復(fù)

使用道具 舉報

16#
ID:266429 發(fā)表于 2021-11-1 16:36 | 只看該作者
Y_G_G 發(fā)表于 2021-11-1 10:49
你看了我的代碼圖片沒有,你怎么數(shù),它都是第9個時鐘
就算是你自己寫的,只要是能連續(xù)讀取的,它也是第9個時 ...

當(dāng)然看過了,類似的代碼另外也看了不少。我手上提到I2C的紙質(zhì)書就有四本,其中兩本的有關(guān)應(yīng)答的時序圖中,在第8個時鐘周期時鐘線的低電位時,已有明確的應(yīng)答低電位信號;一本則是第8周期時鐘線下降沿末端,數(shù)據(jù)線電位開始下降,在第9周期前達(dá)到低電位;最后一本則是含混不清,似乎是在第9周期時鐘線上升沿中達(dá)到低電位,真夠亂套的。
至于應(yīng)答是用高電平還是低電平,這個I2C總線規(guī)格設(shè)計是這樣考慮的:器件在其端口輸出高電平,就意味著其交出對線路的控制權(quán),所以,用低電平作應(yīng)答信號。
至于我編的程序,二樓有讀出操作的應(yīng)答程序。
下面是程序的主要部分,請指教:
void i2cstart()//開始程序,其實應(yīng)分為開機初始化部分與總線開始部分這兩個子函數(shù)
{
   i2cscl=1;delayus(4);
   i2csda=1;delayus(4);
   i2csda=0;delayus(4);
   i2cscl=0;delayus(4);
}
//////
void i2cend()//結(jié)束
{
    i2csda=0;delayus(4);
        i2cscl=1;delayus(4);
        i2csda=1;delayus(4);
}
//////
void i2cwack()//寫入應(yīng)答
{
           i2csda=1; delayus(4);//執(zhí)行后數(shù)據(jù)線狀態(tài)為低,說明從器件的應(yīng)答信號已發(fā)出
        i2cscl=1;delayus(4);//數(shù)據(jù)線狀態(tài)為低
           i2cscl=0;delayus(4);//數(shù)據(jù)線狀態(tài)為高
}
//////
void i2crack()//讀出應(yīng)答
{
   i2csda=0;delayus(4);
   i2cscl=1;delayus(4);
   i2cscl=0;delayus(4);
   i2csda=1;delayus(4);//主器件釋放對數(shù)據(jù)線的控制權(quán)
}
///////
void i2cwritebyte(unsigned char wdat)//寫入一字節(jié),加入應(yīng)答
{          
    unsigned char i;
        P2=wdat;
        for(i=0;i<8;i++)
        {
           i2csda=0x01&wdat>>7;
           wdat=wdat<<1;
          
           i2cscl=1;delayus(4);
           i2cscl=0;delayus(4);
        }//完成后數(shù)據(jù)線狀態(tài)為低,與被輸入該字節(jié)數(shù)據(jù)0位的值無關(guān)
         i2cwack();
}
///////
unsigned char i2creadbyte()//讀出一字節(jié),加入應(yīng)答
{
      
          unsigned char rdat=0,i;
          for(i=0;i<8;i++)
          {
          i2cscl=1;delayus(4);
          rdat=rdat<<1|i2csda;
          i2cscl=0;delayus(4);
          }                   //讀出來的這一字節(jié)數(shù)據(jù)最后一位無論是0還是1,此時數(shù)據(jù)線狀態(tài)均為1
           i2crack(); //應(yīng)答完成后數(shù)據(jù)線狀態(tài)與下一待讀字節(jié)的最高位一致
           return(rdat);
}

//////
void main()//連續(xù)讀兩個字節(jié)并送至P2口
{       
         i2cstart();
         i2cwritebyte(0xa0);
         i2cwritebyte(0x01);
         i2cend();

    i2cstart();
        i2cwritebyte(0xa1);
        P2=i2creadbyte();
        delayms(2000);
        P2=i2creadbyte();
        i2cend();

        while(1);
}
注:讀出來的數(shù)據(jù)直接送到P2口,其上接有8只燈;數(shù)據(jù)線與時鐘線上各接有一只燈用以觀察實驗過程中端口電位。
寫入應(yīng)答有三個動作,其三個動作分別執(zhí)行后各自對應(yīng)的數(shù)據(jù)線的狀態(tài)實測值已在程序中標(biāo)注,由此可知寫入時從器件應(yīng)答信號具體發(fā)出的時序時間。
讀數(shù)據(jù)時,最后一字節(jié)數(shù)據(jù)沒有用非應(yīng)答,用的依然是應(yīng)答,然后結(jié)束。
回復(fù)

使用道具 舉報

17#
ID:975504 發(fā)表于 2021-11-1 16:49 | 只看該作者
51黑有你更精彩,感謝!
回復(fù)

使用道具 舉報

18#
ID:401564 發(fā)表于 2021-11-1 18:23 | 只看該作者
慢慢思考 發(fā)表于 2021-11-1 16:36
當(dāng)然看過了,類似的代碼另外也看了不少。我手上提到I2C的紙質(zhì)書就有四本,其中兩本的有關(guān)應(yīng)答的時序圖 ...

以你的代碼為例
void i2cwritebyte(unsigned char wdat)//寫入一字節(jié),加入應(yīng)答
{         
    unsigned char i;
        P2=wdat;
        for(i=0;i<8;i++)
        {
           i2csda=0x01&wdat>>7;
           wdat=wdat<<1;
         
           i2cscl=1;delayus(4);
           i2cscl=0;delayus(4);//最后時鐘線是低電平,第8個時鐘已經(jīng)結(jié)束
        }
         i2cwack();//應(yīng)答中時鐘線是高電平,這就是第9 個時鐘
}
但是,你的應(yīng)答并不對
應(yīng)答是要等待SDA出現(xiàn)低電平,而不是簡單延時一下
這個SDA的低電平是24C02給出的
理論上應(yīng)該是:
        SCL=1;//時鐘高電平,保持從機在第9個時鐘                          
        Delay();//延時
        SDA=1;//釋放SDA
        while(SDA) ;等待從機出現(xiàn)應(yīng)答,重點在這里,延時是不行的,必需得是等待,這是協(xié)議規(guī)定的


但是,在實際情況中,考慮從機有故障或者什么的,可能不會應(yīng)答,while(SDA) ;會卡死
所以,可以使用:
while((SDA==1)&(k<1000))         //超時就不再等待應(yīng)答
                {
                        k++;
                        Delay();
                }




而你的程序,本身就是錯誤的:
void i2cwack()//寫入應(yīng)答
{
         i2csda=1; delayus(4);//執(zhí)行后數(shù)據(jù)線狀態(tài)為低,說明從器件的應(yīng)答信號已發(fā)出
        i2cscl=1;delayus(4);//數(shù)據(jù)線狀態(tài)為低
        i2cscl=0;delayus(4);//數(shù)據(jù)線狀態(tài)為高
}
應(yīng)該是:
void i2cwack()//寫入應(yīng)答
{
        i2csda=1; delayus(4);
        i2cscl=1;delayus(4);        while(i2csda);         //這里要等待,不是延時,重點!重點!重點!可以加入超時檢測退出,防止卡死
        i2cscl=0;delayus(4);
}
而且,IIC停止讀取之前要加一定不應(yīng)答信號,這個信號要由單片機給出,告訴從機,不要再發(fā)送數(shù)據(jù)了
這個信號不是絕對需要,有的器件你直接停止就可以了,但有的不行,你要給出不應(yīng)答才能正確讀取下一次的數(shù)據(jù)
像你的代碼,能正常就是運氣好,因為有的IIC器件硬件電氣性能很好,它的反應(yīng)比單片機還快,它可能壓根就不需要應(yīng)答
回復(fù)

使用道具 舉報

19#
ID:266429 發(fā)表于 2021-11-1 19:41 | 只看該作者
Y_G_G 發(fā)表于 2021-11-1 18:23
以你的代碼為例
void i2cwritebyte(unsigned char wdat)//寫入一字節(jié),加入應(yīng)答
{         

void i2cwritebyte(unsigned char wdat)//寫入一字節(jié),加入應(yīng)答
{         
    unsigned char i;
        P2=wdat;
        for(i=0;i<8;i++)
        {
           i2csda=0x01&wdat>>7;
           wdat=wdat<<1;
         
           i2cscl=1;delayus(4);
           i2cscl=0;delayus(4);//最后時鐘線是低電平,第8個時鐘已經(jīng)結(jié)束,但結(jié)束時數(shù)據(jù)線已經(jīng)是低電平
        }
         i2cwack();//應(yīng)答中時鐘線是高電平,這就是第9 個時鐘。是一高一低,低時數(shù)據(jù)線恢復(fù)高電平
}


SCL=1;//時鐘高電平,保持從機在第9個時鐘                          
        Delay();//延時
        SDA=1;//釋放SDA
這里的延時,并不是用來等待從器件給出應(yīng)答信號,而是為了讓時鐘線的高電位穩(wěn)定一下。至于從器件的拉低數(shù)據(jù)線的應(yīng)答信號,我在前面的實驗已經(jīng)明確指出,它在這個SCL=1執(zhí)行之前,就已經(jīng)發(fā)出了。原則上,在時鐘線處于高電位時,是不允許改變數(shù)據(jù)線狀態(tài)的,所以,在SCL=1執(zhí)行之后,無論是從器件還是主器件,都不能對數(shù)據(jù)端口進(jìn)行操作。
對應(yīng)的,在讀取數(shù)據(jù)的程序編寫中,主器件的應(yīng)答信號也就是拉低數(shù)據(jù)線的操作,也是在應(yīng)答期SCL=1的操作之前進(jìn)行的,也就是一個字節(jié)數(shù)據(jù)讀完、SCL=0之后就立即執(zhí)行SDA=0這個操作,只能這樣安排順序。

至于我的程序中的“錯誤”,是因為僅是一個試驗應(yīng)答規(guī)格的程序,所以嘛,沒有設(shè)計專門的程序來檢測,而是用人眼觀察數(shù)據(jù)線上燈的亮滅。
回復(fù)

使用道具 舉報

20#
ID:401564 發(fā)表于 2021-11-1 23:32 | 只看該作者
慢慢思考 發(fā)表于 2021-11-1 19:41
void i2cwritebyte(unsigned char wdat)//寫入一字節(jié),加入應(yīng)答
{         
    unsigned char i;

太神奇了
錯誤就是錯誤,
1,到底是不是我說的第9個時鐘?還是像你說的第8個?

2,我沒有看到你代碼中有等待應(yīng)答的指令,一個沒有等待應(yīng)答的IIC,它能叫IIC嗎?錯誤還加引號,敢情你還覺得這沒有等待應(yīng)答的IIC代碼是對的?
你要說其它事,可能在每個人心里都有不一樣的看法,我覺得是對的,你也可以覺得是錯誤的,我有我的標(biāo)準(zhǔn),你有你的標(biāo)準(zhǔn)

但這不一樣,這是單純的技術(shù)問題,它是有對錯的,有標(biāo)準(zhǔn)的
我可以肯定的告訴你:你這個IIC代碼是錯誤的,放哪都是錯誤的,別加引號你告訴我一下,你等待從機應(yīng)答的代碼在哪里??????等待!等待!等待!
回復(fù)

使用道具 舉報

21#
ID:266429 發(fā)表于 2021-11-2 08:41 | 只看該作者
Y_G_G 發(fā)表于 2021-11-1 23:32
太神奇了
錯誤就是錯誤,
1,到底是不是我說的第9個時鐘?還是像你說的第8個?

其實第一個問題,是第8個還是第9個,這個就是個怎么計數(shù)的問題,各人看法不一樣,無所謂,可以確定的是,在寫入操作中,最后一位數(shù)放在數(shù)據(jù)線上,時鐘線然后拉高讀取數(shù)據(jù),然后再拉低后,從器件就將數(shù)據(jù)線拉成低電位了。
第二個問題嘛,正常編程當(dāng)然不能這樣,我這本是根據(jù)我這個實驗的具體情況偷了個懶省了這一步,加個引號并不是認(rèn)為這不是錯誤。實際上這種做法也是可以通過的,它在功能單一且對運行速度無太多要求的場合中,你的每一步之間的延時足夠長比如10ms,基本上出錯的可能性也不大,但這樣絕對不規(guī)范。
回復(fù)

使用道具 舉報

22#
無效樓層,該帖已經(jīng)被刪除
23#
ID:976973 發(fā)表于 2021-11-2 11:57 | 只看該作者
好資料,51黑有你更精彩!!!
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

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

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

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