1 24C02简介
24C02 是一个 2K bit 的串行 EEPROM 存储器,内部含有 256 个字节。在 24C02 里面还有
一个 8 字节的页写缓冲器。该设备的通信方式 IIC,通过其 SCL 和 SDA 与其他设备通信
上图的 WP 引脚是写保护引脚,接高电平只读,接地允许读和写,我们的板子设计是把该
引脚接地。每一个设备都有自己的设备地址,24C02 也不例外,但是 24C02 的设备地址是包括
不可编程部分和可编程部分,可编程部分是根据上图的硬件引脚 A0、A1 和 A2 所决定。设备
地址最后一位用于设置数据的传输方向,即读操作/写操作,0 是写操作,1 是读操作
2 24C02 读写时序图
写时序图
上图展示的主机向 24C02 写操作时序图,主机在 IIC 总线发送第 1 个字节的数据为 24C02
的设备地址 0xA0,用于寻找总线上找到 24C02,在获得 24C02 的应答信号之后,继续发送第
2 个字节数据,该字节数据是 24C02 的内存地址,再等到 24C02 的应答信号,主机继续发送
第 3 字节数据,这里的数据即是写入在第 2 字节内存地址的数据。主机完成写操作后,可以发
出停止信号,终止数据传输。
页写时序图
在单字节写时序时,每次写入数据时窦需要先写入设备的内存地址才能实现,在页写时序
中,只需要告诉 24C02 第一个内存地址 1,后面数据会按照顺序写入到内存地址 2,内存地址 3
等,大大节省了通信时间,提高了时效性。因为 24C02 每次只能写 8bit 数据,所以它的页大小
也就是 1 字节。页写时序的操作方式跟上面的单字节写时序差不多,所以不作过多解释了。参
考以上说明去理解页写时序。
读时序图
24C02 读取数据的过程是一个复合的时序,其中包含写时序和读时序。先看第一个通信过
程,这里是写时序,起始信号产生后,主机发送 24C02 设备地址 0xA0,获取从机应答信号后,
接着发送需要读取的内存地址;在读时序中,起始信号产生后,主机发送 24C02 设备地址 0xA1,
获取从机应答信号后,接着从机返回刚刚在写时序中内存地址的数据,以字节为单位传输在总
线上,假如主机获取数据后返回的是应答信号,那么从机会一直传输数据,当主机发出的是非
应答信号并以停止信号发出为结束,从机就会结束传输。
3示例代码
myiic.h
#ifndef _24C02_H
#define _24C02_H
#include "myiic.h"
#define AT24C02 255
void at24c02_init(void); /* 初始化IIC */
uint8_t at24c02_read_byte(uint8_t addr); /* 指定地址读取一个字节 */
void at24c02_write_byte(uint8_t addr,uint8_t data); /* 指定地址写入一个字节 */
void at24c02_read( uint8_t addr,uint8_t *pbuf, uint8_t datalen); /* 从指定地址开始读出指定长度的数据 */
void at24c02_write(uint8_t addr,uint8_t *pbuf, uint8_t datalen); /* 从指定地址开始写入指定长度的数据 */
uint8_t at24c02_check(void); /* 检查器件 */
#endif
24c02.c
#include "24c02.h"
/**
* @brief 初始化IIC接口
* @param 无
* @retval 无
*/
void at24c02_init(void)
{
iic_init();
}
/**
* @brief 在AT24C02指定地址读出一个数据
* @param readaddr: 开始读数的地址
* @retval 读到的数据
*/
uint8_t at24c02_read_byte(uint8_t addr)
{
uint8_t temp=0;
/* 1 发送起始信号 */
iic_start(); /* 发送IIC开始信号 */
/* 2 发送设备地址 写 */
iic_send_byte(0xA0); /* IIC发送一个字节 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
/* 3 发送内存地址 */
iic_send_byte(addr); /* IIC发送一个字节 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
/* 4 发送起始信号 */
iic_start(); /* 发送IIC开始信号 */
/* 5 发送设备地址 读 */
iic_send_byte(0xA1); /* IIC发送一个字节 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
/* 6 接收数据 主机发nack*/
temp=iic_read_byte(0); /* IIC读取一个字节 */
/* 7 停止*/
iic_stop(); /* 发送IIC停止信号 */
return temp;
}
/**
* @brief 在AT24C02指定地址写入一个数据
* @param addr: 写入数据的目的地址
* @param data: 要写入的数据
* @retval 无
*/
void at24c02_write_byte(uint8_t addr,uint8_t data)
{
/* 1 发送起始信号 */
iic_start(); /* 发送IIC开始信号 */
/* 2 发送设备地址 写 */
iic_send_byte(0xA0); /* IIC发送一个字节 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
/* 3 发送内存地址 */
iic_send_byte(addr); /* IIC发送一个字节 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
/* 4 发送数据 */
iic_send_byte(data); /* IIC发送一个字节 */
iic_wait_ack(); /* 每次发送完一个字节,都要等待ACK */
/* 5 停止 */
iic_stop(); /* 发送IIC停止信号 */
delay_ms(10);/* 注意: EEPROM 写入比较慢,必须等到10ms后再写下一个字节 */
}
/**
* @brief 在AT24C02里面的指定地址开始读出指定个数的数据
* @param addr : 开始读出的地址 对24c02为0~255
* @param pbuf : 数据数组首地址
* @param datalen : 要读出数据的个数
* @retval 无
*/
void at24c02_read( uint8_t addr,uint8_t *pbuf, uint8_t datalen)
{
while(datalen--)
{
*pbuf++=at24c02_read_byte(addr++);
}
}
/**
* @brief 在AT24C02里面的指定地址开始写入指定个数的数据
* @param addr : 开始写入的地址 对24c02为0~255
* @param pbuf : 数据数组首地址
* @param datalen : 要写入数据的个数
* @retval 无
*/
void at24c02_write(uint8_t addr,uint8_t *pbuf, uint8_t datalen)
{
while(datalen--)
{
at24c02_write_byte(addr,*pbuf);
addr++;
pbuf++;
}
}
/**
* @brief 检查AT24C02是否正常
* @note 检测原理: 在器件的末地址写如0X55, 然后再读取, 如果读取值为0X55
* 则表示检测正常. 否则,则表示检测失败.
*
* @param 无
* @retval 检测结果
* 0: 检测成功
* 1: 检测失败
*/
uint8_t at24c02_check(void)
{
uint8_t addr;
uint8_t temp;
addr = AT24C02;
temp=at24c02_read_byte(addr);
if(temp==0x55)
{
return 0;
}
else
{
at24c02_write_byte(addr,0x55);
temp=at24c02_read_byte(addr);
if(temp==0x55)
{
return 0;
}
}
return 1;
}
main.c
#include "24c02.h"
int main(void)
{
uint8_t len;
uint16_t times = 0;
uint8_t rec_data=0;
uint8_t at24c02_chk=0;
HAL_Init(); /* HAL库初始化 */
HAL_ICACHE_Enable(); /* 使能指令缓存 */
sys_stm32_clock_init(250, 4, 2, 2); /* 系统时钟初始化, 250Mhz */
delay_init(250); /* 延时初始化 */
usart_init(115200); /* 串口初始化 */
led_init(); /* LED初始化 */
at24c02_init(); /* 24c02初始化 */
printf("at24c02 init Ok !\r\n");
while(1)
{
at24c02_chk=at24c02_check();
if(at24c02_chk==0)
{
printf("at24c02 Check Ok !\r\n");
}
else
{
printf("at24c02 Check Failed !\r\n");
}
at24c02_write_byte(10,100);/* 指定地址写入一个字节 */
printf("at24c02 write addr 10 data 100 !\r\n");
delay_ms(500);
rec_data =at24c02_read_byte(10);/* 指定地址读取一个字节 */
printf("at24c02 read addr 10 data %d\r\n",rec_data);
delay_ms(500);
LED0_TOGGLE();
}
}