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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
#include "stm32f10x.h"
#include "stm32f10x_i2c.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "misc.h"
// EEPROM 地址(AT24C02,A0-A2=0,写地址为 0xA0,读地址为 0xA1)
#define EEPROM_ADDR 0xA0
// 函数声明
void I2C1_Init(void);
void I2C_EE_ByteWrite(uint8_t device_addr, uint16_t mem_addr, uint8_t data);
uint8_t I2C_EE_ByteRead(uint8_t device_addr, uint16_t mem_addr);
void I2C_EE_PageWrite(uint8_t device_addr, uint16_t mem_addr, uint8_t* pBuffer, uint16_t NumByteToWrite);
void I2C_EE_BufferRead(uint8_t device_addr, uint16_t mem_addr, uint8_t* pBuffer, uint16_t NumByteToRead);
void Delay_ms(uint32_t ms);
int main(void)
{
uint8_t write_data = 0x55;
uint8_t read_data = 0;
// 系统时钟配置(使用内部8MHz,不配置PLL,默认系统时钟为8MHz)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
I2C1_Init();
// 写入一个字节到地址 0x10
I2C_EE_ByteWrite(EEPROM_ADDR, 0x10, write_data);
Delay_ms(10); // 等待 EEPROM 内部写入完成(最大 5ms,保险起见 10ms)
// 从地址 0x10 读取一个字节
read_data = I2C_EE_ByteRead(EEPROM_ADDR, 0x10);
// 此时 read_data 应为 0x55
while (1)
{
// 可添加 LED 闪烁等调试
}
}
// I2C1 初始化(硬件 I2C)
void I2C1_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// 配置 PB6 (SCL), PB7 (SDA) 为复用开漏输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 复用开漏
GPIO_Init(GPIOB, &GPIO_InitStructure);
// I2C1 配置
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // 标准模式下使用 2
I2C_InitStructure.I2C_OwnAddress1 = 0x00; // 主机模式,不需要自身地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitStructure.I2C_ClockSpeed = 100000; // 100kHz
I2C_Init(I2C1, &I2C_InitStructure);
I2C_Cmd(I2C1, ENABLE);
}
// 向 EEPROM 写入一个字节
void I2C_EE_ByteWrite(uint8_t device_addr, uint16_t mem_addr, uint8_t data)
{
// 等待总线空闲
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
// 发送起始条件
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
// 发送设备地址(写)
I2C_Send7bitAddress(I2C1, device_addr, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// 发送内存地址(AT24C02 地址为 8 位)
I2C_SendData(I2C1, (uint8_t)mem_addr);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// 发送数据
I2C_SendData(I2C1, data);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// 发送停止条件
I2C_GenerateSTOP(I2C1, ENABLE);
}
// 从 EEPROM 读取一个字节
uint8_t I2C_EE_ByteRead(uint8_t device_addr, uint16_t mem_addr)
{
uint8_t data = 0;
// 第一步:写入要读取的地址
while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, device_addr, I2C_Direction_Transmitter);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
I2C_SendData(I2C1, (uint8_t)mem_addr);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// 第二步:重新起始,切换到读模式
I2C_GenerateSTART(I2C1, ENABLE);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT));
I2C_Send7bitAddress(I2C1, device_addr, I2C_Direction_Receiver);
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
// 关闭 ACK(单字节读取)
I2C_AcknowledgeConfig(I2C1, DISABLE);
// 发送 STOP 条件(在接收前或后,根据芯片要求)
I2C_GenerateSTOP(I2C1, ENABLE);
// 读取数据
while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED));
data = I2C_ReceiveData(I2C1);
// 重新使能 ACK(为后续通信准备)
I2C_AcknowledgeConfig(I2C1, ENABLE);
return data;
}
// 简单延时函数(基于系统时钟 8MHz)
void Delay_ms(uint32_t ms)
{
uint32_t i, j;
for (i = 0; i < ms; i++)
for (j = 0; j < 8000; j++);
}
|