一、AT24CXXX容量

  AT24C01,AT24C02,AT24C04,AT24C08,AT24C16,AT24C32,AT24C64,AT24C128,AT24C256…不同的xxx代表不同的容量。

AT24CXXX bit容量 Byte容量
AT24C01 1Kbit 128Byte
AT24C02 2Kbit 256Byte
AT24C04 4Kbit 512Byte
AT24C08 8Kbit 1024Byte
AT24C16 16Kbit 2048Byte
AT24C32 32Kbit 4096Byte
AT24C64 64Kbit 8192Byte
AT24C128 128Kbit 16384Byte
AT24C256 256Kbit 32768Byte
AT24C512 512Kbit 65536Byte

二、AT24CXXX页与页内单元

  总容量(Byte容量) = 页数 × 页内字节单元数。

AT24CXXX Byte容量 页数 页内字节单元数
AT24C01 128Byte 16页 8Byte
AT24C02 256Byte 32页 8Byte
AT24C04 512Byte 32页 16Byte
AT24C08 1024Byte 64页 16Byte
AT24C16 2048Byte 128页 16Byte
AT24C32 4096Byte 128页 32Byte
AT24C64 8192Byte 256页 32Byte
AT24C128 16384Byte 256页 64Byte
AT24C256 32768Byte 512页 64Byte
AT24C512 65536Byte 512页 128Byte

三、AT24CXXXX寻址方式(不是IIC地址,是存储器内部寻址)

  对AT24CXXX进行读写操作时,都得先访问存储地址、比如AT24C01写一个字节的IIC时序:

  先发送设备地址,收到应答后再发送需要写数据的地址(WORD ADDRESS)。AT24C01容量为128Byte则WORD ADDRESS只需要7bit就可以覆盖128Byte的数据地址。通俗的讲就是128Byte就占用了128个地址,一个7bit的数据范围为(0-127)刚好128,所以128Byte的字节地址需要一个7bit的数据来表示。
AT24CXXX 字节地址如下(*表示无效位):

AT24CXXX 容量(Byte) WORD ADDRESS(占用bit数) WORD ADDRESS
AT24C01 128Byte 7bit
AT24C02 256Byte 8bit
AT24C04 512Byte 9bit
AT24C08 1024Byte 10bit
AT24C16 2048Byte 11bit
AT24C32 4096Byte 12bit
AT24C64 8192Byte 13bit
AT24C128 16384Byte 14bit
AT24C256 32768Byte 15bit
AT24C512 65536Byte 16bit

四、AT24CXXX页地址与页内单元地址

  比如AT24C256有512页每页64个字节,15bit的地址数据对其寻址,低6bit(D5-D0)为页内字节单元地址,高9bit(D14-D6)为页地址。

如第16页开始写,则WORD ADDRESS = 0x0400(0000 0100 0000 0000)
0:地址无效位
000 0100 00:9位页地址
00 0000:6位页内字节单元地址
下表如AT24C01
16页:需要4bit寻址(2^4=16)
8Byte:需要3bit寻址(2^3=8)

AT24CXXX Byte容量 页数 页内字节单元数 页地址 页内偏移地址
AT24C01 128Byte 16页 8Byte
AT24C02 256Byte 32页 8Byte
AT24C04 512Byte 32页 16Byte
AT24C08 1024Byte 64页 16Byte
AT24C16 2048Byte 128页 16Byte
AT24C32 4096Byte 128页 32Byte
AT24C64 8192Byte 256页 32Byte
AT24C128 16384Byte 256页 64Byte
AT24C256 32768Byte 512页 64Byte
AT24C512 65536Byte 512页 128Byte

查看手册
AT24C01字节寻址需一个7bit地址:

AT24C128字节寻址需一个14bit地址:

以此类推,其实就是上面总结的那张表。

五、AT24CXXX IIC地址

  IIC通信需要先向从设备发送设备地址,AT24CXXX芯片上有A2、A1、A0引脚,通过这三个引脚我们就可以自定义AT24CXXX芯片的通信地址。

地址构成如下(手册上都会有写),比如A2、A1、A0接地,则IIC写地址为1010 0000(0xA0),读地址为1010 0001(0xA1),有关IIC地址详情请看IIC协议详解

六、AT24CXXX 数据的读写

AT24C256为例

1、字节写

2、按页写


★★★注意:
  往AT24CXXX中写数据时,每写一个Byte的数据页内地址+1,当前页写满后会重新覆盖掉这一页前面的数据,而不会自动跳转到下一页,但是读会自动翻页。
具体看手册:

3、如何翻页写

  按页写其实就是执行一次下面的时序,也就是发送一次从机设备和字节地址最大就可以写入64字节的数据,如果要连写多页,就重新按照以下时序发送从机地址和字节地址等。

4、读

有以下模式,和写差不多

七、源程序

 1、i2c_gpio.h

#ifndef _BSP_I2C_GPIO_H
#define _BSP_I2C_GPIO_H#include "stm32f4xx.h"#define I2C_WR   0       // 写控制bit
#define I2C_RD  1       // 读控制bitvoid BSP_AT24CXX_InitI2C(void);
void i2c_Start(void);
void i2c_Stop(void);
void i2c_SendByte(uint8_t _ucByte);
uint8_t i2c_ReadByte(void);
uint8_t i2c_WaitAck(void);
void i2c_Ack(void);
void i2c_NAck(void);
uint8_t i2c_CheckDevice(uint8_t _Address);#endif

2、i2c_ee.h

#ifndef __I2C_EE_H
#define __I2C_EE_H#include "stm32f4xx.h"/* * AT24C02 2kb = 2048bit = 2048/8 B = 256 B* 32 pages of 8 bytes each** Device Address* 1 0 1 0 A2 A1 A0 R/W* 1 0 1 0 0  0  0  0 = 0xA0* 1 0 1 0 0  0  0  1 = 0xA1 *//* AT24C01/02每页有8个字节 * AT24C04/08A/16A每页有16个字节 、*/#define AT24C512#ifdef AT24C01#define EE_MODEL_NAME     "AT24C01"#define EE_DEV_ADDR          0xA0        /* 设备地址 */#define EE_PAGE_SIZE      8           /* 页面大小(字节) */#define EE_SIZE               128         /* 总容量(字节) */#define EE_ADDR_BYTES      1           /* 地址字节个数 */#define EE_ADDR_A8          0           /* 地址字节的高8bit不在首字节 */
#endif#ifdef AT24C02#define EE_MODEL_NAME       "AT24C02"#define EE_DEV_ADDR          0xA0        /* 设备地址 */#define EE_PAGE_SIZE      8           /* 页面大小(字节) */#define EE_SIZE               256         /* 总容量(字节) */#define EE_ADDR_BYTES      1           /* 地址字节个数 */#define EE_ADDR_A8          0           /* 地址字节的高8bit不在首字节 */
#endif#ifdef AT24C04#define EE_MODEL_NAME       "AT24C04"#define EE_DEV_ADDR          0xA0        /* 设备地址 */#define EE_PAGE_SIZE      8           /* 页面大小(字节) */#define EE_SIZE               512         /* 总容量(字节) */#define EE_ADDR_BYTES      1           /* 地址字节个数 */#define EE_ADDR_A8          1           /* 地址字节的高8bit在首字节 */
#endif#ifdef AT24C08#define EE_MODEL_NAME       "AT24C08"#define EE_DEV_ADDR          0xA0        /* 设备地址 */#define EE_PAGE_SIZE      16          /* 页面大小(字节) */#define EE_SIZE               (16*64)     /* 总容量(字节) */#define EE_ADDR_BYTES      2           /* 地址字节个数 */#define EE_ADDR_A8          1           /* 地址字节的高8bit在首字节 */
#endif#ifdef AT24C16#define EE_MODEL_NAME       "AT24C16"#define EE_DEV_ADDR          0xA0        /* 设备地址 */#define EE_PAGE_SIZE      16          /* 页面大小(字节) */#define EE_SIZE               (128*16)    /* 总容量(字节) */#define EE_ADDR_BYTES      2           /* 地址字节个数 */#define EE_ADDR_A8          1           /* 地址字节的高8bit在首字节 */
#endif#ifdef AT24C32#define EE_MODEL_NAME       "AT24C32"#define EE_DEV_ADDR          0xA0        /* 设备地址 */#define EE_PAGE_SIZE      32          /* 页面大小(字节) */#define EE_SIZE               (128*32)    /* 总容量(字节) */#define EE_ADDR_BYTES      2           /* 地址字节个数 */#define EE_ADDR_A8          1           /* 地址字节的高8bit在首字节 */
#endif#ifdef AT24C64#define EE_MODEL_NAME       "AT24C64"#define EE_DEV_ADDR          0xA0        /* 设备地址 */#define EE_PAGE_SIZE      32          /* 页面大小(字节) */#define EE_SIZE               (256*32)    /* 总容量(字节) */#define EE_ADDR_BYTES      2           /* 地址字节个数 */#define EE_ADDR_A8          1           /* 地址字节的高8bit在首字节 */
#endif#ifdef AT24C128#define EE_MODEL_NAME      "AT24C128"#define EE_DEV_ADDR         0xA0        /* 设备地址 */#define EE_PAGE_SIZE      64          /* 页面大小(字节) */#define EE_SIZE               (256*64)    /* 总容量(字节) */#define EE_ADDR_BYTES      2           /* 地址字节个数 */#define EE_ADDR_A8          0           /* 地址字节的高8bit不在首字节 */
#endif#ifdef AT24C256#define EE_MODEL_NAME      "AT24C256"#define EE_DEV_ADDR         0xA0        /* 设备地址 */#define EE_PAGE_SIZE      64          /* 页面大小(字节) */#define EE_SIZE               (512*64)    /* 总容量(字节) */#define EE_ADDR_BYTES      2           /* 地址字节个数 */#define EE_ADDR_A8          0           /* 地址字节的高8bit不在首字节 */
#endif#ifdef AT24C512#define EE_MODEL_NAME      "AT24C512"#define EE_DEV_ADDR         0xA0        /* 设备地址 */#define EE_PAGE_SIZE      128         /* 页面大小(字节) */#define EE_SIZE               (512*128)   /* 总容量(字节) */#define EE_ADDR_BYTES      2           /* 地址字节个数 */#define EE_ADDR_A8          0           /* 地址字节的高8bit不在首字节 */
#endif#endif /* __I2C_EE_H */

3、i2c_gpio.c

*
*********************************************************************************************************
*
*   模块名称 : I2C总线驱动模块
*   文件名称 : bsp_i2c_gpio.c
*   版    本 : V1.0
*   说    明 : 用gpio模拟i2c总线, 适用于STM32F4系列CPU。该模块不包括应用层命令帧,仅包括I2C总线基本操作函数。
*
*   修改记录 :
*       版本号  日期        作者     说明
*       V1.0    2013-02-01 armfly  正式发布
*
*   Copyright (C), 2013-2014, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*//*应用说明:在访问I2C设备前,请先调用 i2c_CheckDevice() 检测I2C设备是否正常,该函数会配置GPIO
*/#include "stm32f4xx.h"
#include "i2c_gpio.h"#define RCC_AT24CXX_I2C_PORT             RCC_AHB1Periph_GPIOB        // GPIO端口时钟
#define GPIO_AT24CXX_I2C_PORT           GPIOB                       // GPIO端口
#define GPIO_AT24CXX_I2C_SCL_Pin        GPIO_Pin_6                  // 连接到SCL时钟线的GPIO
#define GPIO_AT24CXX_I2C_SDA_Pin        GPIO_Pin_7                  // 连接到SDA数据线的GPIO#define I2C_SCL_1()    GPIO_SetBits(GPIO_AT24CXX_I2C_PORT, GPIO_AT24CXX_I2C_SCL_Pin)           // SCL = 1
#define I2C_SCL_0()     GPIO_ResetBits(GPIO_AT24CXX_I2C_PORT, GPIO_AT24CXX_I2C_SCL_Pin)         // SCL = 0
#define I2C_SDA_1()     GPIO_SetBits(GPIO_AT24CXX_I2C_PORT, GPIO_AT24CXX_I2C_SDA_Pin)           // SDA = 1
#define I2C_SDA_0()     GPIO_ResetBits(GPIO_AT24CXX_I2C_PORT, GPIO_AT24CXX_I2C_SDA_Pin)         // SDA = 0
#define I2C_SDA_READ()  GPIO_ReadInputDataBit(GPIO_AT24CXX_I2C_PORT, GPIO_AT24CXX_I2C_SDA_Pin)              // 读SDA口线状态
#define I2C_SCL_READ()  GPIO_ReadInputDataBit(GPIO_AT24CXX_I2C_PORT, GPIO_AT24CXX_I2C_SCL_Pin)              // 读SCL口线状态/*
*********************************************************************************************************
*   函 数 名: bsp_InitI2C
*   功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现
*   形    参:  无
*   返 回 值: 无
*********************************************************************************************************
*/
void BSP_AT24CXX_InitI2C(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AT24CXX_I2C_PORT , ENABLE); /* 打开GPIO时钟 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;        /* 设为输出口 */GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;      /* 设为开漏模式 */GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;   /* 上下拉电阻不使能 */GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;    /* IO口最大速度 */GPIO_InitStructure.GPIO_Pin = GPIO_AT24CXX_I2C_SCL_Pin | GPIO_AT24CXX_I2C_SDA_Pin;GPIO_Init(GPIO_AT24CXX_I2C_PORT, &GPIO_InitStructure);/* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */i2c_Stop();
}/*
*********************************************************************************************************
*   函 数 名: i2c_Delay
*   功能说明: I2C总线位延迟,最快400KHz
*   形    参:  无
*   返 回 值: 无
*********************************************************************************************************
*/
static void i2c_Delay(void)
{uint8_t i;/* CPU主频168MHz时,在内部Flash运行, MDK工程不优化。用台式示波器观测波形。循环次数为5时,SCL频率 = 1.78MHz (读耗时: 92ms, 读写正常,但是用示波器探头碰上就读写失败。时序接近临界)循环次数为10时,SCL频率 = 1.1MHz (读耗时: 138ms, 读速度: 118724B/s)循环次数为30时,SCL频率 = 440KHz, SCL高电平时间1.0us,SCL低电平时间1.2us上拉电阻选择2.2K欧时,SCL上升沿时间约0.5us,如果选4.7K欧,则上升沿约1us实际应用选择400KHz左右的速率即可*/for (i = 0; i < 30; i++){__NOP();__NOP();}
}/*
*********************************************************************************************************
*   函 数 名: i2c_Start
*   功能说明: CPU发起I2C总线启动信号
*   形    参:  无
*   返 回 值: 无
*********************************************************************************************************
*/
void i2c_Start(void)
{/* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */I2C_SDA_1();I2C_SCL_1();i2c_Delay();I2C_SDA_0();i2c_Delay();I2C_SCL_0();i2c_Delay();
}/*
*********************************************************************************************************
*   函 数 名: i2c_Start
*   功能说明: CPU发起I2C总线停止信号
*   形    参:  无
*   返 回 值: 无
*********************************************************************************************************
*/
void i2c_Stop(void)
{/* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */I2C_SDA_0();I2C_SCL_1();i2c_Delay();I2C_SDA_1();i2c_Delay();
}/*
*********************************************************************************************************
*   函 数 名: i2c_SendByte
*   功能说明: CPU向I2C总线设备发送8bit数据
*   形    参:  _ucByte : 等待发送的字节
*   返 回 值: 无
*********************************************************************************************************
*/
void i2c_SendByte(uint8_t _ucByte)
{uint8_t i;/* 先发送字节的高位bit7 */for (i = 0; i < 8; i++){if (_ucByte & 0x80){I2C_SDA_1();}else{I2C_SDA_0();}i2c_Delay();I2C_SCL_1();i2c_Delay();I2C_SCL_0();if (i == 7){I2C_SDA_1(); // 释放总线}_ucByte <<= 1;  /* 左移一个bit */i2c_Delay();}
}/*
*********************************************************************************************************
*   函 数 名: i2c_ReadByte
*   功能说明: CPU从I2C总线设备读取8bit数据
*   形    参:  无
*   返 回 值: 读到的数据
*********************************************************************************************************
*/
uint8_t i2c_ReadByte(void)
{uint8_t i;uint8_t value;/* 读到第1个bit为数据的bit7 */value = 0;for (i = 0; i < 8; i++){value <<= 1;I2C_SCL_1();i2c_Delay();if (I2C_SDA_READ()){value++;}I2C_SCL_0();i2c_Delay();}return value;
}/*
*********************************************************************************************************
*   函 数 名: i2c_WaitAck
*   功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
*   形    参:  无
*   返 回 值: 返回0表示正确应答,1表示无器件响应
*********************************************************************************************************
*/
uint8_t i2c_WaitAck(void)
{uint8_t re;I2C_SDA_1();    /* CPU释放SDA总线 */i2c_Delay();I2C_SCL_1();    /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */i2c_Delay();if (I2C_SDA_READ())    /* CPU读取SDA口线状态 */{re = 1;}else{re = 0;}I2C_SCL_0();i2c_Delay();return re;
}/*
*********************************************************************************************************
*   函 数 名: i2c_Ack
*   功能说明: CPU产生一个ACK信号
*   形    参:  无
*   返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{I2C_SDA_0();   /* CPU驱动SDA = 0 */i2c_Delay();I2C_SCL_1(); /* CPU产生1个时钟 */i2c_Delay();I2C_SCL_0();i2c_Delay();I2C_SDA_1(); /* CPU释放SDA总线 */
}/*
*********************************************************************************************************
*   函 数 名: i2c_NAck
*   功能说明: CPU产生1个NACK信号
*   形    参:  无
*   返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{I2C_SDA_1();   /* CPU驱动SDA = 1 */i2c_Delay();I2C_SCL_1(); /* CPU产生1个时钟 */i2c_Delay();I2C_SCL_0();i2c_Delay();
}/*
*********************************************************************************************************
*   函 数 名: i2c_CheckDevice
*   功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
*   形    参:  _Address:设备的I2C总线地址
*   返 回 值: 返回值 0 表示正确, 返回1表示未探测到
*********************************************************************************************************
*/
uint8_t i2c_CheckDevice(uint8_t _Address)
{uint8_t ucAck;if (I2C_SDA_READ() && I2C_SCL_READ()){i2c_Start();       /* 发送启动信号 *//* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 */i2c_SendByte(_Address | I2C_WR);ucAck = i2c_WaitAck();  /* 检测设备的ACK应答 */i2c_Stop();         /* 发送停止信号 */return ucAck;}return 1; /* I2C总线异常 */
}

4、i2c_ee.c

/*
*********************************************************************************************************
*
*   模块名称 : 串行EEPROM 24xx驱动模块
*   文件名称 : bsp_eeprom_24xx.c
*   版    本 : V1.0
*   说    明 : 实现24xx系列EEPROM的读写操作。写操作采用页写模式提高写入效率。
*
*   修改记录 :
*       版本号  日期        作者     说明
*       V1.0    2013-02-01 armfly  正式发布
*
*   Copyright (C), 2013-2014, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*//*应用说明:访问串行EEPROM前,请先调用一次 bsp_InitI2C()函数配置好I2C相关的GPIO.
*/#include "i2c_gpio.h"
#include "i2c_ee.h"/*
*********************************************************************************************************
*   函 数 名: ee_CheckOk
*   功能说明: 判断串行EERPOM是否正常
*   形    参:  无
*   返 回 值: 1 表示正常, 0 表示不正常
*********************************************************************************************************
*/
uint8_t ee_CheckOk(void)
{if (i2c_CheckDevice(EE_DEV_ADDR) == 0){return 1;}else{/* 失败后,切记发送I2C总线停止信号 */i2c_Stop();return 0;}
}/*
*********************************************************************************************************
*   函 数 名: ee_ReadBytes
*   功能说明: 从串行EEPROM指定地址处开始读取若干数据
*   形    参:  _usAddress : 起始地址
*            _usSize : 数据长度,单位为字节
*            _pReadBuf : 存放读到的数据的缓冲区指针
*   返 回 值: 0 表示失败,1表示成功
*********************************************************************************************************
*/
uint8_t ee_ReadBytes(uint8_t *_pReadBuf, uint16_t _usAddress, uint16_t _usSize)
{uint16_t i;/* 采用串行EEPROM随即读取指令序列,连续读取若干字节 *//* 第1步:发起I2C总线启动信号 */i2c_Start();/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */#if EE_ADDR_A8 == 1i2c_SendByte(EE_DEV_ADDR | I2C_WR | ((_usAddress >> 7) & 0x0E));    /* 此处是写指令 */#elsei2c_SendByte(EE_DEV_ADDR | I2C_WR);    /* 此处是写指令 */#endif/* 第3步:发送ACK */if (i2c_WaitAck() != 0){goto cmd_fail; /* EEPROM器件无应答 */}/* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */if (EE_ADDR_BYTES == 1){i2c_SendByte((uint8_t)_usAddress);if (i2c_WaitAck() != 0){goto cmd_fail; /* EEPROM器件无应答 */}}else{i2c_SendByte(_usAddress >> 8);if (i2c_WaitAck() != 0){goto cmd_fail; /* EEPROM器件无应答 */}i2c_SendByte(_usAddress);if (i2c_WaitAck() != 0){goto cmd_fail;  /* EEPROM器件无应答 */}}/* 第6步:重新启动I2C总线。下面开始读取数据 */i2c_Start();/* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */#if EE_ADDR_A8 == 1i2c_SendByte(EE_DEV_ADDR | I2C_RD | ((_usAddress >> 7) & 0x0E));  /* 此处是写指令 */#else       i2c_SendByte(EE_DEV_ADDR | I2C_RD); /* 此处是写指令 */#endif  /* 第8步:发送ACK */if (i2c_WaitAck() != 0){goto cmd_fail;   /* EEPROM器件无应答 */}/* 第9步:循环读取数据 */for (i = 0; i < _usSize; i++){_pReadBuf[i] = i2c_ReadByte();    /* 读1个字节 *//* 每读完1个字节后,需要发送Ack, 最后一个字节不需要Ack,发Nack */if (i != _usSize - 1){i2c_Ack(); /* 中间字节读完后,CPU产生ACK信号(驱动SDA = 0) */}else{i2c_NAck();    /* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */}}/* 发送I2C总线停止信号 */i2c_Stop();return 1;   /* 执行成功 */cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 *//* 发送I2C总线停止信号 */i2c_Stop();return 0;
}/*
*********************************************************************************************************
*   函 数 名: ee_WriteBytes
*   功能说明: 向串行EEPROM指定地址写入若干数据,采用页写操作提高写入效率
*   形    参:  _usAddress : 起始地址
*            _usSize : 数据长度,单位为字节
*            _pWriteBuf : 存放读到的数据的缓冲区指针
*   返 回 值: 0 表示失败,1表示成功
*********************************************************************************************************
*/
uint8_t ee_WriteBytes(uint8_t *_pWriteBuf, uint16_t _usAddress, uint16_t _usSize)
{uint16_t i,m;uint16_t usAddr;/*写串行EEPROM不像读操作可以连续读取很多字节,每次写操作只能在同一个page。对于24xx02,page size = 8简单的处理方法为:按字节写操作模式,每写1个字节,都发送地址为了提高连续写的效率: 本函数采用page wirte操作。*/usAddr = _usAddress;for (i = 0; i < _usSize; i++){/* 当发送第1个字节或是页面首地址时,需要重新发起启动信号和地址 */if ((i == 0) || (usAddr & (EE_PAGE_SIZE - 1)) == 0){/* 第0步:发停止信号,启动内部写操作 */i2c_Stop();/* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10msCLK频率为200KHz时,查询次数为30次左右*/for (m = 0; m < 1000; m++){/* 第1步:发起I2C总线启动信号 */i2c_Start();/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */#if EE_ADDR_A8 == 1i2c_SendByte(EE_DEV_ADDR | I2C_WR | ((_usAddress >> 7) & 0x0E));  /* 此处是写指令 */#else               i2c_SendByte(EE_DEV_ADDR | I2C_WR);#endif/* 第3步:发送一个时钟,判断器件是否正确应答 */if (i2c_WaitAck() == 0){break;}}if (m  == 1000){goto cmd_fail;    /* EEPROM器件写超时 */}/* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */if (EE_ADDR_BYTES == 1){i2c_SendByte((uint8_t)usAddr);if (i2c_WaitAck() != 0){goto cmd_fail; /* EEPROM器件无应答 */}}else{i2c_SendByte(usAddr >> 8);if (i2c_WaitAck() != 0){goto cmd_fail; /* EEPROM器件无应答 */}i2c_SendByte(usAddr);if (i2c_WaitAck() != 0){goto cmd_fail;  /* EEPROM器件无应答 */}}}/* 第6步:开始写入数据 */i2c_SendByte(_pWriteBuf[i]);/* 第7步:发送ACK */if (i2c_WaitAck() != 0){goto cmd_fail;    /* EEPROM器件无应答 */}usAddr++;   /* 地址增1 */}/* 命令执行成功,发送I2C总线停止信号 */i2c_Stop();/* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10msCLK频率为200KHz时,查询次数为30次左右*/for (m = 0; m < 1000; m++){/* 第1步:发起I2C总线启动信号 */i2c_Start();/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */    #if EE_ADDR_A8 == 1i2c_SendByte(EE_DEV_ADDR | I2C_WR | ((_usAddress >> 7) & 0x0E)); /* 此处是写指令 */#else       i2c_SendByte(EE_DEV_ADDR | I2C_WR); /* 此处是写指令 */#endif/* 第3步:发送一个时钟,判断器件是否正确应答 */if (i2c_WaitAck() == 0){break;}}if (m  == 1000){goto cmd_fail;   /* EEPROM器件写超时 */}/* 命令执行成功,发送I2C总线停止信号 */i2c_Stop();    return 1;cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 *//* 发送I2C总线停止信号 */i2c_Stop();return 0;
}

八、测试

下面以AT24C512为例,进行测试,测试以下功能:

1、任意地址连续跨页读多页数据

2、任意地址连续跨页写多页数据

注意:如果需要测试AT24C512,需要在i2c_ee.h中定义宏定义 AT24C512,告诉单片机目前的芯片是AT24C512芯片。

#define AT24C512

注意:如果需要测试AT24C128,需要在i2c_ee.h中定义宏定义 AT24C128,告诉单片机目前的芯片是AT24C128芯片.

#define AT24C128

为便于观察数据读写的每一个字节都是否正确,初始化数组时,将test_array1[0---127] 初始化数值 = 1---128

test_array1[128---255] 初始化数值 = 1---128

test_array1[256---383] 初始化数值 = 1---128

下面的测试程序先将存储在数组test_array1中的连续3页数据写到起始地址为80的芯片中。然后将起始地址为80的芯片中的数据读到数组test_array2.

main.c

    #include "i2c_gpio.h"#include "i2c_ee.h"uint8_t test_array1[3*EE_PAGE_SIZE];   //注:AT24C512时,EE_PAGE_SIZE=128uint8_t test_array2[3*EE_PAGE_SIZE];   //    AT24C512时,一个页面有128个字节 void DEBUG_test_AT24C512(void){uint16_t i;uint16_t j;for (i=0;i<3*EE_PAGE_SIZE;i++){if (i>=256)j=i-256;            //test_array1[256---383] 单元初始化数值 = 1---128else if (i>=128)j=i-128;            //test_array1[128---255] 单元初始化数值 = 1---128elsej=i;              //test_array1[0---127] 单元初始化数值 = 1---128test_array1[i]=j+1;}memset(test_array2,0x00,3*EE_PAGE_SIZE);  if (ee_CheckOk() == 1)   //如果检测到I2C器件存在{ee_WriteBytes(test_array1,80,3*EE_PAGE_SIZE);  //从I2C的地址80处开始写3页字节(测试跨页连续写)ee_ReadBytes(test_array2,80,3*EE_PAGE_SIZE); //从I2C的地址80处开始读3页字节(测试跨页连续读)}}int main(void)
{BSP_AT24CXX_InitI2C();DEBUG_test_AT24C512();while (1){}
}

九、测试结果

可以观察到先将3页数据(共计128*3=384个字节) 写到AT24C512起始地址80处,然后再次读出,数据完全正确。

STM32F407单片机通用24CXXX读写程序(KEIL),兼容24C系列存储器(24C01到24C512),支持存储器任意地址跨页连续读写多个页相关推荐

  1. 【51单片机快速入门指南】4.1: I2C 与 AT24C02 (EEPROM) 的跨页连续读写

    目录 硬知识 AT24Cxx 介绍 引脚排列 引脚说明 存储结构 器件寻址 器件操作 待机模式 存储复位 写操作 字节写 页写 应答查询 读操作 当前地址读 随机读 顺序读 示例程序 24C02.c ...

  2. 单片机编程php,STC单片机内部FLASH读写程序(最新整理)

    <STC单片机内部FLASH读写程序(最新整理)>由会员分享,可在线阅读,更多相关<STC单片机内部FLASH读写程序(最新整理)(6页珍藏版)>请在人人文库网上搜索. 1.S ...

  3. 24c512 c语言程序,24C32~24C512的51单片机读写程序

    24C32~24C512的51单片机读写程序 来源:-- 作者:-- 浏览:3875 时间:2016-08-10 14:18 标签: 摘要: AT89S52 晶振频率为11.0592MHz 指令周期: ...

  4. 【制作】基于金沙滩51单片机的电子密码锁程序

    基于金沙滩51单片机的电子密码锁程序 很久之前做的一个课设,在B站发了效果视频,发现忘记分享代码了,现在整理分享一下. 零.设计报告 1.设计要求 这部分是讲的整个系统实现了什么功能. 1.1.密码的 ...

  5. 给单片机焼写程序需要什么东西_单片机怎么烧写程序

    1.单片机怎么烧写程序 STC系列单片机为例:首先,需要安装keil软件和STC_ISP程序下载软件.先对你想要实现对单片机的功能用keil编程,然后用STC_ISP下载软件下载到单片机上,最后打开给 ...

  6. AT24C02读写程序

    AT24C02读写程序 单片机:STM32F030F4 编辑环境:keil+stm32cubemx6.6.1 一.硬件配置 二.程序编辑 1.头文件 /********************** A ...

  7. c语言中读取flash值的作用,flash读写程序

    原标题:flash读写程序 在电子工程世界为您找到如下关于"flash读写程序"的新闻 msp430F149单片机的flash读写程序 //基于msp430F149单片机的flas ...

  8. Keil MDK STM32系列(九) 基于HAL和FatFs的FAT格式SD卡TF卡读写

    Keil MDK STM32系列 Keil MDK STM32系列(一) 基于标准外设库SPL的STM32F103开发 Keil MDK STM32系列(二) 基于标准外设库SPL的STM32F401 ...

  9. LPS25HB 寄存器读写程序解读

    文章目录 LPS25HB 寄存器读写程序解读 1.读写功能的统一接口函数 2.设计结构体函数指针来调用统一的读写函数 3.与通信方式无关的寄存器读写抽象函数接口 LPS25HB 寄存器读写程序解读 一 ...

最新文章

  1. 网络技术等级考试知识点
  2. python求同构数_用c语言求1到1000的同构数_后端开发
  3. 除去WebView默认存在的一定像素的边距问题
  4. 电脑键盘灯怎么打开_电脑开机后黑屏键盘灯也不亮,教你一招搞定 建议收藏...
  5. 计算机导论中如何求模,计算机导论作业答案
  6. snipaste如何滚动截图_试用了20个截图工具,我写下这份超全的软件指南
  7. Freenom 申请免费域名(二)
  8. linux无线蓝牙鼠标失效,无线蓝牙鼠标失灵怎么办 无线蓝牙鼠标失灵解决方法【详解】...
  9. nginx安装 打开php文件自动下载的问题
  10. 删除计算机用户时拒绝访问权限,如果打印机拒绝访问并且无法删除设备怎么办...
  11. 微信小程序登陆(两种写法)
  12. 看一点逻辑学,试图理解一点真相
  13. Google Chrome企业咨询服务市场调研报告- 行业发展机遇、市场定位及主要驱动因素
  14. 简述线性和非线性电路及其区别
  15. php 2个数组并集,php中数组的并集、交集和差集函数介绍_PHP教程
  16. Cesium 概述 (一)
  17. hp linux 禁用u盘启动项,BIOS关闭Secure Boot(安全启动)方法大全(联想,华硕,DELL,HP等品牌)...
  18. Mega软件操作教程
  19. ffmpeg视频特效
  20. 白鹭引擎开发微信小游戏进阶教程文档

热门文章

  1. XCTF---MISC---Time_losing
  2. Windows XP SP3上安装IE7浏览器
  3. BUG-索引超出范围
  4. WSL 双系统端口映射,网络穿透最新教程
  5. 实验室信息化建设的基本内容
  6. java面向对象编程的思想_java面向对象编程思想的理解
  7. php将手机号转换成QQ号,教你如何更改qq号码?
  8. 信息不对称状态下的动态零和博弈
  9. 聊聊微服务拆分原则之 AKF
  10. 什么软件可以投屏电脑?最好的手机投屏软件