IIC驱动AT24C02(EEPROM)读写操作

本文介绍了AT24C02EEPROM的特性、地址分配、IIC通信方法以及如何通过STM32F10x进行读写操作,包括时序图解析和相关函数实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


IIC通信链接
IIC通信

AT24C02(EEPROM)简介

总容量是256(2K/8)个字节。
接口:IIC
在这里插入图片描述
在这里插入图片描述

地址介绍

1、EEPROM由8位表示为存储地址
2、设备号+读写位
其中最低位是读写位,0表示读,1表示写
高7位表示设备地址(IIC通讯使用)
下面图中的设备地址只是占用了4位,A0-A2默认为0。
因此设备地址为1010(二进制)
3、内存地址
根据EEPROM的型号不同,其中设备地址占的位数有所不同,有的存储的地址单元超过8位。
例如AT24C04有512个地址,需要9位表示。24C08有1024个地址,需要10位表示。
为解决这个问题,A0-A2不仅可以表示原有设备号的地址数据,也可以存储内存地址高于8位的数据。

在这里插入图片描述

读时序

在这里插入图片描述

写时序

在这里插入图片描述

重点理解与掌握

1、掌握IIC通信的原理与IO模拟IIC时序的逻辑代码
2、对EEPROM设备地址A0-A2的理解
3、根据时序图写发送字节函数
4、对发送字节函数进行进一步封装,发送固定长度的数据,字符串等

代码

eeprom.c文件

#include<stdio.h>
#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"
#include "i2c.h"
#include "eeprom.h"

/*

//eeprom--AT24
//u16 a;
//const u8 TEXT_Buffer[]={"2023年8月30日"};
//#define SIZE sizeof(TEXT_Buffer)

		u8 data[SIZE];
//		u8 value;
		
//		AT24_write_byte(0,0x23);			//发送数字
		AT24CXX_Write(10,(u8*)TEXT_Buffer,SIZE);
		
//		value=AT24_read_byte(0);
		AT24CXX_Read(10,data,SIZE);
		
//		printf("%x\n",value);
		printf("%s\n",data);//显示读到的字符串
		printf("\n");
		delay_ms(100);

*/

void AT24_init()
{
	i2c_init();
}
/*
按照AT24(读)时序图的先后顺序,进行顺序执行
*/
u8 AT24_read_byte(u16 readaddr)
{
	u8 value;
	iic_start();
	
	if(EE_TYPE>AT24C16)
	{
		iic_send_byte(0XA0);						//A是EEPROM在I2C的地址(手册)		
		iic_wait_ack();					
		iic_send_byte(readaddr/256);				//readaddr是EEPROM的内存地址(0~255)
		iic_wait_ack();					
	}
	else{
		iic_send_byte(0XA0|(readaddr/256)<<1);					//发送设备号和高于8位的内存地址
	}
	iic_wait_ack();
	iic_send_byte(readaddr%256);								//发送低于8位的内存地址
	iic_wait_ack();
	iic_start();
	
	iic_send_byte(0xA1);
	iic_wait_ack();
	value = iic_read_byte(0);
	iic_stop();
	return value;
}
/*
按照AT24(写)时序图的先后顺序,进行顺序执行
*/
void AT24_write_byte(u16 writeaddr,u8 DataToWrite)		//
{
	iic_start();
	if(EE_TYPE>AT24C16)
	{
		iic_send_byte(0XA0);		
		iic_wait_ack();					
		iic_send_byte(writeaddr/256);		
		iic_wait_ack();					
	}
	else{
		iic_send_byte(0XA0|(writeaddr/256)<<1);
	}
	iic_wait_ack();
	iic_send_byte(writeaddr%256);	
	iic_wait_ack();
	iic_send_byte(DataToWrite);
	iic_wait_ack();
	iic_stop();
	delay_ms(10);
}

//---------------------------------------------------------------------------

//在AT24CXX里面的指定地址开始写入长度为Len的数据
//该函数用于写入16bit或者32bit的数据.
//WriteAddr  :开始写入的地址  
//DataToWrite:数据数组首地址
//Len        :要写入数据的长度2,4
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
{  	
	u8 t;
	for(t=0;t<Len;t++)
	{
		AT24_write_byte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);
	}												    
}



//在AT24CXX里面的指定地址开始读出长度为Len的数据
//该函数用于读出16bit或者32bit的数据.
//ReadAddr   :开始读出的地址 
//返回值     :数据
//Len        :要读出数据的长度2,4
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
{  	
	u8 t;
	u32 temp=0;
	for(t=0;t<Len;t++)
	{
		temp<<=8;
		temp+=AT24_read_byte(ReadAddr+Len-t-1); 	 				   
	}
	return temp;												    
}


//检查AT24CXX是否正常
//这里用了24XX的最后一个地址(255)来存储标志字.
//如果用其他24C系列,这个地址要修改
//返回1:检测失败
//返回0:检测成功
u8 AT24CXX_Check(void)
{
	u8 temp;
	temp=AT24_read_byte(255);//避免每次开机都写AT24CXX			   
	if(temp==0X55)return 0;		   
	else//排除第一次初始化的情况
	{
		AT24_write_byte(255,0X55);
	    temp=AT24_read_byte(255);	  
		if(temp==0X55)return 0;
	}
	return 1;											  
}

//在AT24CXX里面的指定地址开始读出指定个数的数据
//读取ReadAddr地址的数据,放入pBuffer数组
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer  :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead)
{
	while(NumToRead)
	{
		*pBuffer++=AT24_read_byte(ReadAddr++);	
		NumToRead--;
	}
}  



//在AT24CXX里面的指定地址开始写入指定个数的数据
//将pBuffer数组的内容写入WriteAddr地址
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer   :数据数组首地址
//NumToWrite:要写入数据的个数
//*pBuffer  :读出来的数据保存在数组里
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite)
{
	while(NumToWrite--)
	{
		AT24_write_byte(WriteAddr,*pBuffer);
		WriteAddr++;
		pBuffer++;
	}
}

eeprom.h文件

#ifndef EEPROM_H
#define EEPROM_H
#include "stm32f10x.h"
#include "sys.h"

#define AT24C1		127
#define AT24C2		255
#define AT24C4		511
#define AT24C8		1023
#define AT24C16		2047
#define AT24C32		4095
#define AT24C64		8189
#define AT24C128		16383
#define AT24C256		32767

#define EE_TYPE 	AT24C2

void AT24_init(void);
u8 AT24_read_byte(u16 readaddr);									//读一个字节(8位)的数据
void AT24_write_byte(u16 writeaddr,u8 DataToWrite);		//写一个字节的数据

void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);			//写入Len长度位的数据
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len);
u8 AT24CXX_Check(void);
void AT24CXX_Read(u16 ReadAddr,u8 *pBuffer,u16 NumToRead);						
void AT24CXX_Write(u16 WriteAddr,u8 *pBuffer,u16 NumToWrite);

#endif
STM32 上**没有内置的 EEPROM**,但可以通过以下几种方式**模拟 EEPROM** 或使用**外部 EEPROM 芯片**。下面我们将详细讲解 STM32 中与 EEPROM 地址相关的概念和实现方式。 --- ## ✅ 一、STM32 没有内置 EEPROM STM32 系列微控制器(如 STM32F1、F4、G0、L4 等)**不包含独立的 EEPROM 存储器**,但可以使用**Flash 模拟 EEPROM**,或者通过 I²C/SPI 接口连接**外部 EEPROM 芯片**。 --- ## ✅ 二、方式一:使用 Flash 模拟 EEPROM(适用于内部存储) ### 原理: - STM32 的 Flash 可以用于存储数据。 - Flash 的擦写寿命有限(通常为 10 万次),因此需要**磨损均衡算法**。 - 每个 Flash 页的大小通常为 1KB 或 2KB。 ### EEPROM 地址 = Flash 地址 例如,使用 STM32F103C8T6: ```c #define EEPROM_START_ADDRESS (FLASH_BASE + 64 * 1024 - PAGE_SIZE) // 最后一页 Flash ``` ### 示例:写入 Flash 模拟 EEPROM ```c #include "stm32f1xx_hal.h" #define EEPROM_SIZE 256 #define PAGE_SIZE 0x400 // 1KB #define EEPROM_PAGE (63) // 使用第 63 页(最后一整页) uint32_t eeprom_address = FLASH_BASE + (EEPROM_PAGE * PAGE_SIZE); void write_to_eeprom(uint32_t address, uint16_t data) { HAL_FLASH_Unlock(); HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, address, data); HAL_FLASH_Lock(); } uint16_t read_from_eeprom(uint32_t address) { return *(uint16_t*)address; } ``` ### 注意事项: - Flash 写入前必须先擦除。 - 建议使用**双页法**或**磨损均衡算法**来延长 Flash 寿命。 - 使用 `__attribute__((section(".eeprom")))` 可以将变量分配到特定段。 --- ## ✅ 三、方式二:使用外部 EEPROM 芯片(如 24C02) ### 常见型号: | 型号 | 容量 | 接口 | 地址范围 | |------|------|------|----------| | 24C02 | 2Kbit | I²C | 0x00 ~ 0xFF | | 24C04 | 4Kbit | I²C | 0x00 ~ 0x1FF | | 24C08 | 8Kbit | I²C | 0x00 ~ 0x3FF | | 24C256 | 256Kbit | I²C | 0x0000 ~ 0x7FFF | ### 示例:使用 I²C 写入 24C02 EEPROM ```c #define EEPROM_I2C_ADDR 0xA0 // I²C 地址(7位地址为 0x50) void eeprom_write_byte(I2C_HandleTypeDef *hi2c, uint8_t mem_addr, uint8_t data) { HAL_I2C_Mem_Write(hi2c, EEPROM_I2C_ADDR, mem_addr, I2C_MEMADD_SIZE_8BIT, &data, 1, HAL_MAX_DELAY); } uint8_t eeprom_read_byte(I2C_HandleTypeDef *hi2c, uint8_t mem_addr) { uint8_t data; HAL_I2C_Mem_Read(hi2c, EEPROM_I2C_ADDR, mem_addr, I2C_MEMADD_SIZE_8BIT, &data, 1, HAL_MAX_DELAY); return data; } ``` ### 使用示例: ```c eeprom_write_byte(&hi2c1, 0x00, 0x55); // 写入地址 0x00 uint8_t val = eeprom_read_byte(&hi2c1, 0x00); // 读取地址 0x00 ``` --- ## ✅ 四、总结:EEPROM 地址的理解 | 类型 | 地址含义 | 示例 | |------|----------|------| | Flash 模拟 EEPROM | Flash 内存地址 | `0x0800FC00` | | 外部 EEPROM(I²C) | 芯片内部地址 | `0x00 ~ 0xFF` | | 外部 EEPROM(SPI) | 芯片内部地址 | `0x0000 ~ 0xFFFF` | --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饮食有节起居有常

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值