环境
- MCU型号:STM32F103ZET6
- 开发方式:库函数
一、I2C总线介绍
I2C通讯协议(Inter - Integrated Circuit)是由Phiilps公司开发,由于它引脚少,硬件简单实现,可扩展性强,不需要USART、CAN等通讯协议的外部收发设备,被广泛使用在系统内多个集成电路间通讯。
- I2C总线结构
- I2C是由2根双向总线组成
- SCL 串行时钟线,由主设备产生,控制数据传输的时序。
- SDA 串行数据线,用于传输数据。
2.I2C总线特点
- 简单性:仅需要两根线即可实现通讯,结构简单,易于实现
- 多主设备:I2C总线可以连接多个主设备,但同一时刻只能由一个主设备控制总线
- 多从设备:I2C总线可以连接多个从设备,每个从设备都有一个唯一的地址
- 低速:I2C总线传输速率较低,一般用于短距离低速数据传输
- 开漏输出:I2C总线的设备都采用开漏输出,通过上拉电阻将信号拉高
3.I2C总线通讯过程
1.起始信号:主设备拉低SDA线,然后拉低SCL线,产生起始信号,表示开始一次通讯。 2.设备地址:主设备发送7位或10位从设备地址,以及读/写位。 3.数据传输: 主设备和从设备之间按照字节为单位进行传输。 4.停止信号:主设备拉高SCL线,然后拉高SDA,产生停止信号,表示一次通讯结束。
- I2C总线应用
- 传感器:温湿度传感器,光传感器,加速度传感器等。
- 储存器:E2PROM,实时时钟等。
- 显示器:LCD、OLED等。
- 音频设备:CODEC等。
5.I2C总线注意事项
- 上拉电阻:I2C总线需要连接上拉电阻,保证SCL和SDA在空闲状态下保持高电平
- 时序:I2C通讯对时序要求高,需要严格按照时序操作。
- 总线负载:I2C总线上的设备数量和总线长度会影响总线的性能。
二、E2PROM介绍
2.1 芯片地址介绍
查手册和原理图得知AT24C02的设备地址前4位是固定的1010,我们设备是2K的,所以是第一行中的,我们的设备地址应该是10100000(写)或10100001(读)。
(题外话:如果设备是不是2K的,是4K、8K、16K,读写设备地址怎么看?),在手册中后面位的P0、P1、P2是由未分配的储存块决定的。什么意思呢?假设我们的型号是4K的,就要用组合方式和地址扩展来说明P1和P0是如何工作的
- 组合方式: P1和P0的组合可以产生四种不同的状态(00、01、10、11),对应着芯片内部的四个不同的存储块。
- 地址扩展: 通过将P1和P0的值与固定的1010和A2 A1 A0组合起来,形成一个更长的地址,从而对不同的存储块进行寻址
举例说明
假设AT24C08的总存储容量为1024字节,分为4个存储块,每个存储块256字节。当P1=0,P0=0时,访问的是第一个存储块;当P1=1,P0=1时,访问的是第四个存储块。是为提高更多的寻址能力设计的。
2.2 写入的指令流程
解释
- 发送起始信号
- 发送设备地址(写)
- 等待AT24C02应答,低电平有效
- 发送储存地址,AT24C02内部有(2k/8)=256字节,地址范围0x00到0xFF,发送地址就是告诉AT24C02接下来的数据存在哪个地方
- 等待AT24C02应答,低电平有效
- 发送8个字节的数据,这些数据就是想储存到AT24C02的数据(这里手册中规定型号2K的只能写8个字节,也就是循环一次)
- 等待AT24C02应答,低电平有效
- 发送停止信号
2.3 从任意地址读任意字节的指令流程
解释(按随机读,这种最常用)
- 发送起始信号
- 发送设备地址(写权限)
- 等待AT24C02应答,低电平有效
- 发送要读的储存地址,AT24C02内部有(2k/8)=256字节,地址范围0x00到0xFF,发送地址就是告诉AT24C02接下来的应该返回哪个地址的数据给单片机
- 等待AT24C02应答,低电平有效
- 重新发送起始信号
- 发送设备地址(读权限)
- 等待AT24C02应答,低电平有效
- 循环读取数据,接收AT24C02返回的数据,读数据没有字节限制,可以读1个,也可以一次性读完
- 发送非应答,高电平有效
- 发送停止信号
三、AT24C02读写代码
- 写入一个字节
代码
#if !defined(_AT24C02_H_)
#define _AT24C02_H_
#include "i2c.h"
#define AT24C02_Address 0xA0
#define AT24C02_Read_Address 0xA1
void AT24C02_Init(void);
void AT24C02_WriteOneByte(u8 Address,u8 Dat);
u8 AT24C02_ReadOneByte(u8 Address);
#endif // _AT24C02_H_
#include "at24c02.h"
void AT24C02_Init(void)
{
IIC_Init();
}
void AT24C02_WriteOneByte(u8 Address, u8 Dat)
{
IIC_Start();
IIC_Send_Byte(AT24C02_Address);
IIC_Wait_Ack();
IIC_Send_Byte(Address); // 这里是EEPROM的储存地址
IIC_Wait_Ack();
IIC_Send_Byte(Dat);
IIC_Wait_Ack();
IIC_Stop();
}
u8 AT24C02_ReadOneByte(u8 Address)
{
u8 temp = 0;
IIC_Start();
IIC_Send_Byte(AT24C02_Address);
IIC_Wait_Ack();
IIC_Send_Byte(Address); // 这里是EEPROM的储存地址
IIC_Wait_Ack();
IIC_Start();
IIC_Send_Byte(AT24C02_Read_Address);
IIC_Wait_Ack();
temp = IIC_Read_Byte(0);
IIC_Stop();
return temp;
}
u32 AT24C02_ReadLenByte(u8 Address, u8 Length)
{
u32 temp;
for (u8 i = 0; i < Length; i++)
{
temp = temp << 8;
temp = AT24C02_ReadOneByte(Address) + temp;
}
return temp;
}
void AT24C02_Read(u8 Address, u8 *pBuffer, u16 Length)
{
while (Length--)
{
Address++;
*pBuffer = AT24C02_ReadOneByte(Address);
}
}
void AT24C02_Write(u8 Address, u8 *pBuffer, u16 Length)
{
while (Length--)
{
AT24C02_WriteOneByte(Address, *pBuffer);
Address++;
pBuffer++;
}
}