51单片机的I2C通信EEPROM

常用的串行总线协议

I2C总线、SPI总线、SCI总线
I2C总线:同步串行2线方式进行通信(一条时钟线,一条数据线)
SPI总线:同步串行3线方式进行通信(一条时钟线,一条数据输入线,一条数据输出线)
SCI总线:异步方式进行通信(一条数据输入线,一条数据输出线)

UART总线异步串口在单片机串口通信时使用
1-wire(单线总线)单总线,如使用温度传感器时需要这种通信协议

I2C串行总线

它有两根双向信号线(一根数据线SDA,另一根时钟线SCL)
I2C总线上可以挂多个器件,每个器件都有唯一的地址(标识通信目标)
数据的通信方式采用主从方式(主机负责联系从机,从机被动回应 数据)51单片机的I2C通信EEPROM_第1张图片
I2C总线通过上拉电阻(一般为10k)接正电源。当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都将使总线的信号变低(各器件的SDA和SCL都是与的关系)
51单片机的I2C通信EEPROM_第2张图片
SCL为高电平期间,数据线上的数据必须保持稳定,只有SCL信号为低电平期间,SDA状态才允许变化
51单片机的I2C通信EEPROM_第3张图片

I2C的起始和终止信号

SCL线为高电平期间,SDA线由高电平向低电平的变化表示起始信号
SCL线为高电平期间,SDA线由低电平向高电平的变化表示终止信号
51单片机的I2C通信EEPROM_第4张图片

I2C字节的传送和应答

每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面必须跟随以为应答位(一帧共有9位)
51单片机的I2C通信EEPROM_第5张图片

I2C写数据流程

在起始信号后必须传送一个从机的地址(7位)AT24C02地址为0xa0
第8位是数据的传送方向位(R/T)
“0”表示主机发送数据(T),“1”表示主机接收数据(R)

I2C读数据流程

先发送器件地址,读方向为写,(我们下一帧需要发送从AT24C02内那个单元开始读),需在发一次器件地址(这时读写方向就为读了),我们就可以从总线上读取数据。
51单片机的I2C通信EEPROM_第6张图片

#include
#include

#define uchar unsigned char
#define uint unsigned int
#define AT24C02_ADDR 0xa0  //AT24C02地址

/*I2C   IO口定义*/
sbit SDA = P2^0;
sbit SCL = P2^1;

void delay_5us()//5微秒延时
{
	_nop_();
	
}

void I2C_init()  //I2C初始化
{
	SDA = 1;
	_nop_();
	SCL = 1;
	_nop_();
}

void I2C_Start()//I2C起始信号
{
	SCL = 1;
	_nop_();
	SDA = 1;
	dalay_5us();
	SDA = 0;
	dalay_5us();
}
/*I2C终止信号*/
void I2C_Stop()
{
	SDA = 0;
	_nop_();
	SCL = 1;
	delay_5us();
	SDA = 1;
	delay_5us()
}
/*主机发送应答*/
void Master_ACK(bit i)
{
	SCL = 0;//拉低时钟总线允许SDA数据总线上的数据变化
	_nop_();//让总线稳定
	if(i)//如果i = 1那么拉低数据总线  表示主机应答
	{
		SDA = 0;
	}
	else
	{
		SDA = 1;  //发送非应答
	}
	_nop_();
	SCL = 1;//拉高时钟总线  让从机从SDA线上读走 主机的应答信号
	_nop_();
	SCL = 0;//拉低时钟总线,占用总线继续通信
	_nop_();
	SDA = 1;//释放SDA数据总线,交由从机控制
	_nop_();
}
/*发送一个字节*/
void I2C_send_byte(uchar byte)
{
	uchar i;
	for(i = 0;i < 8; i ++)
	{
		SCL = 0;
		_nop_();
		if(byte & 0x80)
		{
			SDA = 1;
			_nop_();
		}
		else
		{
			SDA = 0;
			_nop_();
		}
		SCL = 1;
		_nop_();
		byte <<= 1;
	}
	SCL = 0;
	_nop_();
	SDA = 1;
	_nop_();
}
/*I2C读一个字节*/
uchar I2C_read_byte()
{
	uchar dat,i;
	SCL = 0;
	_nop_();
	SDA = 1;
	_nop_();
	for(i = 0; i  < 8;i ++)
	{
		SCL = 1;
		_nop_();
		if(SDA)
		{
			dat = dat| 0x01;
		}
		else
		{
			dat = dat & 0xfe;
		}
		_nop_();
		SCL = 0;
		_nop_();
		if(i < 7)
		{
			dat = dat << 1;
		}
	}
	return(dat);	
}

/*检测从机应答*/
bit Test_ACK()
{
	SCL = 1;
	delay_5us();
	if(SDA)
	{
		SCL = 0;
		I2C_Stop();
		return(0);
	}
	else
	{
		SCL = 0;
		_nop_();
		return(1);
	}
}
/*发送数据*/
bit I2C_TransmitData(uchar ADDR,DAT)
{
	I2C_Start();
	I2C_send_byte(AT24C02_ADDR + 0);
	if(!Test_ACK())
	{
		return 0;
	}
	I2C_send_byte(ADDR);
	if(!Test_ACK())
	{
		return 0;
	}
	I2C_send_byte(DAT);
	if(!Test_ACK())
	{
		return 0;
	}
	I2C_Stop();
	return 1;
}
/*接收数据*/
uchar I2C_ReceiveData(uchar ADDR)
{
	uchar DAT;
	I2C_Start();
	I2C_send_byte(AT24C02_ADDR + 0);
	if(!Test_ACK())
	{
		return 0;
	}
	I2C_send_byte(ADDR);
	if(!Test_ACK())
	{
		return 0;
	}
	I2C_send_byte(DAT);
	if(!Test_ACK())
	{
		ACK_flag = 1;
	}
	I2C_Stop();
	delay(10);
	I2C_Start();
	I2C_sned_byte(8);
	Master_ACK(0);
	I2C_Start();
	I2C_send_byte(AT24C02_ADDR + 1);
	if(!Test_ACK())
	{
		ACK_flag = 1;
	}
	DAT = I2C_read_byte();
	Master_ACK(0);
	I2C_Stop();
	return 1;
}

void main()
{
	I2C_init();//I2C初始化
	if(!I2C_TransmitData(255,0xf0))//往AT24C02第255个单元中写入数据0xf0
	{
		P1 = 0;
	}
	delay(5);
	P1 = I2C_ReceiveData(255);//从AT24C02第255个单元中读取数据
	while(1);
}

你可能感兴趣的:(通信)