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: "); 221 for(i =0; i<256;i++) 222 { 223 if(i%8==0) 224 printf(" "); /* */ 225 226 printf("%d ",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! "); 233 234 read_data(dbuf,0,256); 235 236 printf("dbuf after I2C read: "); 237 238 for(i =0; i<256;i++) 239 { 240 if(i%8==0) 241 printf(" "); 242 243 printf("%d ",dbuf[i]); 244 } 245 }