1 硬體特性 1.1 概述 I2C匯流排是由Philips公司開發的兩線式串列匯流排,這兩根線為時鐘線(SCL)和雙向數據線(SDA)。由於I2C匯流排僅需要兩根線,因此在電路板上占用的空間更少,帶來的問題是帶寬較窄。I2C在標準模式下傳輸速率最高100Kb/s,在快速模式下最高可達400kb/s。屬於半
1 硬體特性
1.1 概述
I2C匯流排是由Philips公司開發的兩線式串列匯流排,這兩根線為時鐘線(SCL)和雙向數據線(SDA)。由於I2C匯流排僅需要兩根線,因此在電路板上占用的空間更少,帶來的問題是帶寬較窄。I2C在標準模式下傳輸速率最高100Kb/s,在快速模式下最高可達400kb/s。屬於半雙工。
在嵌入式系統中,I2C應用非常廣泛,大多數微控制器中集成了I2C匯流排,一般用於和RTC,EEPROM,智能電池電路,感測器,LCD以及其他類似設備之間的通信。
1.2 I2C匯流排傳輸時序
1.3 I2C匯流排的信號狀態
1、 空閑狀態:SDA和SCL都是高電平;
2、 開始條件(S):SCL為高電平時,SDA由高電平向低電平跳變,開始傳輸數據;
3、 結束條件(P):SCL為高電平時,SDA由低電平向高電平跳變,結束傳輸數據;
4、 數據有效:在SCL的高電平期間,SDA保持穩定,數據有效。SDA的改變只能發生在SCL的低電平期間;
5、 ACK信號:數據傳輸的過程中,接收器件每接收一個位元組數據要產生一個ACK信號,向發送器件發出特定的低電平脈衝,表示已經收到數據。
1.4 從設備地址
I2C匯流排從設備使用7位地址,最後一個為讀寫控制位。下圖是eeprom的原理圖,我們可以計算出它的地址為0x50。
1.5 I2C讀寫方式
多位元組寫的時序
多位元組讀的時序
具體可參考datasheet
附:ok6410裸機I2C代碼。
1 #define INTPND (*(volatile unsigned long*)0x4a000010) 2 #define SRCPND (*(volatile unsigned long*)0x4a000000) 3 #define INTMSK (*(volatile unsigned long*)0x4a000008) 4 #define GPECON (*(volatile unsigned long*)0x56000040) 5 #define GPEUP (*(volatile unsigned long*)0x56000048) 6 7 #define IICCON (*(volatile unsigned char*)0x54000000) 8 #define IICSTAT (*(volatile unsigned char*)0x54000004) 9 #define IICDS (*(volatile unsigned char*)0x5400000C) 10 11 #define SLAVE_WRITE_ADD 0xa0 /* 寫入數據時;方向位(第0位)為0 */ 12 #define SLAVE_READ_ADD 0xa1 /* 讀取數據時;方向位(第0位)為1 */ 13 14 15 void delay(int i) 16 { 17 int j = 0; 18 while (i--) 19 { 20 for (j=0;j<100;j++) 21 { 22 ; 23 } 24 } 25 } 26 27 28 void i2c_init() 29 { 30 //1.a 初始化中斷 31 INTPND |= (1<<27); 32 SRCPND |= (1<<27); 33 INTMSK &= ~(1<<27); 34 35 IICCON |= (1<<5); 36 37 //1.b 設置scl時鐘 38 IICCON &= ~(1<<6); 39 IICCON &= ~(0xf<<0); 40 IICCON |= (0x5<<0); 41 42 //2. 設置IICSTAT 43 IICCON |= (1<<4); 44 45 //3.設置引腳功能 46 GPECON |= (0x2<<28)|(0x2<<30); 47 GPEUP |= (0x3<<14); 48 49 //4.允許產生ACK 50 IICCON |= (1<<7); 51 } 52 53 54 void write_byte(unsigned char xchar, unsigned char daddr) 55 { 56 /* 寫入數據時,每發送一個數據收到一個ACK就產生一次中斷 57 * 寫入下次發送的數據之後要清除中斷 */ 58 59 //1. 設置處理器為主設備+發送模式 60 IICSTAT |= (3<<6); 61 62 //2. 將從設備的地址寫入到IICDS寄存器 63 IICDS = SLAVE_WRITE_ADD; 64 65 //清除中斷 66 IICCON &= ~(1<<4); 67 68 //3. 寫入0xF0寫入IICSTAT M/T Start 69 IICSTAT = 0xF0; 70 71 //4. 等待ACK的產生 72 while ((IICCON & (1<<4)) == 0 ) 73 delay(100); 74 75 //5.1寫入位元組的地址到IICDS寄存器 76 IICDS = daddr; 77 78 79 //5.2清除中斷 80 IICCON &= ~(1<<4); 81 82 //5.3等待ACK的產生 83 while ((IICCON & (1<<4)) == 0 ) 84 delay(100); 85 86 //6. 將要傳輸的位元組數據寫入IICDS寄存器 87 IICDS = xchar; 88 89 //7. 清除中斷 90 IICCON &= ~(1<<4); 91 92 //8. 等待ACk的產生 93 while ((IICCON & (1<<4)) == 0 ) 94 delay(100); 95 96 //9. 寫入0xD0到IICSTAT 97 IICSTAT = 0xD0; 98 99 //10. 清除中斷 100 IICCON &= ~(1<<4); 101 102 delay(100); 103 } 104 105 void read_data(unsigned char *buf, unsigned char daddr, int length) /* 結合eeprom手冊 */ 106 { 107 /* 每接收一個數據產生一個中斷 */ 108 109 int j =0; 110 unsigned char unusedata; 111 112 //1. 設置處理器為主設備+發送模式 113 IICSTAT |= (3<<6); 114 115 //2. 將從設備的地址寫入到IICDS寄存器 116 IICDS = SLAVE_WRITE_ADD; 117 118 //清除中斷 119 IICCON &= ~(1<<4); 120 121 //3. 寫入0xF0寫入IICSTAT M/T-Start 122 IICSTAT = 0xF0; 123 124 //4. 等待ACK的產生 125 while ((IICCON & (1<<4)) == 0 ) 126 delay(100); 127 128 //5.1寫入eeprom內部地址 129 IICDS = daddr; 130 131 132 //5.2清除中斷 133 IICCON &= ~(1<<4); 134 135 //5.3等待ACK的產生 136 while ((IICCON & (1<<4)) == 0 ) 137 delay(100); 138 139 /**************eeprom代碼**************/ 140 /**************************************/ 141 /***************i2c代碼****************/ 142 143 //設置為主設備接收模式 144 IICSTAT &= ~(3<<6); 145 IICSTAT |= (2<<6); 146 147 148 //2.寫入從設備地址到IICDS /* 從設備地址成功發送之後產生中斷,故要清除中斷 */ 149 IICDS = SLAVE_READ_ADD; 150 //清除中斷 151 IICCON &= ~(1<<4); 152 153 154 //3.寫入0xB0到IICSTAT開始接收,每接收道一個數據就產生一個中斷 155 IICSTAT = 0xb0; 156 157 //等待中斷 158 while ((IICCON & (1<<4)) == 0 ) 159 delay(100); 160 161 #if 0 162 /***寫入設備內部地址***/ 163 IICDS = daddr; 164 IICCON &= ~(1 << 4); 165 while((IICCON & (1 << 4)) == 0) 166 { 167 delay(100); 168 } 169 #endif 170 171 //***丟掉收到的第1個位元組 第一個數據無效 丟棄! 172 unusedata = IICDS; 173 IICCON &= ~(1<<4); 174 while ((IICCON & (1<<4)) == 0 ) 175 delay(100); 176 177 178 179 for(j=0;j<length;j++) 180 { 181 if(j == (length - 1)) 182 { 183 IICCON &= ~(1<<7); 184 } 185 186 //5.1 從IICDS里取出數據 187 buf[j]=IICDS; 188 189 //5.2 清除中斷 190 IICCON &= ~(1<<4); 191 192 //4.等待中斷 193 while ((IICCON & (1<<4)) == 0 ) 194 delay(100); 195 } 196 197 198 //寫入0x90到IICSTAT 199 IICSTAT = 0x90; 200 201 202 // 清除中斷 203 IICCON &= ~(1<<4); 204 } 205 206 void i2c_test() 207 { 208 int i=0; 209 unsigned char sbuf[256]={0}; 210 unsigned char dbuf[256]={0}; 211 212 i2c_init(); 213 214 for(i=0;i<256;i++) 215 { 216 sbuf[i] = i+1; 217 dbuf[i] = 0; 218 } 219 220 printf("dbuf befor I2C read:\r\n"); 221 for(i =0; i<256;i++) 222 { 223 if(i%8==0) 224 printf("\r\n"); /* */ 225 226 printf("%d\t",dbuf[i]); /*t-空格 */ 227 } 228 229 for(i=0;i<256;i++) 230 write_byte(sbuf[i],i); 231 232 printf("i2c reading, plese wait!\n\r"); 233 234 read_data(dbuf,0,256); 235 236 printf("dbuf after I2C read:\r\n"); 237 238 for(i =0; i<256;i++) 239 { 240 if(i%8==0) 241 printf("\r\n"); 242 243 printf("%d\t",dbuf[i]); 244 } 245 }