I2C(Inter-Integrated Circuit)总线是由PHILIPS公司开发的两线式串行总线,用于连接微控制器及其外围设备。是微电子通信控制领域广泛采用的一种总线标准。它是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点。
只要求两条总线线路:一条串行数据线SDA,一条串行时钟线SCL;串行的8 位双向数据传输位速率在标准模式下可达100kbit/s,快速模式下可达400kbit/s,高速模式下可达3.4Mbit/s;每个连接到总线的器件都可以通过唯一的地址和一直存在的简单的主机/从机关系软件设定地址,主机可以作为主机发送器或主机接收器; 它是一个真正的多主机总线,如果两个或更多主机同时初始化,数据传输可以通过冲突检测和仲裁防止数据被破坏;
I2C的使用实际上是严格遵循I2C总线协议进行的,下面我们结合STM32F051一一进行分析:
首先看I2C总线硬件:
硬件准备:
重新开始信号:它本质上是一个开始信号,信号电平和开始信号一样,是在连续传输信号时进行使用。
应答信号:接收数据的IC在接收到8位数据后,会向主设备发出一个特定的低电平脉冲,这就是应答信号。应答信号一般在第9个周期出现,每位信号必须跟一位应答信号,表示数据已经接收。
如下图所示:
上面两个图表示了数据连续传输的基本格式,那么下面我们就来学习如何通过I2C对24c02进行读写。
软件准备:
采样库函数编写程序,工程配置如下图所示,用户需要调用stm32f0xx_i2c.c库函数。需要编写i2c_eeprom.c驱动文件和主函数main.c。
首先是开始信号,然后发送从机地址,写选通,给一个应答信号。然后写入要访问的地址。
再次应答。从新开始信号,发送从机地址,从机地址是外挂总线地址。然后读选通,主机等待从机的应答信号,当接收应答后,开始读取数据。
而24C02写和读是按照页进行。而按页写最大页面不超过8个字节,超过后会发送覆盖。此时采用缓冲进行处理和分配,下面几个函数就是写缓冲和写页面:
1
|
uint32_t sEE_ReadBuffer(uint8_t* pBuffer, uint16_t ReadAddr, uint16_t* NumByteToRead);
|
读缓冲函数:uint8_t* pBuffer:缓冲指针。
uint16_t ReadAddr:读的地址。
uint16_t* NumByteToRead:读字节数
1
|
uint32_t sEE_WritePage(uint8_t* pBuffer, uint16_t WriteAddr, uint8_t* NumByteToWrite);
|
写页函数:uint8_t* pBuffer, 缓冲指针
uint16_t WriteAddr, 写的地址
uint8_t* NumByteToWrite 写字节数
1
|
void
sEE_WriteBuffer(uint8_t* pBuffer, uint16_t WriteAddr, uint16_t NumByteToWrite);
|
写缓冲函数:uint8_t* pBuffer, 缓冲指针
uint16_t WriteAddr, 写的地址
uint8_t* NumByteToWrite 写字节数
1
|
uint32_t sEE_WaitEepromStandbyState(
void
);
|
等待EEPROM待机状态
主函数首先向24c02写入一个数据,然后读出这个数据。对比两个数据是否一样,判断读写是否正确:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
uint8_t temp1[]=
"qfstm32"
;
uint8_t temp2[];
int
main(
void
)
{
SystemInit();
LCD_init();
// 液晶显示器初始化
LCD_Clear(WHITE);
// 全屏显示白色
POINT_COLOR = BLACK;
// 定义笔的颜色为黑色
BACK_COLOR = WHITE;
// 定义笔的背景色为白色
I2C_EE_Init();
SPI_FLASH_Init();
LCD_DrawRectage(0, 0, 320, 20, DARKBLUE);
// 画一个深蓝色边框的矩形
LCD_ShowString(2,2,
"实验十一"
);
LCD_ShowString(100,2,
"i2c读24c02实验"
);
sEE_WriteBuffer(temp1, 0x050, 8);
LCD_ShowString(2,40,
"24c02写入值:"
);
LCD_ShowString(100,40,temp1);
NumDataRead=8;
sEE_ReadBuffer(temp2, 0x050,(uint16_t *)(&NumDataRead));
LCD_ShowString(2,60,
"24c02读出值:"
);
LCD_ShowString(100,60,temp2);
if
(*temp1 != *temp2)
{
LCD_ShowString(50,80,
"读取EEROR"
);
}
else
{
LCD_ShowString(50,80,
"读取sccess"
);
}
while
(1)
{}
}
|