I2C通信实现AT24C02存储数据

1.I2C介绍

I2C总线(Inter IC BUS)是由Philips公司开发的一种通用数据总线。

两根通信线:SCL(Serial Clock)SDA(Serial Data)

通信特点:同步、半双工,带数据应答Ack

2.常见通信接口比较

2.1相关术语介绍

全双工:通信双方在同一时刻互相传送数据。

半双工:通信双方互相双送信息,但是不能同时进行而是分时复用同一根线。

单工:通信从一方发送到另一方,不能反向。

异步:通信双方各自约定通信速率

同步:通信双方靠一根时钟线约定速率。

总线:连接各个设备的数据传输路线。

3.I2C电路规范

(1)I2C总线使用连接设备的SCL(串行时钟总线)和SDA(串行数据总线)来控制发送数据和读数据。

(2)设备的SCL和SDA均要配置成开漏输出模式。

(3)SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右。

(4)开漏输出和上拉电阻的共同作用实现了“线与”的功能,此设计主要是为了解决多机通信互相干扰的问题

4.I2C通信发送数据时序结构

发送一帧数据步骤:

  • 开始条件:S
  • 发送地址:SLAVE ADDRESS+W/R  写地址或者读地址(发送完地址要加应答位)
  • 发送数据:BYTE1.BYTE2........BYTEn(发送完一字节数据要加应答位)
  • 停止条件:  P

4.1I2C标准时序图

主机在 SCL 线上输出串行时钟信号,数据在 SDA 线上进行传输,每传输一个字节(最高位 MSB 开始传输)后面跟随一个应答位Ack,一个 SCL 时钟脉冲传输一个数据位。

4.2开始和终止条件

当总线上的主机都不驱动总线,总线进入空闲状态, SCL 和 SDA 都为高电平。

起始条件:SCL高电平期间,SDA从高电平切换到低电平

终止条件:SCL高电平期间,SDA从低电平切换到高电平

//I2C开始
//参数:无
void I2C_Start(void)
{
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}

//I2C停止
//参数:无
void I2C_Stop(void)
{
	I2C_SDA=0;//停止之前是有数据的
	I2C_SCL=1;
	I2C_SDA=1;
}

4.3发送地址

开始条件后面的帧是地址帧(一个字节),用于指定主机通信的对象地址SLAVE ADDRESS。

=

由上图可以看出地址帧的前七位是从机的地址,最后一位决定往从机里面R写数据还是W读数据。

第八位0,写数据。第八位1读数据。

S:代表开始

SLAVE ADDRESS:代表着发送从机地址

RA:为0,代表从机应答。

4.4.发送数据

4.4.1发送一个字节(接受一个字节)
//I2C发送一个字节
//参数:Byte
void I2C_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
	I2C_SDA=Byte&(0x80>>i);
	I2C_SCL=1;
	I2C_SCL=0;
	}
}

//I2C接受一个字节
//参数:无
//接收到的字节数据
unsigned char I2C_ReceiveByte()
{
	unsigned char i;
	unsigned char Byte=0x00;
	I2C_SDA=1;
	for(i=0;i<8;i++)
{	
	I2C_SCL=1;
	if(	I2C_SDA){Byte|=(0x80>>i);}
	I2C_SCL=0;
}
	return Byte;
}

发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

 接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

    

4.4.2发送应答位(接受应答位)

消息中的每一帧后面都跟随一个应答⁄不应答位。如果成功接收到一个地址帧或数据帧,则从机会向主机返回一个ACK位

发送应答:在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答。应答是什么?是接收方向发送方传送的握手信号,表示我已经接受到您发的消息了!!

接收应答:在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

//I2C发送应答
//参数Ackbit:0为应答,1为非应答
void I2C_SendAck(unsigned char Ackbit )
{
	I2C_SDA=Ackbit;
	I2C_SCL=1;
	I2C_SCL=0;
}

//I2C接受应答
//无参数
//返回值接收到的应答位
unsigned char I2C_RecieveAck(void)
{
	unsigned char Ackbit;
	I2C_SDA=1;
	I2C_SCL=1;
	Ackbit=I2C_SDA;
	I2C_SCL=0;
	
	return Ackbit;
	
}

 5.AT24C02存储数据

5.1AT24C02介绍

AT24C02是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息

存储介质:E2PROM

通讯接口:I2C总线

容量:256字节

5.2AT24C02引脚及应用电路

5.3AT24C02内部结构框图

简单来说,就是通过SCL和SDA接口获得数据,经过一定的逻辑,数据存储到EEPROM(通过X和Y来控制数据的存储位置),并且可以通过一定的逻辑,将数据输出出来 

字节写:在“字地址”处写入“数据”DATA WORD ADDR/COUNTER-用来设置地址,内部设有存储地址的寄存器,每写入或读出一个地址,这个寄存器会自动加1,如果读出不指定地址的话,它默认把寄存器的数据拿出来。

 5.4AT24C02数据帧发送和读写

AT24C02的固定地址为1010,可配置地址本开发板上为000     所以SLAVE ADDRESS+W为0xA0,SLAVE ADDRESS+R为0xA1

 字节写:主机向从机的“字地址”处写入“数据”

随机读:主机写入从机地址--从机应答后--再写入字地址--读从机地址--读出在“字地址”处的“数据” --接受完以后不应答--停止。

 

5.3AT24C0存储数据

实验结果:将存储的数据再LCD1602上读出来

5.3.1子程序

包含AT24C02.c,AT24C02.h,I2C.c,I2C.h,Delay.cDelay.h,Key.c和Key.h以及main.c LCD1602.c和LCD1602.h

5.3.2I2C.c子程序
#include <REGX52.H>

sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;


//I2C开始
//参数:无
void I2C_Start(void)
{
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}

//I2C停止
//参数:无
void I2C_Stop(void)
{
	I2C_SDA=0;//停止之前是有数据的
	I2C_SCL=1;
	I2C_SDA=1;
}

//I2C发送一个字节
//参数:Byte
void I2C_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
	I2C_SDA=Byte&(0x80>>i);
	I2C_SCL=1;
	I2C_SCL=0;
	}
}

//I2C接受一个字节
//参数:无
//接收到的字节数据
unsigned char I2C_ReceiveByte()
{
	unsigned char i;
	unsigned char Byte=0x00;
	I2C_SDA=1;
	for(i=0;i<8;i++)
{	
	I2C_SCL=1;
	if(	I2C_SDA){Byte|=(0x80>>i);}
	I2C_SCL=0;
}
	return Byte;
}


//I2C发送应答
//参数Ackbit:0为应答,1为非应答
void I2C_SendAck(unsigned char Ackbit )
{
	I2C_SDA=Ackbit;
	I2C_SCL=1;
	I2C_SCL=0;
}

//I2C接受应答
//无参数
//返回值接收到的应答位
unsigned char I2C_RecieveAck(void)
{
	unsigned char Ackbit;
	I2C_SDA=1;
	I2C_SCL=1;
	Ackbit=I2C_SDA;
	I2C_SCL=0;
	
	return Ackbit;
	
}



 5.3.3I2C.h子程序
#ifndef  __I2C_H__
#define  __I2C_H__

void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte();
void I2C_SendAck(unsigned char Ackbit );
unsigned char I2C_RecieveAck(void);
#endif
 5.3.4AT24C02.c子程序
#include <REGX52.H>
#include "I2C.h"

#define  AT24C02_ADDRESS 0xA0

//主机向AT24C02写入一个字节
//参数:worldAddress要写入字节的地址
//参数:Data要写入的数据
//返回值无
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
	I2C_Start();//开始
  I2C_SendByte(AT24C02_ADDRESS);//发送从机地址
  I2C_RecieveAck();//从机接受应答
	I2C_SendByte(WordAddress);//发送字地址
	I2C_RecieveAck();//从机接受应答
	I2C_SendByte(Data);//发送数据
	I2C_RecieveAck();//从机接受应答
	I2C_Stop();//停止

}


//AT24C02读出一个字节
//参数:worldAddress要读出字节的地址
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
	unsigned char Data;
	I2C_Start();//开始
  I2C_SendByte(AT24C02_ADDRESS);//发送从机地址
  I2C_RecieveAck();//从机接收应答
	I2C_SendByte(WordAddress);//发送字地址
	I2C_RecieveAck();//从机接收应答
//	I2C_Start();//开始
	I2C_SendByte(AT24C02_ADDRESS|0x01);//主机发送从机读地址
	I2C_RecieveAck();//从机接受应答
  Data=I2C_ReceiveByte();//主机接收数据
	I2C_SendAck(1);//主机发送给从机停止应答
	I2C_Stop();//停止
	return Data;
	
}

5.3.5AT24C02.h

#ifndef  __AT24C02_H__
#define  __AT24C02_H__

void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);

#endif

5.4main.c主程序

#include <REGX52.H>
#include "LCD1602.h"
#include "Key.h"
#include "AT24C02.h"
#include "Delay.h"

unsigned char KeyNum;
unsigned int Num;

void main()
{
	LCD_Init();
	LCD_ShowNum(1,1,Num,5);
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)	//K1按键,Num自增
		{
			Num++;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==2)	//K2按键,Num自减
		{
			Num--;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==3)	//K3按键,向AT24C02写入数据
		{
			AT24C02_WriteByte(0,Num%256);
			Delay(5);
			AT24C02_WriteByte(1,Num/256);
			Delay(5);
			LCD_ShowString(2,1,"Write OK");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
		if(KeyNum==4)	//K4按键,从AT24C02读取数据
		{
			Num=AT24C02_ReadByte(0);
			Num|=AT24C02_ReadByte(1)<<8;
			LCD_ShowNum(1,1,Num,5);
			LCD_ShowString(2,1,"Read OK ");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
	}
}

  • 10
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值