IIC通信之EEPROM


一,I2C串行总线概述


  • I2C总线是PHLIPS公司推出的一种串行总线,是具备多主机系统所需的包括总线裁决和高低速器件同步功能的高性能串行总线。 I2C总线只有两根双向信号线。一根是数据线SDA,另一根是时钟线SCL
  • I2C总线通过上拉电阻接正电源。当总线空闲时,两根线均为高电平。连到总线上的任一器件输出的低电平,都将使总线的信号变低,即各器件的SDA及SCL都是线“与”关系。
  • 每个接到I2C总线上的器件都有唯一的地址。主机与其它器件间的数据传送可以是由主机发送数据到其它器件,这时主机即为发送器。由总线上接收数据的器件则为接收器。在多主机系统中,可能同时有几个主机企图启动总线传送数据。为了避免混乱,
    I2C总线要通过总线仲裁,以决定由哪一台主机控制总线

在这里插入图片描述
I2C总结
(1)主CPU和其附属芯片之间最常用的接口,尤其是各种传感器,因此在物联网时代非常重要。
(2)两根线:SCL、SDA,串行、电平式
(3)总线式结构,可以一对多,总线上可以挂上百个器件,用从地址来区分
(4)主从式,由主设备来发起通信及总线仲裁,从设备被动响应。
(5)通信速率一般(kbps级别),不适合语音、视频等信息类型。


二,I2C总线的数据传送


1、数据位的有效性规定

I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。

在这里插入图片描述

2、起始和终止信号

(1)起始信号:SCL保持高时,SDA有一个从高到低(下降沿)
(2)结束信号:SCL保持高时,SDA有一个从低到高(上升沿)
在这里插入图片描述
时序代码

1)起始信号
void I2C_Start()
{
	I2C_SDA = 1;
	I2C_Delay10us();
	I2C_SCL = 1;
	I2C_Delay10us();//建立时间是I2C_SDA保持时间>4.7us
	I2C_SDA = 0;
	I2C_Delay10us();//保持时间是>4us
	I2C_SCL = 0;			
	I2C_Delay10us();		
}
2)结束信号
void I2C_Stop()
{
	I2C_SDA = 0;
	I2C_Delay10us();
	I2C_SCL = 1;
	I2C_Delay10us();//建立时间大于4.7us
	I2C_SDA = 1;
	I2C_Delay10us();	
	
}

起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态在终止信号产生后,总线就处于空闲状态
接收器件收到一个完整的数据字节后,有可能需要完成一些其它工作,如处理内部中断服务等,可能无法立刻接收下一个字节,这时接收器件可以将SCL线拉成低电平,从而使主机处于等待状态。直到接收器件准备好接收下一个字节时,再释放SCL线使之为高电平,从而使数据传送可以继续进行。

3、I2C的低层时序

(1)字节发送与应答
每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)
在这里插入图片描述
由于某种原因从机不对主机寻址信号应答时(如从机正在进行实时性的处理工作而无法接收总线上的数据),它必须将数据线置于高电平,而由主机产生一个终止信号以结束总线的数据传送。

如果从机对主机进行了应答,但在数据传送一段时间后无法继续接收更多的数据时,从机可以通过对无法接收的第一个数据字节的“非应答”通知主机,主机则应发出终止信号以结束数据的继续传送。当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号。这个信号是由对从机的“非应答”来实现的。然后,从机释放SDA线,以允许主机产生终止信号。
简单来说,发完第8字节后,从机把SDA拉低就是应答;把SDA拉高就是非应答

发送一个字节与应答代码

/*******************************************************************************
* 函 数 名           : I2cSendByte(uchar num)
* 函数功能 	         : 通过I2C发送一个字节。在I2C_SCL时钟信号高电平期间,
*                    * 保持发送信号I2C_SDA保持稳定
* 输    入           : num ,ack
* 输    出         	 : 0或1。发送成功返回1,发送失败返回0
* 备    注           : 发送完一个字节I2C_SCL=0, 需要应答则应答设置为1,否则为0
*******************************************************************************/

uchar I2C_SendByte(uchar dat, uchar ack)
{
	uchar a = 0,b = 0;//最大255,一个机器周期为1us,最大延时255us。
	I2C_SCL = 0;	// 为了保证时序正确,这里应该加一句 SCL = 0;		
	for(a=0; a<8; a++)//要发送8位,从最高位开始
	{
		I2C_SDA = dat >> 7;	 //起始信号之后I2C_SCL=0,所以可以直接改变I2C_SDA信号
		dat = dat << 1;
		I2C_Delay10us();
		I2C_SCL = 1;
		I2C_Delay10us();//建立时间>4.7us
		I2C_SCL = 0;
		I2C_Delay10us();//时间大于4us		
	}

	I2C_SDA = 1;			// 主设备释放SDA线给从设备去操作
	I2C_Delay10us();
	I2C_SCL = 1;			// 主设备开始了第9个周期
	while(I2C_SDA && (ack == 1))//等待应答,也就是等待从设备把I2C_SDA拉低
	{
		b++;
		if(b > 200)	 //如果超过200us没有应答发送失败,或者为非应答,表示接收结束
		{
			I2C_SCL = 0;
			I2C_Delay10us();
			return 0;
		}
	}

	I2C_SCL = 0;
	I2C_Delay10us();
 	return 1;		
}

概念;释放总线。在51单片机中,SDA=1就是释放总线;在其他更高级的单片机(譬如STM32等)这里的处理还会有点不一样。
为什么SDA=1就是释放总线,是因为当51单片机把引脚拉高时,从设备可以选择再把这个引脚拉高或者拉低;但是当51单片机把这个引脚拉低(接地)后,从设备再也没办法把这个引脚拉高了。

I2C读取一个字节代码

/*******************************************************************************
* 函 数 名           : I2cReadByte()
* 函数功能	    	 : 使用I2c读取一个字节
* 输    入           : 无
* 输    出         	 : dat
* 备    注           : 接收完一个字节I2C_SCL=0
*******************************************************************************/

uchar I2C_ReadByte()
{
	uchar a = 0,dat = 0;
	I2C_SDA = 1;			//起始和发送一个字节之后I2C_SCL都是0
	I2C_Delay10us();
	I2C_SCL = 0;                // 按道理这里应该有一个SCL = 0的
	for(a=0; a<8; a++)//接收8个字节
	{
		I2C_SCL = 1;		// 通知从设备我要开始读了,可以放1bit数据到SDA了
		I2C_Delay10us();
		dat <<= 1;			// 读取的时候是高位在前的
		dat |= I2C_SDA;
		I2C_Delay10us();
		I2C_SCL = 0;		// 拉低,为下一个bit的周期做准备
		I2C_Delay10us();
	}
	return dat;		
}

三,EEPROM有关知识和读写操作


1、EEPROM

(1)一些概念:ROM、RAM、PROM(可编程ROM)、EPROM(可擦除ROM)、EEPROM(电可擦除ROM)
(2)为什么需要EEPROM(单片机内部的ROM只能在程序下载时进行擦除和改写,但是程序运行本身是不能改写的。单片机内部的RAM中的数据程序运行时可以改,但是掉电就丢失了。有时候我们有一些数据要存在系统中,要求掉电不丢失,而且程序还要能改。所以内部ROM和RAM都不行。这时候系统中就需要一块EEPROM)
(3)EEPROM存在系统中的2种形式:内置在单片机内部,外部扩展
(4)我们在此分析的EEPROM的型号是AT24C02

2、器件寻址
(1)从器件的地址是由从器件自身定义的,不同的从器件的地址定义方式是不同的,要查具体的芯片数据手册来确定。
(2)同一个I2C网络中只有一个主设备,但是从设备可以有多个。这多个从设备的从地址不能相同(硬件设计工程师必须保证这一点。因为从地址是不能通过软件设定的)
(3)通过分析原理图和24C02的地址定义,可以得出:
从设备地址是:读地址:0xa1,写地址:0xa0

在这里插入图片描述


AT24c02写操作


在这里插入图片描述

代码

/*******************************************************************************
* 函 数 名         : void At24c02Write(unsigned char addr,unsigned char dat)
* 函数功能		   : 往24c02的一个地址写入一个数据
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

void At24c02Write(unsigned char addr,unsigned char dat)
{
	I2C_Start();
	I2C_SendByte(0xa0, 1);//发送写器件地址
	I2C_SendByte(addr, 1);//发送要写入内存地址
	I2C_SendByte(dat, 1);	//发送数据
	I2C_Stop();
}

AT24c02读操作


在这里插入图片描述

/*******************************************************************************
* 函 数 名         : unsigned char At24c02Read(unsigned char addr)
* 函数功能		   : 读取24c02的一个地址的一个数据
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/

unsigned char At24c02Read(unsigned char addr)
{
	unsigned char num;
	I2C_Start();
	I2C_SendByte(0xa0, 1); //发送写器件地址
	I2C_SendByte(addr, 1); //发送要读取的地址
	I2C_Start();
	I2C_SendByte(0xa1, 1); //发送读器件地址
	num=I2C_ReadByte(); //读取数据
	I2C_Stop();
	return num;	
}

  • 12
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值