第十章 I2C接口實驗 注:在AT91SAM7Sxx系列中,I2C稱作TWI。 一.實驗?zāi)康?br /> 能夠正確讀寫I2C接口芯片存儲器(24C02),即寫入24C02的數(shù)據(jù)與讀出來的數(shù)據(jù)相同。 二.實驗程序和參數(shù)設(shè)置 1> 連接器選項設(shè)置和啟動代碼與上一個實驗相同 2> I2C驅(qū)動程序 ATMEL官方網(wǎng)站上有這方便的參考程序。主要由I2C接口的初始化、I2C的讀和寫三部分組成。 #i nclude "board.h" #i nclude "twi.h" void InitTwi(void) { AT91F_TWI_CfgPIO(); //配置TWI的TWD和TWCK管腳 AT91F_PIO_CfgOpendrain(AT91C_BASE_PIOA,(unsigned int)AT91C_PA3_TWD); AT91F_TWI_CfgPMC (); //使能TWI外圍時鐘 AT91F_TWI_Configure (AT91C_BASE_TWI); //將TWI設(shè)置成主模式 AT91F_SetTwiClock(AT91C_BASE_TWI); //計算、設(shè)置時鐘發(fā)生寄存器 } //*---------------------------------------------------------------------------- //* \fn AT91F_SetTwiClock //*計算、設(shè)置TWI時鐘發(fā)生寄存器 //*---------------------------------------------------------------------------- void AT91F_SetTwiClock(const AT91PS_TWI pTwi) { int sclock; sclock = (10*MCK /AT91C_TWI_CLOCK); sclock = (MCK /AT91C_TWI_CLOCK); if (sclock % 10 >= 5) sclock = (sclock /10) - 5; else sclock = (sclock /10)- 6; sclock = (sclock + (4 - sclock %4)) >> 2; // div 4 pTwi->TWI_CWGR = 0x00010000 | sclock | (sclock } //*---------------------------------------------------------------------------- //* \fn AT91F_TWI_Write //* \brief Send n bytes to a slave device //*---------------------------------------------------------------------------- int AT91F_TWI_Write(const AT91PS_TWI pTwi ,int address, char *data2send, int size) { unsigned int status; pTwi->TWI_MMR=(AT91C_EEPROM_I2C_ADDRESS| AT91C_TWI_IADRSZ_1_BYTE ) & ~AT91C_TWI_MREAD; pTwi->TWI_IADR = address; // Set TWI Internal Address Register status = pTwi->TWI_SR; pTwi->TWI_THR = *(data2send++); pTwi->TWI_CR = AT91C_TWI_START; while (size-- >1){ // Wait THR Holding register to be empty while (!(pTwi->TWI_SR & AT91C_TWI_TXRDY)); pTwi->TWI_THR = *(data2send++);// Send first byte } pTwi->TWI_CR = AT91C_TWI_STOP; status = pTwi->TWI_SR; while (!(pTwi->TWI_SR & AT91C_TWI_TXCOMP)); // Wait transfer is finished return AT91C_EEPROM_WRITE_OK; } //*---------------------------------------------------------------------------- //* \fn AT91F_TWI_Read //* \brief Read n bytes from a slave device //*---------------------------------------------------------------------------- int AT91F_TWI_Read(const AT91PS_TWI pTwi , int address, char *data2rec, int size) { unsigned int status; pTwi->TWI_MMR=(AT91C_EEPROM_I2C_ADDRESS|AT91C_TWI_IADRSZ_1_BYTE) | AT91C_TWI_MREAD; // Set the TWI Master Mode Register pTwi->TWI_IADR = address; // Set TWI Internal Address Register pTwi->TWI_CR = AT91C_TWI_START; // Start transfer status = pTwi->TWI_SR; while (size-- >1){ // Wait RHR Holding register is full while (!(pTwi->TWI_SR & AT91C_TWI_RXRDY)); *(data2rec++) = pTwi->TWI_RHR; // Read byte } pTwi->TWI_CR = AT91C_TWI_STOP; status = pTwi->TWI_SR; while (!(pTwi->TWI_SR & AT91C_TWI_TXCOMP)); // Wait transfer is finished *data2rec = pTwi->TWI_RHR; // Read last byte return AT91C_EEPROM_READ_OK; } 3> 主函數(shù) 在主函數(shù)中,首先調(diào)用了TWI的初始化函數(shù),然后進入了超級大循環(huán)。在每次寫和讀時,都對它們的數(shù)據(jù)緩沖區(qū)進行初始化,以查看讀、寫的正確性。 #i nclude "board.h" #i nclude "twi.h" int main ( void ) { int loop,index=0; char Wri_data[16], Red_data[16]; //定義寫和讀緩沖區(qū) InitTwi(); //TWI初始化 while (1) { for (loop = 0; loop 初始化寫和讀緩沖區(qū)的內(nèi)容 data1[loop] = loop + index; data2[loop] = 0; } index += 1; AT91F_TWI_Write(AT91C_BASE_TWI, 0x0, Wri_data, EEP_RW_CHK_CNT);//寫 AT91F_TWI_Read(AT91C_BASE_TWI, 0x0, Red_data, EEP_RW_CHK_CNT);//讀 }//用單步調(diào)試,可比較Wri_data[16]和 Red_data[16]的內(nèi)容來判斷讀寫是否正確。 } 三.出現(xiàn)的問題與解決方法 1> 無論寫入任何數(shù)據(jù),讀出來都是同樣的數(shù),表明數(shù)據(jù)沒有寫入(在調(diào)試時對其寫操作,器件沒有產(chǎn)生應(yīng)答)。 原因是24C02的寫保護管腳沒有接地,內(nèi)部的數(shù)據(jù)被寫保護了。注意:有些廠家的EEROM的該管腳處于懸空時為不保護狀態(tài),而有些廠家的EEROM會處于保護狀態(tài),因此在用之前一定要仔細閱讀廠家的數(shù)據(jù)手冊,或不要將該腳懸空。 2> 對24WC02寫的數(shù)據(jù)和讀的數(shù)據(jù)不一樣。 原因是I2C的時鐘太快。在本實驗程序中,可以減少twi.h中的AT91C_TWI_CLOCK常量的數(shù)值。或者直接在程序中修改TWI時鐘波形發(fā)生寄存器TWI_CWGR。 3> 當寫入16字節(jié)數(shù)據(jù),再讀出16字節(jié)數(shù)據(jù)時,最后一個字節(jié)總為0。 原因是TWI Master Mode Register的IADRSZ(器件內(nèi)部地址長度)設(shè)成了兩個字節(jié)(Two-byte),要將改成一個字節(jié)(One-byte)。 |