關(guān)鍵字: i2c ,IIC,bus, ACK,NACK,NAK,SDA,SCL,timing,master,slaver,時序,響應(yīng),總線 關(guān)于i2c的響應(yīng)問題:對于每一個接收設(shè)備(從設(shè)備,slaver),當它被尋址后,都要求在接收到每一個字節(jié)后產(chǎn)生一個響應(yīng)。因此,the master device 必須產(chǎn)生一個額外的時鐘脈沖(第九個脈沖)用以和這個響應(yīng)位相關(guān)聯(lián)。 在這個脈沖期間,發(fā)出響應(yīng)的從設(shè)備必須將SDA拉低并在時鐘脈沖的高電平期間保持住。這表示該設(shè)備給出了一個ACK。如果它不拉低SDA線,就表示不響應(yīng)(NACK)。 另外,在從機(發(fā)送方)發(fā)送完最后一個字節(jié)后主設(shè)備(接收方)必須產(chǎn)生一個不響應(yīng)位,用以通知從機(發(fā)送方)不要再發(fā)送信息了,這樣從機就知道該將SDA釋放了,而后,主機發(fā)出一個停止位給slaver。
總結(jié)下,i2c通訊中,SDA 和 SCL 都是有主機控制的,從設(shè)備只是能夠?qū)DA線拉低而已。對于SCL線,從機是沒有任何能力去控制的。從機只能被動跟隨SCL 再說的清楚些: 主機發(fā)送數(shù)據(jù)到從機的狀態(tài)下:主機控制SCL信號線和SDA信號線,從機只是在SCL線為高的時候去被動讀取SDA線。 主機讀取從機的數(shù)據(jù):主機來發(fā)出時鐘信號,從機只是保證在時鐘信號為高電平的時候的SDA的狀態(tài)而已。 //---------------------------------------- 補充@201108311142 SDA和SCL已經(jīng)通過上拉電阻被上拉,master可以控制(拉低或者釋放)這兩條線,而slaver只能控制SDA線。當master發(fā)送數(shù)據(jù)時,master會適時地將SDA和SCL拉低或釋放(拉高)。確切的時序應(yīng)該是這樣的: 當mater要發(fā)送一個start時,mater會將SDA拉低,這就可以了,因為此時的SCL一定是High。好了,一個start就這樣發(fā)出去了。而slaver也會發(fā)現(xiàn)這個start信號的發(fā)生,slaver便會準備好接收接下來的數(shù)據(jù)了。緊接著,master要發(fā)送一個Byte的數(shù)據(jù)了,一位一位的發(fā)出這8個bits。這時master會先將SCL拉低,然后在SCL為低的狀態(tài)下將一個bit準備好放到SDA上(比如要發(fā)送一個 0,master就會通過拉低SDA來放好這個0),然后master會把SCL拉高(釋放),此時slaver會立刻檢測到SCL的變化,由此聰明的slaver便知道m(xù)aster已經(jīng)將要發(fā)送的那個bit準備好了,slaver便會在這個SCL的高電平期間盡快(maser不會等你很久的哦)去讀取一下SDA,嗯讀到了一個0,slaver就把這個0放到自己的移位寄存器中待后續(xù)處理。master會在一個設(shè)定好的時間后把SCL再次拉低,然后在SCL為低電平期間把下一個bit放到SDA上,然后再把SCL拉高,然后slaver在SCL的高電平期間再去讀SDA。。。。。如此反復8次,一個Byte的傳輸便告結(jié)束。當這8個bit發(fā)完后,SCL是處于低電平的(被master拉低的),SDA是出于高電平的(master已經(jīng)釋放了SDA)。 當一個字節(jié)發(fā)送完畢后,master會釋放SDA(拉高)并拉低SCL,此時slaver如果打算發(fā)出一個ACK的話,它必須在這個SCL被master拉低的短暫時間內(nèi)去主動將SDA拉低并保持住 (此前我們說過,SDA此時已經(jīng)被master釋放,所以slaver才有機會去拉低這個SDA)。master會在一個確定的時間后再次將SCL拉高,并在拉高的期間去讀取SDA線的狀態(tài),如果讀到低電平,則認為收到了來自slaver的響應(yīng)(ACK),否則認為slaver沒有響應(yīng)(NACK)剛才發(fā)送的那一個Byte。這個過程就是我們說的i2c通訊中的第9個時鐘周期。當master讀完這個ACK / NACK 后,會再次將SCL拉低,用以通知slaver:第9個時鐘周期已經(jīng)結(jié)束,你現(xiàn)在可以釋放SDA了。而此時master也可以向SDA上準備下一個Byte的第一個bit。繼而重復上述過程。。。。?;蛘?,master也許想在接下來發(fā)送一個stop過去,那么master會在這個SCL為低的時間內(nèi)將SDA拉低,而后再將SCL拉高,在SCL為高的期間再將SDA釋放 (拉高) 。這樣,一個STOP位就產(chǎn)生了。你會發(fā)現(xiàn)此后的SDA和SCL都是高,這就是是所謂的總線空閑了! 一句話:SCL是單向的,由master控制。而SDA是雙向的,master可以控制,slaver也可以控制。 Yasin Lee@201109091400 昨天在調(diào)試mma8452q的過程中發(fā)現(xiàn)一個新的問題: 我一直以為用i2c讀取slaver的某個寄存器的過程是:1.向slaver寫一個寄存器地址過去。2.讀取slaver。就是這樣兩步,可是這樣的想法在讀取mma8452q時卻出現(xiàn)了問題,總是無法讀到正確的數(shù)據(jù)。上述兩步我是通過這樣的方法實現(xiàn)的:1.調(diào)用i2c_master_send發(fā)送一個字節(jié)的數(shù)據(jù)(寄存器地址)過去。2.調(diào)用i2c_master_recv讀取一個字節(jié)。完畢。之所以這么做是基于這樣的想法:當向slaver寫入(發(fā)送)一個寄存器地址過去后,slaver就會把當前的讀寫指針(假想的)指向這個寄存器,此后,讀取的時候自然是讀到這個寄存器的值了。 可是這樣的想法不行,考慮到,這個假設(shè)可能不對,我便直接使用i2c_transfer來進行操作,因為這個函數(shù)可以實現(xiàn)在由寫入狀態(tài)切換到讀取狀體的過程中不發(fā)送stop,也就是直接再次發(fā)送一個start,即Restart。 問題解決,看來對mma8452q的讀取操作必須經(jīng)由restart來做中間的切換。而不能在切換過程中發(fā)送stop命令。而先前采用的分部操作在每一步完成后都有一個i2c stop命令發(fā)生,所以出了問題。 |
|