AT24C系列是常见的EEPROM存储芯片, 常用于保存参数及掉电记忆的数据. 访问AT24C时I2C总线的频率不能太高, AT24C系列的I2C总线最高频率是400KHz(2.7V), 在1.8V时频率会降到100KHz, STC8H系列的主频基本上从24MHz起步, 甚至直接运行在36.864MHz上, I2C总线的频率是基于FOSC计算的, 在最初的调试阶段, 务必设置一个较大的预分频, 这样可以确保问题不出在频率过高上
目录
====
AT24C系列
=========
![](https://img2022.cnblogs.com/blog/650273/202207/650273-20220704055426731-1277627101.jpg)
AT24C系列是常见的EEPROM存储芯片, 常用于保存参数及掉电记忆的数据
-
容量: 型号代表了其容量, 从AT24C01到AT24C1024, 存储容量为1K BIT ~ 1024K BIT, 注意单位是Bit, 如果转换为字节就是128字节 ~ 128K字节
-
电压: 整个系列有2.7V (2.7V至5.5V)和1.8V (1.8V至5.5V)两个版本, 都兼容3.3V和5V
-
封装: 8-lead PDIP, 8-lead JEDEC SOIC, 8-lead MAP, 5-lead SOT23, 8-lead TSSOP 和 8-ball dBGA2
与其他存储器件相比
-
容量小
-
皮实, 几近无限的擦写次数: 10万次以上, 典型值为百万
-
超长的数据保持: 40年以上
-
工作温度范围: 工业级[-55℃,125℃]
-
I2C总线, 只需要SCL和SDA两个接口, 并且可以和其他I2C设备复用
-
支持写保护
因为这些特点, AT24C常用于一些容量小但是稳定性要求高, 并且需要反复擦写的场景.
AT24C的设备地址和存储地址
=========================
设备地址
AT24C的设备地址都是一个字节, 以二进制 1010
开头, 通过A0,A1,A2这三个pin进行调整. 根据容量不同, 设备地址和寻址范围有区别
AT24C01 - AT24C16
这个系列的存储地址只有一个字节, 所以内存寻址只有256字节(2048 bit), 对于AT24C01, AT24C02可以直接寻址, 对于更大容量的型号, 需要结合设备地址对内存地址分page访问
-
AT24C01, AT24C02: 设备地址 0xA0 - 0xAE, 第8位是R/W, 同一个I2C总线上可以并存8个同类设备
-
AT24C04: 0xA0 - 0xAC, 第7位是page选择, 第8位是R/W, 同一个I2C总线上可以并存4个同类设备
-
AT24C08: 0XA0 - 0xA8, 第6,7位是page选择, 第8位是R/W, 同一个I2C总线上可以并存2个同类设备
-
AT24C16: 0XA0, 第5, 6,7位是page选择, 第8位是R/W, 同一个I2C总线上只能存在1个同类设备
AT24C32, AT24C64
AT24C128, AT24C256, AT24C512
AT24C1024
-
设备地址 0xA0 - 0xA4, 第5位固定为0, 第7位是page选择, 第8位是R/W, 同一个I2C总线上可以并存2个同类设备
-
存储地址两个字节, 所以内存寻址只有64K字节, 128K需要分两个page进行访问
通过STC8H访问AT24C系列存储芯片
==============================
注意
访问AT24C时I2C总线的频率不能太高.
-
AT24C系列的I2C总线最高频率是400KHz(2.7V), 在1.8V时频率会降到100KHz
-
市面上的兼容芯片可能会达不到前面的指标
-
STC8H系列的主频基本上从24MHz起步, 甚至直接运行在36.864MHz上
-
STC8H I2C总线的频率是基于FOSC计算的, 在最初的调试阶段, 务必设置一个较大的预分频, 这样可以确保问题不出在频率过高上
接线
![](https://img2022.cnblogs.com/blog/650273/202207/650273-20220704054926314-224272643.jpg)
对于DIP8封装, 接线方式都是一样的, 测试使用的是 STC8H3K64S2, 可以直接替换为 STC8H 其它型号, 除了下面的4个pin, 还需要选择将A0, A1, A2 接GND或接VCC
1
2
3
4
5
6
7
8
9
10
11
12
|
P32 -> SCL
P33 -> SDA
GND -> GND
3.3V -> VCC
|
AT24C08访问示例
这个例子演示了单字节存储地址系列型号的访问方式
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
#include "fw_hal.h"
// 设置地址 0xA0, 对应A0,A1,A2三个pin都接地, 测试中根据自己的接线修改
#define AT24C_ADDR 0xA0
__CODE int8_t dat[20] = {0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB};
// I2C初始化
void I2C_Init(void)
{
// 主设备模式
I2C_SetWorkMode(I2C_WorkMode_Master);
/**
* I2C 总线频率 = FOSC / 2 / (__prescaler__ * 2 + 4) 这里设成最大值0x3F
*/
I2C_SetClockPrescaler(0x3F);
// 选择I2C端口
I2C_SetPort(I2C_AlterPort_P32_P33);
// 启用 I2C
I2C_SetEnabled(HAL_State_ON);
}
// GPIO初始化
void GPIO_Init(void)
{
// SDA
GPIO_P3_SetMode(GPIO_Pin_3, GPIO_Mode_InOut_QBD);
// SCL
GPIO_P3_SetMode(GPIO_Pin_2, GPIO_Mode_Output_PP);
}
int main(void)
{
uint8_t offset, i, buf[20];
SYS_SetClock();
// 开启 UART1, baud 115200 with Timer2, 1T mode, no interrupt
UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200);
GPIO_Init();
I2C_Init();
// 对地址0x00连续写入12个字节
I2C_Write(AT24C_ADDR, 0x00, dat, 12);
while(1)
{
// 分4次, 起始地址递增, 每次连续读出6个字节并通过串口输出
for (offset = 0; offset < 4; offset++)
{
I2C_Read(AT24C_ADDR, offset, buf, 6);
for (i = 0; i < 6; i++)
{
UART1_TxHex(buf[i]);
UART1_TxChar(':');
}
UART1_TxString(" ");
SYS_Delay(10);
}
UART1_TxString("\r\n");
// 间隔1秒
SYS_Delay(1000);
}
}
|
代码地址
AT24C32访问示例
这个例子演示了双字节存储地址系列型号的访问方式
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
|
#include "fw_hal.h"
// AT24C device address, change according to the voltage level of A0/A1/A2
#define AT24C_ADDR 0xA0
// Test data
__CODE int8_t dat[20] = {0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB};
void I2C_Init(void)
{
// Master mode
I2C_SetWorkMode(I2C_WorkMode_Master);
/**
* I2C clock = FOSC / 2 / (__prescaler__ * 2 + 4)
*/
I2C_SetClockPrescaler(0x3F);
// Switch alternative port
I2C_SetPort(I2C_AlterPort_P32_P33);
// Start I2C
I2C_SetEnabled(HAL_State_ON);
}
void GPIO_Init(void)
{
// SDA
GPIO_P3_SetMode(GPIO_Pin_3, GPIO_Mode_InOut_QBD);
// SCL
GPIO_P3_SetMode(GPIO_Pin_2, GPIO_Mode_Output_PP);
}
int main(void)
{
uint8_t offset, i, buf[20];
SYS_SetClock();
// UART1 configuration: baud 115200 with Timer2, 1T mode, no interrupt
UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200);
GPIO_Init();
I2C_Init();
// 与AT24C08示例的区别在于使用了16bit地址
I2C_Write16BitAddr(AT24C_ADDR, 0x0000, dat, 12);
while(1)
{
for (offset = 0; offset < 4; offset++)
{
// 与AT24C08示例的区别在于使用了16bit地址
I2C_Read16BitAddr(AT24C_ADDR, 0x0000|offset, buf, 6);
for (i = 0; i < 6; i++)
{
UART1_TxHex(buf[i]);
UART1_TxChar(':');
}
UART1_TxString(" ");
SYS_Delay(10);
}
UART1_TxString("\r\n");
SYS_Delay(1000);
}
}
|
代码地址