目录
- STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解)
- STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解)
- STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明
- STC8H开发(四): FwLib_STC8 封装库的介绍和使用注意事项
- STC8H开发(五): SPI驱动nRF24L01无线模块
- STC8H开发(六): SPI驱动ADXL345三轴加速度检测模块
- STC8H开发(七): I2C驱动MPU6050三轴加速度+三轴角速度检测模块
- STC8H开发(八): NRF24L01无线传输音频(对讲机原型)
- STC8H开发(九): STC8H8K64U模拟USB HID外设
- STC8H开发(十): SPI驱动Nokia5110 LCD(PCD8544)
- STC8H开发(十一): GPIO单线驱动多个DS18B20数字温度计
- STC8H开发(十二): I2C驱动AT24C08,AT24C32系列EEPROM存储
AT24C系列
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
- 从这个容量开始, 存储地址变成两个字节
- 设备地址 0xA0 - 0xAE, 第8位是R/W, 同一个I2C总线上可以并存8个同类设备
AT24C128, AT24C256, AT24C512
- 设备地址 0xA0 - 0xA6, 第5位固定为0, 第8位是R/W, 同一个I2C总线上可以并存4个同类设备
- 存储地址两个字节
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计算的, 在最初的调试阶段, 务必设置一个较大的预分频, 这样可以确保问题不出在频率过高上
接线
对于DIP8封装, 接线方式都是一样的, 测试使用的是 STC8H3K64S2, 可以直接替换为 STC8H 其它型号, 除了下面的4个pin, 还需要选择将A0, A1, A2 接GND或接VCC
P32 -> SCL
P33 -> SDA
GND -> GND
3.3V -> VCC
AT24C08访问示例
这个例子演示了单字节存储地址系列型号的访问方式
#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);
}
}
代码地址
- GitHub https://github.com/IOsetting/FwLib_STC8/blob/master/demo/i2c/at24c/at24c08_stc8h3k.c
- Gitee https://gitee.com/iosetting/fw-lib_-stc8/blob/master/demo/i2c/at24c/at24c08_stc8h3k.c
AT24C32访问示例
这个例子演示了双字节存储地址系列型号的访问方式
#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);
}
}
代码地址