x24Cxx系列EEPROM芯片C语言通用读写程序

EEPROM芯片读写程序相关索引

1.AT24C01/AT24C02系列EEPROM芯片单片机读写驱动程序
2.AT24C04、AT24C08、AT24C16系列EEPROM芯片单片机读写驱动程序
3.AT24C32、AT24C64、AT24C128、AT24C256、AT24C512系列EEPROM芯片单片机读写驱动程序
4.x24Cxx系列EEPROM芯片C语言通用读写程序

一、概述

在之前的3篇文章中,介绍了x24C01~x24C512的读写程序,相关文章如下:
1.IIC驱动:4位数码管显示模块TM1637芯片C语言驱动程序
2.AT24C01、AT24C02读写:AT24C01/AT24C02系列EEPROM芯片单片机读写驱动程序
3.AT24C04、AT24C08、AT24C16读写:AT24C04、AT24C08、AT24C16系列EEPROM芯片单片机读写驱动程序
4.AT24C32、AT24C64、AT24C128、AT24C256、AT24C512读写:AT24C32、AT24C64、AT24C128、AT24C256、AT24C512系列EEPROM芯片单片机读写驱动程序
本篇博文将综合前述几篇文章,将x24C01-x24C512写成可以通用的程序,以方便不同容量EEPROM芯片移植。为此,笔者斥巨资购入了x24C01-x24C512共10个EEPROM芯片以及读写模块,全家福如下图:
在这里插入图片描述

在这里插入图片描述

以下的所有程序均在所有型号芯片上经过验证。

二、芯片对比

型号容量bit容量byte页数字节/页器件寻址位可寻址器件数WordAddress位数/字节数备注
AT24C011k128168A2A1A087/1WordAddress1个字节
AT24C022k256328A2A1A088/1WordAddress1个字节
AT24C044k5123216A2A149/1WordAddress1个字节+P0位
AT24C088k10246416A2210/1WordAddress 1个字节+P0、P1位
AT24C1616k204812816-111/1WordAddress1个字节+P0、P1、P2位
AT24C3232k4k12832A2A1A0812/2WordAddress2个字节
AT24C6464k8k25632A2A1A0813/2WordAddress2个字节
AT24C128128k16k25664A1A0414/2WordAddress2个字节
AT24C256256k32k51264A1A0415/2WordAddress2个字节
AT24C512512k64k512128A2A1A0816/2WordAddress2个字节

通过上表,结合前3篇文章的介绍,我们可以总结出,x24C01/x24C02的读写最基本,在这个基础上,由于x24C04/x24C08/x24C16的存储地址的增多,需要在对存储地址寻址的时候,多出几位,这几位加在P0/P1/P2即“页选择位”上;还是在这个基础上,x24C32/x24C64/x24C128/x24C256/x24X512的存储地址更多,1个字节+页选择位也无法满足,因此干脆将WordAddress搞成2个字节的,不再需要页选择位。

三、主要程序代码

经过上述的分析,我们还是通过宏定义的方式,先定义器件型号,再以条件编译的方式,对不同的芯片编译不同的代码。

/*******************************************************************************
型号	  Byte容量	  页数	  页内字节数    WORD_ADDR位数 WORD_ADDR字节数
x24C01	  128Byte	  16页	  8Byte			7bit			1Byte
x24C02	  256Byte	  32页	  8Byte			8bit			1Byte
x24C04	  512Byte	  32页	  16Byte		9bit			1Byte
x24C08	  1024Byte	  64页	  16Byte		10bit			1Byte
x24C16	  2048Byte	  128页	  16Byte		11bit			1Byte
x24C32	  4096Byte	  128页	  32Byte		12bit			2Byte
x24C64	  8192Byte	  256页	  32Byte		13bit			2Byte
x24C128	  16384Byte	  256页	  64Byte		14bit			2Byte
x24C256	  32768Byte	  512页	  64Byte		15bit			2Byte
x24C512	  65536Byte	  512页	  128Byte		16bit			2Byte
*******************************************************************************/
#define READ_CMD				1
#define WRITE_CMD				0

#define x24C01//器件名称,x24C01~x24C512

#define DEV_ADDR				0xA0					//设备硬件地址

#ifdef x24C01
	#define PAGE_NUM			16						//页数
	#define PAGE_SIZE			8						//页面大小(字节)
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		1						//地址字节个数
#endif 
 
#ifdef x24C02
	#define PAGE_NUM			32						//页数 
	#define PAGE_SIZE			8						//页面大小(字节)
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		1						//地址字节个数
#endif
 
#ifdef x24C04
 	#define PAGE_NUM			32						//页数
	#define PAGE_SIZE			16						//页面大小(字节)
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		1						//地址字节个数
#endif
 
#ifdef x24C08
 	#define PAGE_NUM			64						//页数
	#define PAGE_SIZE			16						//页面大小(字节)
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		1						//地址字节个数
#endif
 
#ifdef x24C16
 	#define PAGE_NUM			128						//页数
	#define PAGE_SIZE			16						//页面大小(字节)
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		1						//地址字节个数
#endif
 
#ifdef x24C32
 	#define PAGE_NUM			128						//页数
	#define PAGE_SIZE			32						//页面大小(字节)
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		2						//地址字节个数
#endif
 
#ifdef x24C64
 	#define PAGE_NUM			256						//页数
	#define PAGE_SIZE			32						//页面大小(字节)
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		2						//地址字节个数
#endif
 
#ifdef x24C128
 	#define PAGE_NUM			256						//页数
	#define PAGE_SIZE			64						//页面大小(字节)
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		2						//地址字节个数
#endif
 
#ifdef x24C256
 	#define PAGE_NUM			512						//页数
	#define PAGE_SIZE			64						//页面大小(字节)
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		2						//地址字节个数
#endif
 
#ifdef x24C512
 	#define PAGE_NUM			512						//页数
	#define PAGE_SIZE			128						//页面大小(字节) 
	#define CAPACITY_SIZE		(PAGE_NUM * PAGE_SIZE)	//总容量(字节)
	#define ADDR_BYTE_NUM		2						//地址字节个数
#endif
/*******************************************************************************
  * 函数名:x24Cxx_WriteByte
  * 功  能:写一个字节
  * 参  数:u16Addr要写入的地址
			u8Data要写入的数据
  * 返回值:无
  * 说  明:器件地址(包含写入命令) -> 1或2个字节WORD ADDR -> 数据
*******************************************************************************/
void x24Cxx_WriteByte(uint16_t u16Addr, uint8_t u8Data)
{
	x24Cxx_WriteEnable();//使能写入
	IIC_Start();//起始信号	
	#if	(ADDR_BYTE_NUM == 1)//地址只有1个字节
	{
		IIC_WriteByte(DEV_ADDR | WRITE_CMD | (((uint8_t)((u16Addr >> 8) & 0x07)) << 1));//器件寻址+写+页选择位
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)(u16Addr & 0xFF));//只取地址的低字节
		IIC_WaitAck();//等待应答
	}
	#endif
	#if	(ADDR_BYTE_NUM == 2)//地址有2个字节
	{
		IIC_WriteByte(DEV_ADDR | WRITE_CMD);//器件寻址+写
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)((u16Addr >> 8) & 0xFF));//地址高字节
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)(u16Addr & 0xFF));//地址低字节
		IIC_WaitAck();//等待应答
	}
	#endif
	IIC_WriteByte(u8Data);
	IIC_WaitAck();//等待应答
	IIC_Stop();
	x24Cxx_WriteDisble();//禁止写入
}

/*******************************************************************************
  * 函数名:x24Cxx_ReadByte
  * 功  能:读一个字节
  * 参  数:u16Addr要读取的地址
  * 返回值:u8Data读出的数据
  * 说  明:无
*******************************************************************************/
uint8_t x24Cxx_ReadByte(uint16_t u16Addr)
{
	uint8_t u8Data = 0;
	IIC_Start();//起始信号	
	#if	(ADDR_BYTE_NUM == 1)//地址只有1个字节
	{
		IIC_WriteByte(DEV_ADDR | WRITE_CMD | (((uint8_t)((u16Addr >> 8) & 0x07)) << 1));//器件寻址+写+页选择位
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)(u16Addr & 0xFF));//只取地址的低字节
		IIC_WaitAck();//等待应答
	}
	#endif
	#if	(ADDR_BYTE_NUM == 2)//地址有2个字节
	{
		IIC_WriteByte(DEV_ADDR | WRITE_CMD);//器件寻址+写
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)((u16Addr >> 8) & 0xFF));//地址高字节
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)(u16Addr & 0xFF));//地址低字节
		IIC_WaitAck();//等待应答
	}
	#endif
	IIC_Start();//起始信号
	IIC_WriteByte(DEV_ADDR | READ_CMD);//器件寻址+读
	IIC_WaitAck();//等待应答
	u8Data = IIC_ReadByte();
	IIC_NoAck();
	IIC_Stop();
	return u8Data;
}
/*******************************************************************************
  * 函数名:x24Cxx_WritePage
  * 功  能:页写
  * 参  数:u16Addr要写入的首地址;
			u8Len写入数据字节数,最大为PAGE_SIZE
			pData要写入的数据首地址
  * 返回值:无
  * 说  明:最多写入1页,防止翻卷,如果地址跨页则去掉跨页的部分
*******************************************************************************/
void x24Cxx_WritePage(uint16_t u16Addr, uint8_t u8Len, uint8_t *pData)
{
	uint8_t i;
	if (u8Len > PAGE_SIZE)//长度大于页的长度
	{
		u8Len = PAGE_SIZE;
	}
	if ((u16Addr + (uint16_t)u8Len) > CAPACITY_SIZE)//超过容量
	{
		u8Len = (uint8_t)(CAPACITY_SIZE - u16Addr);
	}
	if (((u16Addr % PAGE_SIZE) + (uint16_t)u8Len) > PAGE_SIZE)//判断是否跨页
	{
		u8Len -= (uint8_t)((u16Addr + (uint16_t)u8Len) % PAGE_SIZE);//跨页,截掉跨页的部分
	}
	x24Cxx_WriteEnable();//使能写入
	IIC_Start();//起始信号
	#if	(ADDR_BYTE_NUM == 1)//地址只有1个字节
	{
		IIC_WriteByte(DEV_ADDR | WRITE_CMD | (((uint8_t)((u16Addr >> 8) & 0x07)) << 1));//器件寻址+写+页选择位
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)(u16Addr & 0xFF));//只取地址的低字节
		IIC_WaitAck();//等待应答
	}
	#endif
	#if	(ADDR_BYTE_NUM == 2)//地址有2个字节
	{
		IIC_WriteByte(DEV_ADDR | WRITE_CMD);//器件寻址+写
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)((u16Addr >> 8) & 0xFF));//地址高字节
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)(u16Addr & 0xFF));//地址低字节
		IIC_WaitAck();//等待应答
	}
	#endif	
	for (i = 0; i < u8Len; i++)
	{
		IIC_WriteByte(*(pData + i));
		IIC_WaitAck();//等待应答
	}
	IIC_Stop();	
	x24Cxx_WriteDisble();//禁止写入
}
/*******************************************************************************
  * 函数名:x24Cxx_ReadPage
  * 功  能:页读
  * 参  数:u16Addr要读取的首地址;
			u8Len读取数据字节数,最大为PAGE_SIZE
			pBuff读取数据存入的缓存
  * 返回值:无
  * 说  明:无
*******************************************************************************/
void x24Cxx_ReadPage(uint16_t u16Addr, uint8_t u8Len, uint8_t *pBuff)
{
	uint8_t i;
	if (u8Len > PAGE_SIZE)//长度大于页的长度
	{
		u8Len = PAGE_SIZE;
	}
	if ((u16Addr + (uint16_t)u8Len) > CAPACITY_SIZE)//超过容量
	{
		u8Len = (uint8_t)(CAPACITY_SIZE - u16Addr);
	}
	if (((u16Addr % PAGE_SIZE) + (uint16_t)u8Len) > PAGE_SIZE)//判断是否跨页
	{
		u8Len -= (uint8_t)((u16Addr + (uint16_t)u8Len) % PAGE_SIZE);//跨页,截掉跨页的部分
	}
	IIC_Start();//起始信号	
	#if	(ADDR_BYTE_NUM == 1)//地址只有1个字节
	{
		IIC_WriteByte(DEV_ADDR | WRITE_CMD | (((uint8_t)((u16Addr >> 8) & 0x07)) << 1));//器件寻址+写+页选择位
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)(u16Addr & 0xFF));//只取地址的低字节
		IIC_WaitAck();//等待应答
	}
	#endif
	#if	(ADDR_BYTE_NUM == 2)//地址有2个字节
	{
		IIC_WriteByte(DEV_ADDR | WRITE_CMD);//器件寻址+写
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)((u16Addr >> 8) & 0xFF));//地址高字节
		IIC_WaitAck();//等待应答
		IIC_WriteByte((uint8_t)(u16Addr & 0xFF));//地址低字节
		IIC_WaitAck();//等待应答
	}
	#endif
	IIC_Start();//起始信号
	IIC_WriteByte(DEV_ADDR | READ_CMD);//器件寻址+读
	IIC_WaitAck();//等待应答
	for (i = 0; i < (u8Len - 1); i++)
	{
		*(pBuff + i) = IIC_ReadByte();
		IIC_Ack();
	}
	*(pBuff + u8Len - 1) = IIC_ReadByte();
	IIC_NoAck();//最后一个不应答
	IIC_Stop();
}

四、总结

1.器件地址必须与A2/A1/A0引脚的硬件连接对应;
2.该程序,写入或读取的地址,不要超过芯片的容量,否则结果会异常,读者可以自行修改程序,做功能更全面的地址是否合规的检查;
3.x24Cxx_WriteEnable()函数为WP写保护功能使能,根据单片机的引脚配置自行定义;
4.调用写入程序(无论是单字节写入还是页写),需要延时10ms(即twr,有的芯片手册说是5ms)后再对器件进行操作,否则这段时间内器件不响应命令;

  • 3
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
首先简单的说明以下I2C总线,I2C总线是一种串行数据总线,只有二根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。在 I2C总线上传送的一个数据字节由八位组成。总线对每次传送的字节数没有限制,但每个字节后必须跟一位应答位。数据传送首先传送最高位(MSB),数据传送按图1所示格式进行。首先由主机发出启动信号“S”(SDA在SCL高电平期间由高电平跳变为低电平),然后由主机发送一个字节的数据。启动信号后的第一个字节数据具有特殊含义:高七位是从机的地址,第八位是传送方向位,0表示主机发送数据(),1表示主机接收数据()。被寻址到的从机设备按传送方向位设置为对应工作方式。标准I2C总线的设备都有一个七位地址,所有连接在I2C总线上的设备都接收启动信号后的第一个字节,并将接收到的地址与自己的地址进行比较,如果地址相符则为主机要寻访的从机,应在第九位答时钟脉冲时向SDA线送出低电平作为应答。除了第一字节是通用呼叫地址或十位从机地址之外第二字节开始即数据字节。数据传送完毕,由主机发出停止信号“P”(SDA在SCL高电平期间由低电平跳变为高电平)。   AT24C系列串行E2PROM具有I2C总线接口功能,功耗小,宽电源电压(根据不同型号2.5V~6.0V),工作电流约为3mA,静态电流随电源电压不同为30μA~110μA,AT24C系列串行E2PROM参数如下 型 号 容 量 器件寻址字节(8位) 一次装载字节数 AT24C01 128×8 1010A2A1A0 R/W 4 AT24C02 256×8 1010A2A1A0 R/W 8 AT24C04 512×8 1010A2A1P0 R/W 16 AT24C08 1024×8 1010A2P1P0 R/W 16 AT24C16 2048×8 1010P2P1P0 R/W 16   由于I2C总线可挂接多个串行接口器件,在I2C总线中每个器件应有唯一的器件地址,按I2C总线规则,器件地址为7位数据(即一个I2C总线系统中理论上可挂接128个不同地址的器件),它和1位数据方向位构成一个器件寻址字节,最低位D0为方向位(/)。器件寻址字节中的最高4位(D7~D4)为器件型号地址,不同的I2C总线接口器件的型号地址是厂家给定的,如AT24C系列E2PROM的型号地址皆为1010,器件地址中的低3位为引脚地址A2 A1 A0,对应器件寻址字节中的D3、D2、D1位,在硬件设计时由连接的引脚电平给定。   对AT24C系列 E2PROM的操作完全遵守I2C总线的主收从发和主发从收的规则。
### 回答1: 基于STM32的AT24CXX程序案例是指在STM32开发板上使用AT24CXX系列I2C EEPROM芯片的示例程序。AT24CXX系列芯片是一种非易失性存储器,通过I2C总线与微控制器通信。以下是一个简单的示例程序: 首先,需要在STM32的开发环境中创建一个新的工程。然后,根据开发板上的引脚配置连接AT24CXX芯片与STM32开发板。常用的引脚连接如下: - SDA引脚连接到STM32的SDA引脚 - SCL引脚连接到STM32的SCL引脚 - VCC引脚连接到STM32的3.3V电源 - GND引脚连接到STM32的地 在示例程序中,首先需要包含I2C库的头文件,以便能够使用相关的函数和变量。然后,在主程序中,初始化I2C总线并设置AT24CXX芯片的地址。 接下来,可以使用I2C库提供的函数来AT24CXX芯片的数据。例如,可以使用函数往芯片入数据,如WriteByte函数,它接收芯片的地址、要入的数据和数据长度作为参数。 同时,还可以使用相应的函数来从芯片取数据,如ReadByte函数,它接收芯片的地址和要取的数据长度作为参数,并返回取到的数据。 用户可以根据自己的需求,使用不同的函数来实现对AT24CXX芯片操作。在示例程序中,可以先往芯片入一些数据,然后再从芯片取出来进行验证。 最后,记得释放I2C总线资源,关闭芯片的访问。 这只是一个简单的基于STM32的AT24CXX程序案例,实际上,在实际应用中可能会更复杂,需要根据具体情况进行修改和调试。希望这个简单的示例能够对您有所帮助! ### 回答2: AT24CXX是一种串行EEPROM芯片,常用于存储一些不经常变化的数据,如配置参数、历史记录等。STM32是一款微控制器,具有丰富的外设和高性能,适用于各种应用场景,包括AT24CXX的应用。 基于STM32的AT24CXX程序案例可以实现以下功能:取和入AT24CXX芯片的数据。 首先,需要进行初始化设置。通过I2C总线连接STM32和AT24CXX,设置I2C引脚并配置I2C的工作频率。 然后,可以进行数据取和入操作。对于取操作,先发送I2C启动信号,然后发送AT24CXX的地址和取命令,再取数据并通过串口打印出来。对于入操作,先发送I2C启动信号,然后发送AT24CXX的地址和入命令,再将要入的数据发送给AT24CXX。 最后,需要释放I2C总线资源。发送I2C停止信号,完成取或入操作后,释放I2C总线。 总结起来,基于STM32的AT24CXX程序案例主要包括初始化设置、数据取、数据入和I2C总线资源释放。通过该程序可以轻松实现与AT24CXX芯片的通信,实现对数据的操作。这样的程序案例可以被广泛应用于各种需要使用AT24CXX芯片存储数据的应用中。 ### 回答3: 基于STM32的AT24CXX是一种常见的串行EEPROM(电可擦除可编程只存储器),在许多应用中被用于存储较小的数据。下面是一个基于STM32的AT24CXX程序案例的简要说明。 首先,我们需要在STM32上连接AT24CXX芯片。AT24CXX有不同的型号,如AT24C02、AT24C08等,具有不同的存储容量。我们需要根据芯片型号选择正确的硬件连接方式,通常是通过I2C总线连接。 在项目中,我们需要引入STM32开发环境,并准备好相应的库文件。在主程序中,首先初始化I2C总线,并配置相关的引脚和时钟。 接下来,我们需要编AT24CXX的函数。例如,我们可以编一个函数来向AT24CXX芯片入数据,该函数接收一个地址和一个数据字节作为参数。函数首先发送起始信号,然后发送设备地址和入命令,再发送数据地址,最后发送数据字节。函数最后发送停止信号来结束整个传输过程。 同样,我们也需要编一个函数来从AT24CXX芯片取数据。该函数也需要接收一个地址参数,并返回取到的数据字节。同样,函数首先发送起始信号,然后发送设备地址和取命令,再发送数据地址。最后,函数接收从芯片返回的数据字节,并发送停止信号。 在主程序中,我们可以使用这些函数来实现我们的需求。例如,我们可以编一个函数来向AT24CXX芯片入一串数据,并编另一个函数来从芯片取该数据,并在串口终端上打印出来。 总的来说,基于STM32的AT24CXX程序案例涉及到初始化I2C总线、入和取AT24CXX芯片的函数。开发者可以根据自己的需求和芯片型号编相应的代码。这样,我们可以成功在STM32上实现对AT24CXX芯片操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值