51单片机 AT24C02(I2C总线)
存储器
随机存储 RAM
只读存储 ROM
AT24C02芯片
是一种可以实现掉电不丢失的存储器,可用于保存单片机运行时想要永久保存的数据信息
存储材质:E2PROM
通讯接口:I2C总线
容量:256字节
I2C总线
一种通用的数据总线
两根通信线:SCL,SDA
同步、半双工、带数据应答
I2C电路规范
所有I2C设备的SCL连在一起,SDA连在一起
设备的SCL和SDA均要配置成开漏输出模式
SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右
开漏输出和上拉电阻的共同作用实现了“线与"的功能,此设计主要
是为了解决多机通信互相干扰的问题
I2C时序结构
起始条件
SCL高电平期间,SDA从高电平切换到低电平
终止条件
SCL高电平期间,SDA从低电平切换到高电平
// 生成I2C启动条件
void I2c_Start()
{
I2C_SDA = 1; // 拉高SDA线
I2C_SCL = 1; // 拉高SCL线
I2C_SDA = 0; // SDA线从高电平变为低电平,产生启动条件
I2C_SCL = 0; // 拉低SCL线
}
// 生成I2C停止条件
void I2C_Stop()
{
I2C_SDA = 0; // 拉低SDA线
I2C_SCL = 1; // 拉高SCL线
I2C_SDA = 1; // SDA线从低电平变为高电平,产生停止条件
}
发送一个字节
SCL低电平期间,主机将数据位依次放到SDA线上
(高位在前),然后拉高SCL,从机将在SCL高电平期间读取数据位,
所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,
即可发送一个字节
// 发送一个字节数据
void I2C_SendByte(unsigned char Byte)
{
unsigned char i;
for (i = 0; i < 8; i++) {
I2C_SDA = Byte & (0x80 >> i); // 依次发送字节的每一位
I2C_SCL = 1; // 拉高SCL线,产生时钟信号
I2C_SCL = 0; // 拉低SCL线
}
}
接收一个字节
SCL低电平期间,从机将数据位依次放到SDA线上
(高位在前),然后拉高SCL,主机将在SCL高电平期间读取数据位
所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次
即可接收一个字节(主机在接收之前,需要释放SDA)
// 接收一个字节数据
unsigned char I2C_ReceiveByte()
{
unsigned char i, Byte = 0x00;
I2C_SDA = 1; // 释放SDA线,准备接收数据
for (i = 0; i < 8; i++) {
I2C_SCL = 1; // 拉高SCL线,产生时钟信号
if (I2C_SDA) {
Byte |= (0x80 >> i); // 读取SDA线上的数据位
}
I2C_SCL = 0; // 拉低SCL线
}
return Byte; // 返回接收到的字节
}
发送应答
在接收完一个字节之后,主机在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
接收应答
在发送完一个字节之后,主机在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
// 发送应答信号
void I2C_SendAck(unsigned char AckBit)
{
I2C_SDA = AckBit; // 设置SDA线为应答信号
I2C_SCL = 1; // 拉高SCL线,产生时钟信号
I2C_SCL = 0; // 拉低SCL线
}
// 接收应答信号
unsigned char I2C_ReceiveAck()
{
unsigned char AckBit;
I2C_SDA = 1; // 释放SDA线,准备接收应答信号
I2C_SCL = 1; // 拉高SCL线,产生时钟信号
AckBit = I2C_SDA; // 读取SDA线上的应答信号
I2C_SCL = 0; // 拉低SCL线
return AckBit; // 返回接收到的应答信号
}
SLAVE ADDRESS: A6-A3是固定的
A2-A0是可配的
最后一位是确定读或写的0是写,1是读
过程:
开始——>发送从机地址 + write——>接收应答——>发送一个字节——>接受应答——>……发送字节——>接受应答——>结束
过程:
开始——>发送从机地址 + read——>接收应答——>接收一个字节——>发送应答——>……接收字节——>发送应答or发送非应答——>结 束
字节写入和读取
// 向AT24C02的指定地址写入一个字节数据
void AT24C02_WriteByte(unsigned char WordAddress, unsigned char Data)
{
I2c_Start(); // 生成启动条件
I2C_SendByte(AT24C02_ADDRESS); // 发送设备地址和写命令
I2C_ReceiveAck(); // 接收应答信号
I2C_SendByte(WordAddress); // 发送字地址
I2C_ReceiveAck(); // 接收应答信号
I2C_SendByte(Data); // 发送数据
I2C_ReceiveAck(); // 接收应答信号
I2C_Stop(); // 生成停止条件
}
// 从AT24C02的指定地址读取一个字节数据
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; // 返回读取的数据
}
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化
每次数据传输都以字节为单位,每次传输的字节数不受限制。