14_单片机_I2C_24C02
1. I2C:Inter-Integrated Circuit,是由Philips公司(现被NXP收购)开发,是一种同步、半双工的通信总线。
I2C的通信速率:100Kbit/s(标准模式);400Kbit/s(快速模式);3.4Mbit/s(高速模式)
标准的 I2C 需要两根信号线:
a. SCL:Serial Clock,时钟线,时钟都是由主设备(Master)提供;
b. SDA:Serial Data,双向数据线,发送数据或接收数据(收发不能同时进行)
2. I2C属于总线式架构,可以挂载多个参与通信的设备,即多机模式,且任何一个器件都可以作为主设备(Master),在多数情况下都是由微控制器作为主设备(Master)
I2C:“主从式”方式,主设备(Master)发起通信及总线仲裁,从设备(Slave)被动响应。

3. I2C状态(1:表示高电平;0:表示低电平)
a. 总线START(Start Data Transfer ):SCL=1;SDA发生跳变(由1变为0),开始传送数据

b. 总线STOP(Stop Data Transfer):SCL=1;SDA发生跳变(由0变为1),停止数据传送

c. 数据阶段:I2C数据在SDA上逐位地串行传输,从高位(MSB)开始
进行数据传送时,在SCL=1时,SDA上的电平必须保持稳定,如下图所示。
只有SCL为低电平期间,才允许SDA上的电平改变状态。

d. 总线空闲(IDLE):SDA和SCL 同时处于 “高电平” 时,规定为总线的空闲状态,即释放总线,两条信号线被上拉电阻把电平拉高。
e. ACK 与 NACK:I2C总线上的所有数据都是以8位字节传送的,Mater每发送一个字节,在第9个时钟脉冲期间释放数据线,由Slave反馈一个应答信号。
应答信号为低电平,规定为有效应答位(ACK),表示Slave已经成功接收了该字节;
应答信号为高电平,规定为非应答位(NACK),一般表示Slave接收该字节没有成功。
4. I2C的写操作

a. Master 发起 START;
b. Master 发送 设备地址和写操作,等待ACK;
c. Slave 发送 ACK;
d. Master 发送 寄存器地址,等待ACK;
e. Slave 发送 ACK;
f. Master 发送 data(8bit),即要写入寄存器中的数据,等待ACK;
g. Slave 发送 ACK;
步骤f 和 步骤g 可以重复多次,即顺序写多个寄存器
h. Master 发起 STOP,结束传输

5. I2C的读操作

a. Master 发起 START;
b. Master 发送 设备地址 和 写操作,等待ACK;
c. Slave 发送ACK;
d. Master 发送 寄存器地址,等待ACK;
e. Slave 发送 ACK;
f. Master 发起 START;
g. Master 发送 设备地址 和 读操作,等待ACK;
h. Slave 发送 ACK;
i. Slave 发送 data(8bit),即寄存器的值;等待ACK;
j. Master 发送ACK
k. 上述两步可以重复多次,即顺序读多个寄存器
l. 当Master接收完数据后,由Mater发送NACK,告知Slave停止发送数据;
m. Master 发起STOP 结束传输

6. I2C 读写操作 对应的 零件数据表(24C02 EEPROM)


7. EEPROM,24C02
参考零件数据表:https://www.mouser.cn/ProductDetail/Microchip-Technology/24C02CT-ST?qs=WWgnj3qycflYpFNSapIRqA%3D%3D
零件封装&Pin

8. 设备寻址:针对24C02,前4位固定为“1010”,后三位用来作为地址,也注定在同一根总线上,允许使用8个24C02设备
当前单片机开发板上的E0、E1、E2都接地(即A0、A1、A2接地),设备地址:0xA0(写)、0xA1(读)

9. 实现向EEPROM写入一部分数据,断电再上电,读取EEPROM,通过串口打印
UART 头文件
1 #ifndef __UART_H__ 2 #define __UART_H__ 3 4 #include <REG51.H> 5 6 /***************函数声明**********************/ 7 void uart_init(void); 8 void SendOneByte(unsigned char c); 9 10 #endif
UART 源文件
1 #include "uart.h" 2 3 4 /***************************************************************** 5 * Function : uart_init 6 * Description : 串口初始化 7 * Parameters : None 8 * Return Value: None 9 *****************************************************************/ 10 void uart_init(void) 11 { 12 TMOD = 0x20; 13 SCON = 0x50; 14 TH1 = 0xF3; 15 TL1 = TH1; 16 PCON = 0x80; // 加倍波特率4800 17 EA = 1; 18 ES = 1; 19 TR1 = 1; 20 } 21 22 /***************************************************************** 23 * Function : SendOneByte 24 * Description : 通过串口发送1个字节 25 * Parameters : None 26 * Return Value: None 27 *****************************************************************/ 28 void SendOneByte(unsigned char c) 29 { 30 SBUF = c; 31 while(!TI); 32 TI = 0; 33 } 34 35 void UARTInterrupt(void) interrupt 4 36 { 37 }
I2C 头文件
1 #ifndef __I2C__H_ 2 #define __I2C__H_ 3 4 #include <reg51.h> 5 6 /**************关键字重定义**************/ 7 #ifndef uchar 8 #define uchar unsigned char 9 #endif 10 11 #ifndef uint 12 #define uint unsigned char 13 #endif 14 15 /**************I/O定义**************/ 16 sbit I2C_SCL = P0^0; 17 sbit I2C_SDA = P0^1; 18 19 /**************函数声明**************/ 20 void I2C_Delay10us(void); 21 void I2C_Start(void); 22 void I2C_Stop(void); 23 uchar I2C_SendByte(uchar dat); 24 uchar I2C_ReadByte(void); 25 26 #endif
I2C 源文件
1 #include "I2C.h" 2 3 4 /***************************************************************** 5 * Function : I2C_Delay10us 6 * Description : 延时10us,SDA需要保持4.7us以上 7 * Parameters : None 8 * Return Value : None 9 *****************************************************************/ 10 void I2C_Delay10us(void) 11 { 12 uchar a, b; 13 for(b=1; b>0; b--) 14 for(a=2; a>0; a--); 15 } 16 17 /***************************************************************** 18 * Function : I2C_Start 19 * Description : I2C 发送 START 20 * Parameters : None 21 * Return Value : None 22 *****************************************************************/ 23 void I2C_Start(void) 24 { 25 I2C_SDA = 1; 26 I2C_Delay10us(); 27 I2C_SCL = 1; 28 I2C_Delay10us(); 29 30 // 起始信号:SDA跳变 1->0 31 I2C_SDA = 0; 32 I2C_Delay10us(); 33 34 // SCL 复位 35 I2C_SCL = 0; 36 I2C_Delay10us(); 37 } 38 39 /***************************************************************** 40 * Function : I2C_Stop 41 * Description : I2C 发送 STOP 42 * Parameters : None 43 * Return Value : None 44 *****************************************************************/ 45 void I2C_Stop(void) 46 { 47 I2C_SDA = 0; 48 I2C_Delay10us(); 49 I2C_SCL = 1; 50 I2C_Delay10us(); 51 52 // 结束信号,SDA跳变 0->1 53 I2C_SDA = 1; 54 I2C_Delay10us(); 55 } 56 57 /***************************************************************** 58 * Function : I2C_SendByte 59 * Description : 通过I2C发送1个字节 60 * Parameters : dat(字节数据) 61 * Return Value : 0-Fail;1-Pass 62 *****************************************************************/ 63 uchar I2C_SendByte(uchar dat) 64 { 65 uchar i = 0,b = 0; //最大255,一个机器周期为1us,最大延时255us 66 67 // SCL=1期间,SDA上的电平需要保持稳定,I2C从MSB开始传输 68 // START 中 SCL已复位0 69 for(i=0; i<8; i++) 70 { 71 I2C_SDA = dat>>7; // 右移7位,取最高位 72 dat = dat<<1; // 将最高位遗弃,次高位变为最高位 73 I2C_Delay10us(); 74 75 I2C_SCL = 1; 76 I2C_Delay10us(); 77 I2C_SCL = 0; 78 I2C_Delay10us(); 79 } 80 81 // 释放总线 82 I2C_SDA = 1; 83 I2C_Delay10us(); 84 I2C_SCL = 1; 85 I2C_Delay10us(); 86 87 while(I2C_SDA) 88 { 89 b++; 90 if(b > 200) // 判断 ACK(传输失败) 还是 NACK(结束传输) 91 { 92 I2C_SCL = 0; 93 I2C_Delay10us(); 94 return 0; 95 } 96 } 97 98 I2C_SCL = 0; 99 I2C_Delay10us(); 100 return 1; 101 } 102 103 /***************************************************************** 104 * Function : I2C_ReadByte 105 * Description : 通过I2C读取一个字节 106 * Parameters : None 107 * Return Value : dat(字节数据) 108 *****************************************************************/ 109 uchar I2C_ReadByte(void) 110 { 111 uchar i = 0,dat = 0; 112 113 I2C_SDA = 1; // START 和 SEND 之后 SCL已复位,释放SDA 114 I2C_Delay10us(); 115 116 for(i=0; i<8; i++) 117 { 118 I2C_SCL = 1; 119 I2C_Delay10us(); 120 121 dat = dat<<1; 122 dat = dat | I2C_SDA; 123 I2C_Delay10us(); 124 125 I2C_SCL = 0; // 为下一个脉冲周期准备 126 I2C_Delay10us(); 127 } 128 return dat; 129 }
EEPROM 24C02 头文件
1 #ifndef __E24C02__H_ 2 #define __E24C02__H_ 3 4 #include "I2C.h" 5 6 #ifndef uchar 7 #define uchar unsigned char 8 #endif 9 10 #ifndef uint 11 #define uint unsigned int 12 #endif 13 14 void E24C02_write(uchar addr, uchar dat); 15 uchar E24C02_read(uchar addr); 16 17 18 #endif
EEPROM 24C02 源文件
1 #include "E24C02.h" 2 3 /***************************************************************** 4 * Function : E24C02_write 5 * Description : 向EEPROM 24C02写入数据 6 * Parameters : addr(寄存器地址);dat(数据) 7 * Return Value : None 8 *****************************************************************/ 9 void E24C02_write(uchar addr, uchar dat) 10 { 11 I2C_Start(); // START 12 I2C_SendByte(0xA0); // 设备地址,写操作 13 I2C_SendByte(addr); // 要写入的寄存器地址 14 I2C_SendByte(dat); // 写入的数据 15 I2C_Stop(); // STOP 16 } 17 18 /***************************************************************** 19 * Function : 20 * Description : 21 * Parameters : 22 * Return Value : 23 *****************************************************************/ 24 uchar E24C02_read(uchar addr) 25 { 26 uchar tmp; 27 28 I2C_Start(); // START 29 I2C_SendByte(0xA0); // 设备地址,写操作 30 I2C_SendByte(addr); // 要写入的寄存器地址 31 32 I2C_Start(); // START 33 I2C_SendByte(0xA1); // 设备地址,读操作 34 tmp = I2C_ReadByte(); // 读取数据,赋值tmp 35 I2C_Stop(); // STOP 36 37 return tmp; 38 }
Main
1 #include "I2C.h" 2 #include "uart.h" 3 #include "E24C02.h" 4 5 /***************************************************************** 6 * Function : delay15ms 7 * Description : 延时15ms 8 * Parameters : None 9 * Return Value : None 10 *****************************************************************/ 11 void delay15ms(void) 12 { 13 unsigned char a,b,c; 14 for(c=1;c>0;c--) 15 for(b=238;b>0;b--) 16 for(a=30;a>0;a--); 17 } 18 19 20 void main(void) 21 { 22 unsigned char i = 0, addr = 0; 23 unsigned char src_data[] = "P####OIUYTREWQ@#$"; 24 unsigned char buf[8] = "11111111"; 25 26 uart_init(); 27 28 // 写入数据到EEPROM 24C02 29 for(i=0; i<8; i++) 30 { 31 E24C02_write(addr, src_data[i]); 32 delay15ms(); 33 addr++; 34 } 35 36 // 打印buf的内容 37 for(i=0; i<8; i++) 38 { 39 SendOneByte(buf[i]); 40 } 41 42 // 打印分割线 43 for(i=0; i<30; i++) 44 { 45 SendOneByte('+'); 46 } 47 48 // 读取EEPROM的数据 49 addr = 0; 50 for(i=0; i<8; i++) 51 { 52 buf[i] = E24C02_read(addr); 53 delay15ms(); 54 addr++; 55 } 56 57 // 打印buf的内容 58 for(i=0; i<8; i++) 59 { 60 SendOneByte(buf[i]); 61 } 62 63 while(1); 64 }
记录下~
浙公网安备 33010602011771号