AT24C02.c文件
#include <regx52.h>
#include "I2C.h"
#define AT24C02_ADDRESS 0xA0
// 不需要初始化
// 将数据赋值给T的时候需要先把以前的数值提取出来,
// 不然会导致每次都重新写入计数
/**
* @brief AT24C02写入一个字节
* @param WordAddress 要写入字节的地址
* @param Data 要写入的数据
* @retval 无
*/
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS);
I2C_ReceiveAck();
I2C_SendByte(WordAddress);
I2C_ReceiveAck();
I2C_SendByte(Data);
I2C_ReceiveAck();
I2C_Stop();
}
/**
* @brief AT24C02读取一个字节
* @param WordAddress 要读出字节的地址
* @retval 读出的数据
*/
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
unsigned char Data;
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS);
I2C_ReceiveAck();
I2C_SendByte(WordAddress);
I2C_ReceiveAck();
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS|0x01);
I2C_ReceiveAck();
Data=I2C_ReceiveByte();
I2C_SendAck(1);
I2C_Stop();
return Data;
}
IIC.c文件
#include <regx52.h>
sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;
/**
* @brief I2C开始
* @param 无
* @retval 无
*/
void I2C_Start(void)
{
I2C_SDA=1;
I2C_SCL=1;
I2C_SDA=0;
I2C_SCL=0;
}
/**
* @brief I2C停止
* @param 无
* @retval 无
*/
void I2C_Stop(void)
{
I2C_SDA=0;
I2C_SCL=1;
I2C_SDA=1;
}
/**
* @brief I2C发送一个字节
* @param Byte 要发送的字节
* @retval 无
*/
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;
}
}
/**
* @brief I2C接收一个字节
* @param 无
* @retval 接收到的一个字节数据
*/
unsigned char I2C_ReceiveByte(void)
{
unsigned char i,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;
}
/**
* @brief I2C发送应答
* @param AckBit 应答位,0为应答,1为非应答
* @retval 无
*/
void I2C_SendAck(unsigned char AckBit)
{
I2C_SDA=AckBit;
I2C_SCL=1;
I2C_SCL=0;
}
/**
* @brief I2C接收应答位
* @param 无
* @retval 接收到的应答位,0为应答,1为非应答
*/
unsigned char I2C_ReceiveAck(void)
{
unsigned char AckBit;
I2C_SDA=1;
I2C_SCL=1;
AckBit=I2C_SDA;
I2C_SCL=0;
return AckBit;
先从AT24C02(EEPROM)开始:
P21----- 时钟线SCL
P20-----数据线SDA
知道了这个时候需要先去了解IIC(I2C)
IIC是同步通信的一种特殊形式,具有接口线少,控制方式简单, 器件封装形式小,通信速率较高等优点。
具体表现在:I2C 总线只有两根双向信号线。一根是 数据线 SDA,另一根是时钟线 SCL。
它的物理层有如下特点:
(1)它是一个支持多设备的总线。“总线”指多个设备共用的信号线。在 一个 I2C 通讯总线中,可连接多个 I2C 通讯设备,支持多个通讯主机及多个通 讯从机。
(2)一个 I2C 总线只使用两条总线线路,一条双向串行数据线(SDA),一 条串行时钟线(SCL)。数据线即用来表示数据,时钟线用于数据收发同步。
(3)每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址 进行不同设备之间的访问。
(4)总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而 当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平。
(5)多个主机同时使用总线时,为了防止数据冲突,会利用仲裁方式决定 由哪个设备占用总线。 261
(6)具有三种传输模式:标准模式传输速率为 100kbit/s,快速模式为 400kbit/s,高速模式下可达 3.4Mbit/s,但目前大多 I2C 设备尚不支持高速模 式。
(7)连接到相同总线的 IC 数量受到总线的最大电容 400pF 限制。
常用术语:(拣我认为重要的)
主机:启动数据传送并产生时钟信号的设备;(单片机核心是主机)
从机:被主机寻址的器件; (AT24C02是从机)
发送器:发送数据到总线的器件; AT24C02
接收器:从总线接收数据的器件。 单片机核心
每次数据传输都以字节为单位,每次传输的字节数不受限制。
起始和停止信号
SCL 线为高电平期间,SDA 线由高电平向低电平的变化表示起始信号;
SCL 线为高电平期间,SDA 线由低电平向高电平的变化表示终止信号。
起始和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态;在终止信号产生后,总线就处于空闲状态。
/**
* @brief I2C开始
* @param 无
* @retval 无
*/
void I2C_Start(void)
{
I2C_SDA=1;
I2C_SCL=1;
I2C_SDA=0;
I2C_SCL=0;
}
/**
* @brief I2C停止
* @param 无
* @retval 无
*/
void I2C_Stop(void)
{
I2C_SDA=0;
I2C_SCL=1;
I2C_SDA=1;
}
应答响应:
每当发送器件传输完一个字节的数据后,后面必须紧跟一个校验位,这个校验位是接收端通过控制 SDA(数据线)来实现的,以提醒发送端数据我这边已经接收完成,数据传送可以继续进行。
这里发送器不是单单的单片机核心和AT24C02,因为所以这里的发送器两个都可能,一个发一个收,收完再发接收完成。(一来一回)
校验位其实就是数据或地址传输过程中的响应。
响应包括“应答(ACK)”和“非应答(NACK)”两种信号。
主机的SDA由于发送的是0或1而变化,但是从机的SDA就是我们自己人为控制了。
在写程序的时候是要实时改变SDA是输入还是输出(通过从机地址来辨别)
从机不对寻址信号应答时(如从机正在进行实时性的处理 工作而无法接收总线上的数据),它必须将数据线置于高电平,而由主机产生一个终止信号以结束总线的数据传送。
如果从机对主机进行了应答(意思是继续),但在数据传送一段时间后无法继续接收更多的数据时,从机可以通过对无法接收的第一个数据字节的“非应答”(拒绝)通知主机,主机则应发出终止信号以结束数据的继续传送。
当主机接收数据时,它收到最后一个数据字节后,必须向从机发出一个结束传送的信号。这个信号是由对从机的“非应答”来实现的。然后,从机释放 SDA 线,以允许主机产生终止信号。
这些信号中,起始信号是必需的,结束信号和应答信号都可以不要。
从想停,主发终
从有事,从非应答(拒绝),主发终
主接收最后一个数据,发结束信号给从(通过对从机非应答(拒绝)),从释放SDA,主终止
总线的寻址方式
I2C 总线寻址按照从机地址位数可分为两种,一种是 7 位,另一种是 10 位。采用 7 位的寻址字节(寻址字节是起始信号后的第一个字节)的位定义如下
D7~D1 位组成从机的地址。
D0 位是数据传送方向位,为“ 0”时表示主机向从机写数据,为“1”时表示主机由从机读数据(从机发)。
用“0”表示主机发送(写)数据(W),“1”表示主机接收数据(R)。
当主机发送了一个地址后,总线上的每个器件都将头 7 位与它自己的地址比较,如果一样,器件会判定它被主机寻址,其他地址不同的器件将被忽略后面的数据信号。
至于是从机接收器还是从机发送器,都由 R/W 位决定的。
每次数据传送总是由主机产生的终止信号结束。但是,若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。
此处对照AT24C02-------------------------------这里是地址
开发板已经将芯片的 A0/A1/A2 连接到 GND,所以器件地址为 1010000
#define AT24C02_ADDRESS 0xA0
单片机核心发送给AT24C02(AT24C02里面存储数据)
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
I2C_Start(); //开始发送
I2C_SendByte(AT24C02_ADDRESS); //元器件地址
I2C_ReceiveAck(); //接收元器件地址
I2C_SendByte(WordAddress); //数据存在哪里
I2C_ReceiveAck(); //接收
I2C_SendByte(Data); //发送数据
I2C_ReceiveAck(); //接收数据
I2C_Stop(); //结束
}
AT24C02_WriteByte(1,2);在“1空间”存放“2”;
读取
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
unsigned char Data;
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS); //想读哪个元器件
I2C_ReceiveAck();
I2C_SendByte(WordAddress); //想读哪个空间的数据
I2C_ReceiveAck();
I2C_Start();
I2C_SendByte(AT24C02_ADDRESS|0x01); //表示是主机读取数据
I2C_ReceiveAck(); //通过移位读取
Data=I2C_ReceiveByte();
I2C_SendAck(1); //非应答
I2C_Stop();
return Data;
}
使用:t=AT24C02_ReadByte(1);读取“1空间”里面的数据。
引用大佬图:
脑子不行了,溜了溜了