您好,登錄后才能下訂單哦!
本篇內容主要講解“arm9 IIC接口有什么用”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“arm9 IIC接口有什么用”吧!
在2440的使用中其iic接口一般用來讀取外圍芯片的數據, 這種情況下2440處于主機模式, 本例用中斷的方式來講述 主機發送/主機接收 模式.
主機發送模式使用流程:
IICCON: 是否返回ack, 總線時鐘選擇, 中斷標志
IICCON[7] 在發送模式該位沒有意義, 因為發送模式下主機只接收ACK信號, 并不主動發出ACK.
在接收模式中當從機返回了數據之后, 如果主機需要從機繼續返回數據就必須發送一個ACK, 否則數據發送方不會繼續發送數據.
綜上: 無論是主/從, 只要接收數據的一方想要繼續通信就必須要發送一個ACK信號, 所以ACK信號絕對是由接收數據的一方來發出的.
IICCON[5] 必須為1, 否則IICCON[4]無法使用
IICCON[4] 0: 無中斷發生 1: 有中斷發生, 這時總線傳輸中止. 如果要繼續傳輸則需將該位清0
發生中斷的條件: 1. 總線仲裁失敗 2. 發送/接收完一個字節 3. 當廣播或從地址匹配成功
GPEUP |= 0xc000; // 禁止內部上拉 GPECON |= 0xa0000000; // 選擇引腳功能:GPE15:IICSDA, GPE14:IICSCL INTMSK &= ~(BIT_IIC); //清除IIC中斷屏蔽位 /* bit[7] = 1, 使能ACK * bit[6] = 0, IICCLK = PCLK/16 * bit[5] = 1, 使能中斷 * bit[3:0] = 0xf, Tx clock = IICCLK/16 * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz */ IICCON = (1<<7) | (0<<6) | (1<<5) | (0xf); // 0xaf IICSTAT = 0x10; // IICSTAT[4]:I2C串行輸出使能(Rx/Tx), 這里可以不必配置該寄存器, 因為真正開始發送/接收的時候會重新配置IICSTAT(見下邊的I2C_Write)
IICADD: 當2440作為從機的時候, 本身的iic地址可以由該寄存器來設置.
IICSTAT : 主從模式選擇, S/P信號發送, 標記各種狀態
IICSTAT[7:6] 主從模式選擇
IICSTAT[5] 讀取此位時 0 : 總線空閑, 1 : 總線忙 ; 寫入0: 發出 P 信號, 寫入 1: 發出 S 信號
IICSTAT[4] 開啟收發
IICSTAT[3] 總線仲裁成功標志位
IICSTAT[2] 當2440作為從機時, 接收到的地址和IICADD匹配則該位置一, 在檢測到 S/P 信號時自動清0
IICSTAT[1] 當接收到 0x00 地址時置一, 當檢測到 S/P 信號時自動清0
IICSTAT[0] 0: 接收到ACK; 1: 沒有接收到ACK
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *以下為中斷方式操作I2C接口的主要代碼, 從機芯片為 m41t11* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
在啟動文件中設定好I2C中斷的異常向量, 在ISR中清除異常標志
//head.S中設置異常向量 @ 0x1c: 快中斷模式的向量地址 HandleFIQ: b HandleFIQ //interrupt.c中的ISR, 該ISR總查詢到了IIC中斷, 調取了IIC異常處理函數 void IRQ_Handle(void) { unsigned long oft = INTOFFSET; //清中斷 if (oft == 4) EINTPEND = 1<<7; //EINT4-7合用IRQ4,注意EINTPEND[3:0]保留未用,向這些位寫入1可能導致未知結果 SRCPND = 1<<oft; INTPND = INTPND; /* 調用中斷服務程序 */ isr_handle_array[oft](); }
以下為IIC的主要操作:
#define WRDATA (1) #define RDDATA (2) typedef struct tI2C { unsigned char *pData; /* 數據緩沖區 */ volatile int DataCount; /* 等待傳輸的數據長度 */ volatile int Status; /* 狀態 */ volatile int Mode; /* 模式:讀/寫 */ volatile int Pt; /* pData中待傳輸數據的位置 */ }tS3C24xx_I2C, *ptS3C24xx_I2C; static tS3C24xx_I2C g_tS3C24xx_I2C; // I2C初始化 void i2c_init(void) { GPEUP |= 0xc000; // 禁止內部上拉 GPECON |= 0xa0000000; // 選擇引腳功能:GPE15:IICSDA, GPE14:IICSCL INTMSK &= ~(BIT_IIC); //允許IIC中斷 /* bit[7] = 1, 使能ACK * bit[6] = 0, IICCLK = PCLK/16 * bit[5] = 1, 使能中斷 * bit[3:0] = 0xf, Tx clock = IICCLK/16 * PCLK = 50MHz, IICCLK = 3.125MHz, Tx Clock = 0.195MHz */ IICCON = (1<<7) | (0<<6) | (1<<5) | (0xf); // 0xaf IICADD = 0x10; // S3C24xx slave address = [7:1] 這句可以不需要的, 該寄存器只在2440作為從機才有用 IICSTAT = 0x10; // I2C串行輸出使能(Rx/Tx) 這句也可以不用, 因為真正寫的時候又重新配置了IICSTAT } /* * 主機發送 * slvAddr : 從機地址,buf : 數據存放的緩沖區,len : 數據長度 */ void i2c_write(unsigned int slvAddr, unsigned char *buf, int len) { g_tS3C24xx_I2C.Mode = WRDATA; // 寫操作 g_tS3C24xx_I2C.Pt = 0; // 索引值初始為0 g_tS3C24xx_I2C.pData = buf; // 保存緩沖區地址 g_tS3C24xx_I2C.DataCount = len; // 傳輸長度 IICDS = slvAddr; IICSTAT = 0xf0; // 主機發送,啟動 /* 等待直至數據傳輸完畢 */ while (g_tS3C24xx_I2C.DataCount != -1); } // 主機接收 // slvAddr : 從機地址,buf : 數據存放的緩沖區,len : 數據長度 void i2c_read(unsigned int slvAddr, unsigned char *buf, int len) { g_tS3C24xx_I2C.Mode = RDDATA; // 讀操作 g_tS3C24xx_I2C.Pt = -1; // 索引值初始化為-1,表示第1個中斷時不接收數據(地址中斷) g_tS3C24xx_I2C.pData = buf; // 保存緩沖區地址 g_tS3C24xx_I2C.DataCount = len; // 傳輸長度 IICDS = slvAddr; IICSTAT = 0xb0; // 主機接收,啟動 /* 等待直至數據傳輸完畢 */ while (g_tS3C24xx_I2C.DataCount != -1); } // I2C中斷服務程序 // 根據剩余的數據長度選擇繼續傳輸或者結束 void I2CIntHandle(void) { unsigned int iicSt,i; // 清中斷 SRCPND = BIT_IIC; INTPND = BIT_IIC; iicSt = IICSTAT; //先判斷是不是仲裁失敗引起的中斷 if(iicSt & 0x8){ printf("Bus arbitration failed\n\r"); } switch (g_tS3C24xx_I2C.Mode) { case WRDATA: { //檢測是否數據發送完畢, 若完畢: 發送P信號, 數據長度=-1 if((g_tS3C24xx_I2C.DataCount--) == 0) { // 下面兩行用來恢復I2C操作,發出P信號 IICSTAT = 0xd0; IICCON = 0xaf; Delay(10000); // 等待一段時間以便P信號已經發出 break; //注意這里的break, 發送P信號完畢直接返回. } //若數據未發送完畢直接發送, 緩沖區索引值++ IICDS = g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++]; // 將數據寫入IICDS后,需要一段時間才能出現在SDA線上 for (i = 0; i < 10; i++); IICCON = 0xaf; // 恢復I2C傳輸 break; } case RDDATA: { // 這次中斷是發送I2C設備地址后發生的,沒有數據, 第一次發送完地址之后(發送完一個字節會產生中斷)產生的中斷, 接收數據之后2440是需要發出ACK信號的 if (g_tS3C24xx_I2C.Pt == -1) { // 只接收一個數據時,不要發出ACK信號 g_tS3C24xx_I2C.Pt = 0;//準備從數據緩存區的0開始發送數據 if(g_tS3C24xx_I2C.DataCount == 1) IICCON = 0x2f; // 恢復I2C傳輸,開始接收數據,關閉ACK, 接收到數據時不發出ACK, 最后一個數據要先關閉ack, 因為最后一個數據要發送no ack, 其實就是不發送ack else IICCON = 0xaf; // 恢復I2C傳輸,開始接收數據, 0x2f與0xaf的區別就是前者不開ack break; } if ((g_tS3C24xx_I2C.DataCount--) == 0) { //如果要讀取的剩余數據長度為0, 就發送P信號 g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++] = IICDS; // 下面兩行恢復I2C操作,發出P信號 IICSTAT = 0x90; IICCON = 0xaf; Delay(10000); // 等待一段時間以便P信號已經發出 break; } g_tS3C24xx_I2C.pData[g_tS3C24xx_I2C.Pt++] = IICDS; // 接收最后一個數據時,不要發出ACK信號 if(g_tS3C24xx_I2C.DataCount == 0) IICCON = 0x2f; // 恢復I2C傳輸,接收到下一數據時無ACK else IICCON = 0xaf; // 恢復I2C傳輸,接收到下一數據時發出ACK break; } default: break; } }
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *以上為中斷方式操作I2C總線, 以下使用輪詢方式來操作* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
以下以 LM75(數字溫度傳感器) 來說明 輪詢方式 讀取溫度值的方法.
控制過程: 1. 讀取溫度值之前需要先指定 LM75 的寄存器, LM75 的寄存器 0x0 是溫度寄存器器(READ ONLY). 所以先發送S信號再發送 LM75 的地址, 然后發送 0x0 就可以選中溫度寄存器
2. 選中溫度寄存器之后, LM75 會將 高/低 字節依次發送到I2C總線. 所以, 再次發送 LM75 地址, 讀取 高/低 字節 發送P信號結束傳輸.
int set_pointer_and_read_2byte(int mode) { //主機發送模式, 選中溫度寄存器 I2C0.I2CDS0 = 0x90; // 發送LM75地址 I2C0.I2CCON0 = 0xe0; // 使能, PRESCALER:512 ,RX/TX 中斷使能 I2C0.I2CSTAT0 =0xf0; // 主發送模式, 啟動, 使能 RX/TX while(!(I2C0.I2CCON0&(1<<4))); // 等待直至發送完成 I2C0.I2CDS0 = mode; // READ TEMPERATURE ONLY 讀取溫度寄存器 I2C0.I2CCON0 &= ~(1<<4); // 清除掛起標志 & 恢復總線操作 while(!(I2C0.I2CCON0&(1<<4))); // 等待直至發送完成 //主機接收模式, 開始接收溫度數據 I2C0.I2CDS0 = 0x91; // 重新發送LM75地址 I2C0.I2CSTAT0 =0xb0; // 主機接收模式, 啟動, 使能 RX/TX I2C0.I2CCON0 &= ~(1<<4); // 清除掛起標志 & 恢復總線操作 while(!(I2C0.I2CCON0&(1<<4))); // 等待直至發送完成 I2C0.I2CCON0 &= ~(1<<4); // 清除掛起標志 & 恢復總線操作 while(!(I2C0.I2CCON0&(1<<4))); // 等待直至讀取完成 high = I2C0.I2CDS0; // 讀取低8位數據 I2C0.I2CCON0 &= ~((1<<7)|(1<<4));// 清除掛起標志 & 恢復總線操作 & 禁止發送 ACK while(!(I2C0.I2CCON0&(1<<4))); // 等待直至讀取完成 low = I2C0.I2CDS0; // 讀取更低字節數據(小數部分 ?) I2C0.I2CSTAT0 &= ~(1<<5); // 發送 P信號, 釋放總線 I2C0.I2CCON0 &= ~(1<<4); // 清除中斷標志位 return ((high << 8) | low); }
到此,相信大家對“arm9 IIC接口有什么用”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。