单片机 【I2C 通信】
================================I2C 通信================================
1-WIRE -------------------- DS18B20
I2C ------------------------(本课)
SDA ----------(serial data I/O)
SCL -----------(serial clock)
==================================I2C传输协议
=======================================I2C传输起始和终止信号
=====================================I2C字节的传送与应答
======================应答位的作用
================================I2C写数据流程
========================I2C读数据流程
========================软件模拟I2C通信时序
1 /*I2C初始化*/ 2 void I2C_init() 3 { 4 SDA = 1; 5 _nop_(); 6 SCL = 1; 7 _nop_(); 8 }
1 /*I2C起始信号*/ 2 void I2C_Start() 3 { 4 SCL = 1; 5 _nop_(); 6 SDA = 1; 7 delay_5us(); 8 SDA = 0; 9 delay_5us(); 10 }
1 /*I2C终止信号*/ 2 void I2C_Stop() 3 { 4 SDA = 0; 5 _nop_(); 6 SCL = 1; 7 delay_5us(); 8 SDA = 1; 9 delay_5us(); 10 }
1 /*主机发送应答*/ 2 void Master_ACK(bit i) 3 { 4 SCL = 0; // 拉低时钟总线允许SDA数据总线上的数据变化 5 _nop_(); // 让总线稳定 6 if (i) //如果i = 1 那么拉低数据总线 表示主机应答 7 { 8 SDA = 0; 9 } 10 else 11 { 12 SDA = 1; //发送非应答 13 } 14 _nop_();//让总线稳定 15 SCL = 1;//拉高时钟总线 让从机从SDA线上读走 主机的应答信号 16 delay_5us(); 17 SCL = 0;//拉低时钟总线, 占用总线继续通信 18 _nop_(); 19 SDA = 1;//释放SDA数据总线。 20 _nop_(); 21 }
1 /*检测从机应答*/ 2 bit Test_ACK() 3 { 4 SCL = 1; 5 delay_5us(); 6 if (SDA) 7 { 8 SCL = 0; 9 _nop_(); 10 I2C_Stop(); 11 return(0); 12 } 13 else 14 { 15 SCL = 0; 16 _nop_(); 17 return(1); 18 } 19 }
1 /*发送一个字节*/ 2 void I2C_send_byte(uchar byte) 3 { 4 uchar i; 5 for(i = 0 ; i < 8 ; i++) 6 { 7 SCL = 0; 8 _nop_(); 9 if (byte & 0x80) 10 { 11 SDA = 1; 12 _nop_(); 13 } 14 else 15 { 16 SDA = 0; 17 _nop_(); 18 } 19 SCL = 1; 20 _nop_(); 21 byte <<= 1; // 0101 0100B 22 } 23 SCL = 0; 24 _nop_(); 25 SDA = 1; 26 _nop_(); 27 }
1 /*I2C 读一字节*/ 2 uchar I2C_read_byte() 3 { 4 uchar dat,i; 5 SCL = 0; 6 _nop_(); 7 SDA = 1; 8 _nop_(); 9 for(i = 0 ; i < 8 ; i++) 10 { 11 SCL = 1; 12 _nop_(); 13 if (SDA) 14 { 15 dat |= 0x01; // 16 } 17 else 18 { 19 dat &= 0xfe; //1111 1110 20 } 21 _nop_(); 22 SCL = 0 ; 23 _nop_(); 24 if(i < 7) 25 { 26 dat = dat << 1; 27 } 28 } 29 return(dat); 30 }
1 /*I2C发送数据*/ 2 bit I2C_TransmitData(uchar ADDR, DAT) 3 { 4 I2C_Start(); 5 I2C_send_byte(AT24C02_ADDR+0); 6 if (!Test_ACK()) 7 { 8 return(0); 9 } 10 I2C_send_byte(ADDR); 11 if (!Test_ACK()) 12 { 13 return(0); 14 } 15 I2C_send_byte(DAT); 16 if (!Test_ACK()) 17 { 18 return(0); 19 } 20 I2C_Stop(); 21 return(1); 22 }
1 /*I2C接收数据*/ 2 uchar I2C_ReceiveData(uchar ADDR) 3 { 4 uchar DAT; 5 I2C_Start(); 6 I2C_send_byte(AT24C02_ADDR+0); 7 if (!Test_ACK()) 8 { 9 return(0); 10 } 11 I2C_send_byte(ADDR); 12 Master_ACK(0); 13 I2C_Start(); 14 I2C_send_byte(AT24C02_ADDR+1); 15 if (!Test_ACK()) 16 { 17 return(0); 18 } 19 DAT = I2C_read_byte(); 20 Master_ACK(0); 21 I2C_Stop(); 22 return(DAT); 23 }
1 void main() 2 { 3 I2C_init();//I2C初始化 4 if(!I2C_TransmitData(255,0xf0)); //往AT24C02第255个单元中写入数据0XF0 5 { 6 P1 = 0; 7 } 8 delay(5); 9 /**/ 10 P1 = I2C_ReceiveData(255);//从AT24C02第255个单元中读取数据 11 while(1); 12 }
1 # include <reg52.h> 2 # include <intrins.h> 3 4 #define uchar unsigned char 5 #define uint unsigned int 6 #define AT24C02_ADDR 0xa0 //AT24C02地址 7 8 /*I2C IO口定义*/ 9 sbit SDA = P2^0; 10 sbit SCL = P2^1; 11 12 /*5us延时*/ 13 void delay_5us() 14 { 15 _nop_(); 16 } 17 18 /*1Ms延时*/ 19 void delay(uint z) 20 { 21 uint x,y; 22 for(x = z; x > 0; x--) 23 for(y = 114; y > 0 ; y--); 24 } 25 26 /*I2C初始化*/ 27 void I2C_init() 28 { 29 SDA = 1; 30 _nop_(); 31 SCL = 1; 32 _nop_(); 33 } 34 35 /*I2C起始信号*/ 36 void I2C_Start() 37 { 38 SCL = 1; 39 _nop_(); 40 SDA = 1; 41 delay_5us(); 42 SDA = 0; 43 delay_5us(); 44 } 45 46 /*I2C终止信号*/ 47 void I2C_Stop() 48 { 49 SDA = 0; 50 _nop_(); 51 SCL = 1; 52 delay_5us(); 53 SDA = 1; 54 delay_5us(); 55 } 56 57 /*主机发送应答*/ 58 void Master_ACK(bit i) 59 { 60 SCL = 0; // 拉低时钟总线允许SDA数据总线上的数据变化 61 _nop_(); // 让总线稳定 62 if (i) //如果i = 1 那么拉低数据总线 表示主机应答 63 { 64 SDA = 0; 65 } 66 else 67 { 68 SDA = 1; //发送非应答 69 } 70 _nop_();//让总线稳定 71 SCL = 1;//拉高时钟总线 让从机从SDA线上读走 主机的应答信号 72 delay_5us(); 73 SCL = 0;//拉低时钟总线, 占用总线继续通信 74 _nop_(); 75 SDA = 1;//释放SDA数据总线。 76 _nop_(); 77 } 78 79 /*检测从机应答*/ 80 bit Test_ACK() 81 { 82 SCL = 1; 83 delay_5us(); 84 if (SDA) 85 { 86 SCL = 0; 87 _nop_(); 88 I2C_Stop(); 89 return(0); 90 } 91 else 92 { 93 SCL = 0; 94 _nop_(); 95 return(1); 96 } 97 } 98 99 /*发送一个字节*/ 100 void I2C_send_byte(uchar byte) 101 { 102 uchar i; 103 for(i = 0 ; i < 8 ; i++) 104 { 105 SCL = 0; 106 _nop_(); 107 if (byte & 0x80) 108 { 109 SDA = 1; 110 _nop_(); 111 } 112 else 113 { 114 SDA = 0; 115 _nop_(); 116 } 117 SCL = 1; 118 _nop_(); 119 byte <<= 1; // 0101 0100B 120 } 121 SCL = 0; 122 _nop_(); 123 SDA = 1; 124 _nop_(); 125 } 126 127 128 /*I2C 读一字节*/ 129 uchar I2C_read_byte() 130 { 131 uchar dat,i; 132 SCL = 0; 133 _nop_(); 134 SDA = 1; 135 _nop_(); 136 for(i = 0 ; i < 8 ; i++) 137 { 138 SCL = 1; 139 _nop_(); 140 if (SDA) 141 { 142 dat |= 0x01; // 143 } 144 else 145 { 146 dat &= 0xfe; //1111 1110 147 } 148 _nop_(); 149 SCL = 0 ; 150 _nop_(); 151 if(i < 7) 152 { 153 dat = dat << 1; 154 } 155 } 156 return(dat); 157 } 158 159 /*I2C发送数据*/ 160 bit I2C_TransmitData(uchar ADDR, DAT) 161 { 162 I2C_Start(); 163 I2C_send_byte(AT24C02_ADDR+0); 164 if (!Test_ACK()) 165 { 166 return(0); 167 } 168 I2C_send_byte(ADDR); 169 if (!Test_ACK()) 170 { 171 return(0); 172 } 173 I2C_send_byte(DAT); 174 if (!Test_ACK()) 175 { 176 return(0); 177 } 178 I2C_Stop(); 179 return(1); 180 } 181 182 /*I2C接收数据*/ 183 uchar I2C_ReceiveData(uchar ADDR) 184 { 185 uchar DAT; 186 I2C_Start(); 187 I2C_send_byte(AT24C02_ADDR+0); 188 if (!Test_ACK()) 189 { 190 return(0); 191 } 192 I2C_send_byte(ADDR); 193 Master_ACK(0); 194 I2C_Start(); 195 I2C_send_byte(AT24C02_ADDR+1); 196 if (!Test_ACK()) 197 { 198 return(0); 199 } 200 DAT = I2C_read_byte(); 201 Master_ACK(0); 202 I2C_Stop(); 203 return(DAT); 204 } 205 206 void main() 207 { 208 I2C_init();//I2C初始化 209 if(!I2C_TransmitData(255,0xf0)) //往AT24C02第255个单元中写入数据0XF0 210 { 211 P1 = 0; 212 } 213 delay(5); 214 /**/ 215 P1 = I2C_ReceiveData(255);//从AT24C02第255个单元中读取数据 216 while(1); 217 }
为什么在传输过程中,SCL=0,SDA=1; 在这里解释一下:
打个比方:SDA相当于琴弦,在最初的初始化时SDA=1;(相当于琴弦放松的时候)
SCL只有在SDA传输过程中SCL=1(等于1时相当于开关开启,传送数据),只有SCL=0时数据才可以改变(相当于数据加载开关关闭);
一个二次元的生物