51单片机——I2C总线存储器24C02的应用

目标实现功能

       单片机先向24C02写入256个字节的数据,再从24C02中一次读取2个字节的数据、并在数码管上动态显示,直至读完24C02中256个字节的数据。

1.I2C总线简介

I2C总线有两根双向的信号线,一根是数据线SDA,另一根是时钟线SCL。I2C总线通过上拉电阻接正电源,因此,当总线空闲时为高电平。

2.I2C通信协议

起始信号、停止信号由主机发出。在数据传送时,当时钟线为高电平时,数据线上的电平状态必须保持稳定;当时钟线为低电平时,数据线上的电平状态才允许变化。发送器将8位数据从高位到低位传送完成后,需要接收来自接收器的应答或非应答的信号。

51单片机需要编写模拟I2C总线通信的程序,才能与其他I2C总线器件通信。

<1>起始信号的程序

/*I2C起始信号*/
void i2c_start()//当SCL为高电平,SDA从高电平变为低电平
{
	SDA=1;
	delay6us();//将SDA置为高电平
	SCL=1;
	delay6us();//将SCL置为高电平
	SDA=0;
	delay6us();//SDA从高电平变为低电平
	SCL=0;
  delay6us();//将SCL置为低电平,准备发送数据
}

<2>停止信号的程序

/*I2C停止信号*/
void i2c_stop()//当SCL为高电平,SDA从低电平变为高电平
{
	SDA=0;
	delay6us();//将SDA置为低电平
	SCL=1;
	delay6us();//将SCL置为高电平
	SDA=1;
	delay6us();//SDA从低电平变为高电平
}

<3>发送8位数据的程序

/*I2C发送数据*/
bit i2c_sendbyte(uchar dat)//主机发送数据8位
{
	uchar i;//整型变量i,用于循环
	for(i=0;i<8;i++)//发8次
	{
		SDA=dat>>7;//每次发送高位
	  dat=dat<<1;//次高位补位
		delay6us();//SDA形成电平
		SCL=1;
		delay6us();//SCL为高电平时,SDA值可以被接收器读取
		SCL=0;//将SCL置为低电平
		delay6us();//将SCL置为低电平,准备发送下一位数据
	}
	SDA=1;
	delay6us();//释放SDA,准备接收应答信号
	SCL=1;
	delay6us();//当SCL置为高电平,读取SDA状态
	while(SDA)//非应答时进入while循环
	{
		SCL=0;
	  delay6us();//将SCL置为低电平
		return 0;//接收器非应答返回0
	}
	SCL=0;
	delay6us();//将SCL置为低电平
  return 1;//接收器应答返回1
}

 <4>读取8位数据的程序

/*I2C读取数据*/
uchar i2c_readbyte()//主机读取数据8位
{
	uchar dat=0;
	uchar i;//整型变量i,用于循环
	SDA=1;
	delay6us();//释放SDA,准备读取数据
	for(i=0;i<8;i++)
	{
		SCL=1;
		delay6us();//当SCL为1时,接收器可以读取SDA
		dat=dat<<1;//左移1位
		dat=dat|SDA;//先高后低
		delay6us();//延时	
		SCL=0;
		delay6us();//将SCL置为低电平,准备读取数据
	}
  return dat;//返回读取的数值
}

<5>应答信号的程序

/*I2C应答信号*/
void i2c_ask()//当SCL为高电平时,SDA为低电平
{
	SDA=0;
	delay6us();//将SDA置为低电平
	SCL=1;
	delay6us();//将SCL置为高电平
    SCL=0;
	delay6us();//将SCL置为低电平
}

<6>非应答信号的程序

/*I2C非应答信号*/
void i2c_noask()//当SCL为高电平时,SDA为高电平
{
	SDA=1;
	delay6us();//将SDA置为高电平
	SCL=1;
	delay6us();//将SCL置为高电平
    SCL=0;
	delay6us();//将SCL置为低电平
}

3.单片机与24C02的I2C总线通信的程序 

存储器24C02存储容量256*8bit,24C02的器件地址为7位,高4位固定为1010、低三位由A0、A1、A2引脚的电平值决定。读写信号(1:读;0:写)加7位器件地址构成一个字节的数据,

通过这个字节的数据,选择目标器件并确定读或写 。

24C024可以根据需要一次写入2~16个字节的数据,通过循环可以实现写入256个字节的数据。

单片机向24C02一次写入多个字节的子程序如下:

/*主机向24C02器件发送数据(多字节写操作)
  起始信号-器件地址(7位地址+写信号)
  应答信号-写24C02器件的存储首地址(8位)
  应答信号-写数据(8位)-应答信号
  写数据(8位)-........-应答-停止信号*/
bit c02_mutiwrite(uchar addr,uchar *p,uchar num)//参数addr表示写24C02器件的存储首地址,指针p指向待写数据,num表示数据个数
{
	bit flag=0;//用于判断I2C发送数据是否成功
	uchar i;
	i2c_start();//起始信号
	flag=i2c_sendbyte(0xA0);//24C02器件地址1010000 0(写)
	if(flag==0) return 0;
	flag=i2c_sendbyte(addr);//写24C02器件的存储首地址
	if(flag==0) return 0;
	for(i=0;i

单片机每次从24C02读出2个字节,形成一个16位2进制数。

例如第一个字节数据是0000 0001即 (十进制数1),第二个字节数据的是0000 0010即(十进制数2)

新的16位2进制数0000 0001 0000 0010即(十进制数是258)。

子程序如下:

/*主机从24C02器件读取数据(每次读2个字节操作)
  起始信号-器件地址(7位地址+写信号)//伪写操作
  应答信号-目标读取的存储首地址(8位)
  应答信号-起始信号-器件地址(7位地址+读信号)
  读数据(8位)-应答-读数据(8位)-非应答-停止信号*/
bit c02_mutireadbyte(uchar addr,uint *p)//参数addr表示读24C02器件的存储首地址,指针p指向保存数据的地址
{
	bit flag=0;//用于判断I2C发送数据是否成功
	i2c_start();//起始信号
	flag=i2c_sendbyte(0xA0);//24C02器件地址1010 000 0(写)
	if(flag==0) return 0;
	flag=i2c_sendbyte(addr);//目标读取的存储首地址(8位)
  if(flag==0) return 0;
	i2c_start();//起始信号
	flag=i2c_sendbyte(0xA1);//24C02器件地址1010 000 1(读)
	if(flag==0) return 0;
	*p=i2c_readbyte();//主机读取第一个字节(8位)
	i2c_ask();//主机发送应答
	*p=(*p)<<8;//第一个字节(8位)左移8位作高8位
	*p=(*p)+i2c_readbyte();//主机读取数据8位作低8位
	i2c_noask();//非应答
	i2c_stop();//停止信号
	return 1;//读数据成功	
}

 注:具体工程见链接https://item.taobao.com/item.htm?id=835593680495icon-default.png?t=O83Ahttps://item.taobao.com/item.htm?id=835593680495

4.程序仿真结果

按下写入按键,单片机向24C02写入256个字节的数据,同时指示灯会亮。当写入完成后,指示灯灭。

掉电重启后,按下读取按键,单片机从24C02一次读取两个字节,第一个字节作为高八位,第二个字节作为第八位,形成的新的16位2进制数,以十进制数的形式在数码管上动态显示,直到读完最后的2个字节、并在数码管上显示。

实物亲测有效!!!

视频如下:

51单片机———I2C总线存储器24C02的应用

你可能感兴趣的:(51单片机,嵌入式硬件,单片机)