工具
1.Proteus 8 仿真器
2.keil 5 编辑器
原理图
讲解
特点:
- 宽范围的工作电压,1.8V~5.5V;
- 低电压技术,1mA典型工作电流,1μA典型待机电流;
- 存储器组织结构为1024 X 8(8K bits);
- 2线串行接口,完全兼容I2C总线,I2C时钟频率为1MHz(5V),400kHz(1.8V、2.5V、2.7V);
- 施密特触发输入噪声抑制;
- 硬件数据写保护;
- 内部写周期(最大5ms);
- 可按字节写,页写:16字节页;
- 可按字节、随机和序列读;
- 自动递增地址;
- ESD保护大于2.5kV;
- 高可靠性;
- 擦写寿命:100万次;
- 数据保持时间:100年。
引脚:
注意:此图与仿真器中有所差异但原理一致 仿真器中1,2,3,4接地,8接电源,7为写保护(高电平时禁止写入,低电平可以写入)接地,5数据,6时钟。
时序
开始:SDA与SCL高电平--(>4μs)--SDA拉为低电平--(>4μs)--SCL拉为低电平
// 开始 SCL高电平状态下 SDA 由高电平变低电平
void start()
{
SDA=1;
SCL=1;
delay(); //5us
SDA=0;
delay(); //5us
SCL=0;
}
结束:SDA低电平,SCL高电平--(>4μs)--SDA拉为高电平--(>4μs)--SDA,SCL拉为低电平
// 结束 SCL高电平状态下 SDA 由低电平变高电平
void end()
{
SDA=0;
SCL=1;
delay(); //5us
SDA=1;
delay(); //5us
SCL=0;
SDA=0;
}
写入:SDA(电平由单字节的每一位决定)--(>4μs)--SCL拉为高电平--(>4μs)--SCL拉为低电平
// 发送
void send(unsigned char byte)
{
unsigned char i;
for(i=0;i<8;i++) //字节拆分按位传递
{ //SCL为高电平 读取SDA稳定数据 所以SDA变化在前
SDA=byte&(0x80>>i); //从最高位依次传递给SDA
delay(); //5us
SCL=1;
delay(); //5us
SCL=0;
}
}
读取:SDA高电平(开始接收前),SCL高电平--(>4μs)--SDA(电平由单字节的每一位决定)--(>4μs)--SCL拉为低电平
// 接收
unsigned char read()
{
unsigned char i,byte=0x00; //byte需要初始化0x00
SDA=1;
for(i=0;i<8;i++) //字节拆分按位接收
{
SCL=1;
delay(); //5us
if(SDA){byte|=(0x80>>i);}
delay(); //5us
SCL=0;
}
return byte;
}
接收应答:SDA高电平--(>4μs)--SCL拉为高电平--(>4μs)--SCL拉为低电平
//接收应答
bit read_sck()
{
bit ACK;
SDA=1;
delay(); //5us
SCL=1;
delay(); //5us
ACK=SDA;
SCL=0;
return ACK;
}
发送应答:SDA( 0 应答,1 非应答 )--(>4μs)--SCL拉为高电平--(>4μs)--SCL拉为低电平
//发送应答
void send_sck(bit ACK )
{
SDA=ACK;
delay(); //5us
SCL=1;
delay(); //5us
SCL=0;
}
代码
main.c
#include <reg52.h>
#include <I2C.h>
unsigned char arr[]={0xa0,0xff,0xaa,0x90};
main(void)
{
unsigned char i;
for(i=0;i<4;i++)
{
I2C_send(i,arr[i]);
}
//随机读 指定地址读取数据
P1= I2C_read(2);
}
I2C.c
#include <REGX51.H>
#include <intrins.H>
#define delay();{_nop_();_nop_();_nop_();_nop_();_nop_();} //五个机器周期 5微妙 一周期多长时间与晶振有关
sbit SDA = P3^7; //数据
sbit SCL = P3^6; //时钟
void delay_ms(unsigned int ms) {
unsigned int i, j;
for (i = 0; i < ms; i++) {
for (j = 0; j < 1275; j++) { // 这里使用了大约1275个空循环,可以根据你的晶振频率进行调整
// 这里什么也不做,只是为了消耗一些时间
}
}
}
// 开始 SCL高电平状态下 SDA 由高电平变低电平
void start()
{
SDA=1;
SCL=1;
delay();
SDA=0;
delay();
SCL=0;
}
// 结束 SCL高电平状态下 SDA 由低电平变高电平
void end()
{
SDA=0;
SCL=1;
delay();
SDA=1;
delay_ms(10);
}
// 发送
void send(unsigned char byte)
{
unsigned char i;
for(i=0;i<8;i++) //字节拆分按位传递
{ //SCL为高电平 读取SDA稳定数据 所以SDA变化在前
SDA=byte&(0x80>>i); //从最高位依次传递给SDA
delay();
SCL=1;
delay();
SCL=0;
}
}
// 接收
unsigned char read()
{
unsigned char i,byte=0x00;
SDA=1;
for(i=0;i<8;i++) //字节拆分按位接收
{
SCL=1;
delay();
if(SDA){byte|=(0x80>>i);}
delay();
SCL=0;
}
return byte;
}
void send_sck(bit ACK) {
// 根据ACK的值设置数据线SDA
SDA = ACK; // 注意:通常ACK是低电平,NACK是高电平
delay(); // 保持SDA状态,等待从机读取
SCL = 1; // 将时钟线SCL拉高
delay(); // 等待时钟线稳定
SCL = 0; // 将时钟线SCL拉低,结束应答
delay(); // 等待时钟线稳定
SDA = 1; //释放数据线 线权交给从机
}
//接收应答
bit read_sck()
{
bit ACK;
SDA=1;
delay(); //5us
SCL=1;
delay(); //5us
ACK=SDA;
delay(); //5us
SCL=0;
return ACK;
}
void I2C_send(unsigned char address,unsigned char byte)
{
start();
send(0xa0);
read_sck();
send(address);
read_sck();
send(byte);
read_sck();
end();
delay_ms(5);
}
unsigned char I2C_read(unsigned char address)
{
unsigned char read_data;
start();
send(0xa0);
read_sck();
send(address);
read_sck();
start();
send(0xa1);
read_sck();
read_data=read();
send_sck(1);
end();
return read_data;
}