文章目录
一、EEPROM模块-24C02介绍
1、描述
24C02是电可擦除PROM,采用256×8-bit的组织结构以及两线串行接口。电压可允许低至1.8V,待机电流和工作电流分别位1uA和1mA。24C02具有页写能力,每页为8字节。
- 宽范围的工作电压1.8V~5.5V;
- 2线串行接口,完全兼容I2C总线;
- I2C 时钟频率为1MHz (5V), 400 kHz (1.8V, 2.5V, 2.7V);
- 硬件数据写保护;
- 擦写寿命:100万次;
- 数据保持时间:100年;
2、引脚定义
3、芯片地址及存储结构
1、通过A0、A1、A2的硬件连接来确定芯片的地址
2、24C02的内存大小是2K字节,存储结构如下:
4、开发板原理图
二、IIC协议介绍
在以往的博客里,专门介绍过IIC的相关内容,地址如下:
IIC通讯详解
在此对IIC进行总结:
1、主CPU和其附属芯片之间最常用的接口,尤其是各种传感器,因此在物联网时代非常重要;
2、三根线:GND、SCL、SDA,串行、电平式;
3、总线式结构,可以一对多,总线上可以挂上百个器件,用从地址来区分;
4、主从式,由主设备来发起通信及总线仲裁(主设备决定哪个从设备工作),从设备被动响应;
5、通信速率比较低(kbps级别),不适合语音、视频等信息类型。
三、低层时序代码实现
1、起始条件
当时钟线(SCL)为高电平时,数据线(SDA)的下降沿(由高到低),叫做起始条件
代码如下:
void Iic_Start(void)
{
IIC_SDA = 1;
Iic_Delay_10us();
IIC_SCL = 1;
Iic_Delay_10us();
IIC_SDA = 0; //在SCL为高的时候,SDA产生一个下降沿
Iic_Delay_10us();
IIC_SCL = 0; //拉低SCL,准备发送数据
Iic_Delay_10us();
}
2、停止条件
当时钟线(SCL)为高电平时,数据线(SDA)的上升沿(由低到高),叫做停止条件
代码如下:
void Iic_Stop(void)
{
IIC_SDA = 0;
Iic_Delay_10us();
IIC_SCL = 1;
Iic_Delay_10us();
IIC_SDA = 1; //在SCL为高的时候,SDA产生一个上升沿
Iic_Delay_10us();
}
3、应答和非应答
1、在第9个bit位时,时钟线(SCL)为高时,接收器拉低数据线(SDA)表示应答,并在应答脉冲期间保持稳定的低电平,没有拉低表示非应答。
2、当主器件作为接收器时,必须发出数据传输结束的信号给发送器,即它在最后一个字节之后的应答脉冲期间不会产生应答信号(拉低SDA)。这种情况下发送器必须释放SDA线作为高,以便主器件产生停止条件。
应答代码如下:
void Iic_Ack(void)
{
IIC_SCL = 0;
Iic_Delay_10us();
IIC_SDA = 0;
Iic_Delay_10us();
IIC_SCL = 1;
Iic_Delay_10us();
IIC_SCL = 0;
}
非应答代码如下:
void Iic_Nack(void)
{
IIC_SCL = 0;
Iic_Delay_10us();
IIC_SDA = 1;
Iic_Delay_10us();
IIC_SCL = 1;
Iic_Delay_10us();
IIC_SCL = 0;
}
4、应答等待
主机给从机发送数据后,会等待从机的应答
unsigned char Iic_Wait_Ack(void)
{
unsigned char wait_time = 0;
IIC_SCL = 0;
Iic_Delay_10us();
IIC_SDA = 1;
Iic_Delay_10us();
IIC_SCL = 1;
while(IIC_SDA) //等待应答(SDA为低电平)
{
wait_time++;
if(wait_time > 200) //应答超时,停止等待,强制推出
{
Iic_Stop();
return 0;
}
}
IIC_SCL = 0;
return 1;
}
5、写一个字节
主机向从机写一个字节
void Iic_Write_Byte(unsigned char dat)
{
unsigned char i = 0;
IIC_SCL = 0;
Iic_Delay_10us();
for(i = 0; i < 8; i++)
{
if((dat & 0x80) > 0) //先写高字节
IIC_SDA = 1;
else
IIC_SDA = 0;
dat <<= 1;
Iic_Delay_10us();
IIC_SCL = 1;
Iic_Delay_10us();
IIC_SCL = 0;
Iic_Delay_10us();
}
}
6、读一个字节
主机向从机读一个字节
unsigned char Iic_Read_Byte(unsigned char ack)
{
unsigned char i = 0, recive = 0;
IIC_SCL = 0;
Iic_Delay_10us();
for(i = 0; i < 8; i++)
{
IIC_SCL = 1;
Iic_Delay_10us();
recive <<= 1; //注意此句代码的位置顺序
recive |= IIC_SDA; //先读高字节
Iic_Delay_10us();
IIC_SCL = 0;
Iic_Delay_10us();
}
if(ack)
Iic_Ack();
else
Iic_Nack();
return recive;
}
四、AT24C02高层代码实现
1、在AT24C02指定地址写入一个数据
向指定地址写入数据时序图
向指定地址写入数据代码实现:
void At24c02_Write_One_Byte(unsigned char addr, unsigned char dat)
{
Iic_Start(); //第一步,起始条件
Iic_Write_Byte(AT24C02_WRITE); //第二步,器件地址,写
if(Iic_Wait_Ack()) //第三步,等待从机应答
{
Iic_Write_Byte(addr); //第四步,如果应答,则发送目标地址
if(Iic_Wait_Ack()) //第五步,等待从机应答
{
Iic_Write_Byte(dat); //第六步,如果收到应答,则在相应的内存地址写入数据
Iic_Wait_Ack(); //第七步,等待从机应答
Iic_Stop(); //第八步,停止条件
}
else
Iic_Stop(); //如果没有收到从机的应答,则发送结束条件,让出总线
}
else
Iic_Stop(); //如果没有收到从机的应答,则发送结束条件,让出总线
}
2、向AT24C02指定地址读取一个数据
向指定地址读取数据时序图
向指定地址读取数据代码实现:
unsigned char At24c02_Read_One_Byte(unsigned char addr)
{
unsigned char recive;
Iic_Start(); //第一步,起始条件
Iic_Write_Byte(AT24C02_WRITE); //第二步,器件地址,写
if(Iic_Wait_Ack()) //第三步,等待从机应答
{
Iic_Write_Byte(addr); //第四步,如果应答,则发送目标地址
if(Iic_Wait_Ack()) //第五步,等待从机应答
{
Iic_Start(); //第六步,如果收到应答,则再次发送起始条件
Iic_Write_Byte(AT24C02_READ); //第七步,器件地址,写
if(Iic_Wait_Ack()) //第八步,等待从机应答
{
recive = Iic_Read_Byte(0); //第九步,如果收到应答,接收数据
//第十步,等待应答,也可以不等待
Iic_Stop(); //第十一步,停止条件
}
else
Iic_Stop(); //如果没有收到从机的应答,则发送结束条件,让出总线
}
else
Iic_Stop(); //如果没有收到从机的应答,则发送结束条件,让出总线
}
else
Iic_Stop(); //如果没有收到从机的应答,则发送结束条件,让出总线
return recive;
}
五、一些宏定义
#define AT24C02_READ 0xA1
#define AT24C02_WRITE 0xA0
sbit IIC_SCL = P2^1; //SCL时钟线
sbit IIC_SDA = P2^0; //SDA数据线
总结
1、本次介绍了IIC通信的相关知识以及实现代码;
2、本次介绍了AT24C02的操作时序;
3、该节的重点是看懂时序图,并用代码实现。