学习笔记四.基于HAL库的stm32f103硬件读写EEPROM(CUBEMX)

本文介绍了如何使用STM32CubeMX配置硬件IIC来读写EEPROM(AT24C02)。通过HAL库的I2C_Mem_Write和I2C_Mem_Read函数实现单字节和页的读写操作,并详细解释了函数参数。还提供了一个5ms延时的重要性以及页写入的封装函数,确保数据正确写入。最后展示了完整的读写和页写入示例代码。
摘要由CSDN通过智能技术生成

基于cubemx的stm32f103硬件读写EEPROM

今天介绍一种可擦除存储器.
EEPROM (Electrically Erasable Programmable read only memory)是指带电可擦可编程只读存储器。是一种掉电后数据不丢失的存储芯片。EEPROM 可以在电脑上或专用设备上擦除已有信息,重新编程。一般用在即插即用。(百度百科)
一般常规单片机的EEPROM是AT24C02
(AT24C02是一个2K位串行CMOS E2PROM, 内部含有256个8位字节,CATALYST公司的先进CMOS技术实质上减少了器件的功耗。AT24C02有一个16字节页写缓冲器。该器件通过IIC总线接口进行操作,有一个专门的写保护功能。【百度百科】)

在这里插入图片描述
EEPROM 芯片最常用的通讯方式就是 I2C 协议,在上一篇文章我们介绍了用软件IIC写OLED,今天我们采用硬件IIC(因为软件IIC调试出了问题,还没解决,解决了补上传)。
打开cubemx配置硬件IIC,顺便配置一下串口方便监测数据。

读写eeprom主要用这句函数
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout)
参数解释
在这里插入图片描述
对这句函数做一下小的封装,就可以写入字节,和页写入。写之前要注意eeprom的写地址是0XA0,读地址0XA1。

//只写
uint8_t At24c02_Write_Byte(uint16_t addr, uint8_t* data)
{
	return HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, addr, I2C_MEMADD_SIZE_8BIT, data, 1, 0xFFFF);
}
//只读
uint8_t At24c02_Read_Byte(uint16_t addr, uint8_t* data,uint16_t size)
{
	return HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, addr, I2C_MEMADD_SIZE_8BIT, data, size, 0xFFFF);
}



//参数为写地址,写的数据(一般可以定义一个数组),读地址
void eeprom_onebit_rw(uint16_t write_addr, uint8_t* write_dat,uint16_t read_addr)		
{
  uint8_t recv_buf=0;//读取数据的数组
	if(HAL_OK == HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_WRITE, write_addr, I2C_MEMADD_SIZE_8BIT, write_dat, 1, 0xFFFF))
	{
		printf("EEPROM WRITE OK\n");
	}
	else
	{
		printf("WRITE FAIL\n");
	}
	
	HAL_Delay(5);		//5毫秒延时
	
	if(HAL_OK == HAL_I2C_Mem_Read(&hi2c1, AT24C02_ADDR_READ, read_addr, I2C_MEMADD_SIZE_8BIT, &recv_buf, 1, 0xFFFF))
	{
		printf("Read Ok, recv_data = %d\n ",recv_buf);
	}
	else
	{
		printf("Read Fail\n");
	}
}

直接将函数放在主函数里面调用,串口打印数据
请添加图片描述
函数中5ms的延时很重要,如果没有延时,数据写会失败
请添加图片描述
这是单个字节写入。一字节写一字节写很麻烦,所以我们继续封装,编写页写入函数。
首先我们知道eeprom每页8个字节,地址从0-255,借鉴野火的页写入方法,相应参数移植前做更改,可以自己写一写试一下

uint32_t I2C_EE_PageWrite(uint8_t* pBuffer, uint8_t WriteAddr,uint8_t NumByteToWrite)
 {
	HAL_StatusTypeDef status = HAL_OK;
	/* Write EEPROM_PAGESIZE */
	status=HAL_I2C_Mem_Write(&hi2c1, AT24C02_ADDR_READ,WriteAddr,I2C_MEMADD_SIZE_8BIT, (uint8_t*)(pBuffer),NumByteToWrite, 100);
	while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY){
	}
	/* Check if the EEPROM is ready for a new operation */
	while (HAL_I2C_IsDeviceReady(&hi2c1, AT24C02_ADDR_WRITE,3000, 0xffff) == HAL_TIMEOUT);
	/* Wait for the end of the transfer */
	while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY) {
	}
	return status;
}
 
//void I2C_EE_WaitEepromStandbyState(void); //是等待响应的函数,不再展开  

 /**
 * @brief 将缓冲区中的数据写到 I2C EEPROM 中
 * @param
 * @arg pBuffer:缓冲区指针
 * @arg WriteAddr:写地址
 * @arg NumByteToWrite:写的字节数
 * @retval 无
 */
  #define I2C_PageSize 8
  
 void I2C_EE_BufferWrite(u8* pBuffer, u8 WriteAddr,u16 NumByteToWrite)
 {
	u8 NumOfPage=0,NumOfSingle=0,Addr =0,count=0,temp =0;
 
	/*mod 运算求余,若 writeAddr 是 I2C_PageSize 整数倍,
	运算结果 Addr 值为 0*/
	Addr = WriteAddr % I2C_PageSize;
 
	/*差 count 个数据值,刚好可以对齐到页地址*/
	count = I2C_PageSize - Addr;
	
	/*计算出要写多少整数页*/
	NumOfPage = NumByteToWrite / I2C_PageSize;
 
	/*mod 运算求余,计算出剩余不满一页的字节数*/
	NumOfSingle = NumByteToWrite % I2C_PageSize;
	
	// Addr=0,则 WriteAddr 刚好按页对齐 aligned
	// 这样就很简单了,直接写就可以,写完整页后
	// 把剩下的不满一页的写完即可
	if (Addr == 0) {
		/* 如果 NumByteToWrite < I2C_PageSize */
		if (NumOfPage == 0) {
			I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
			//I2C_EE_WaitEepromStandbyState();
		//	HAL_Delay(50);
		}
		/* 如果 NumByteToWrite > I2C_PageSize */
		else {
			/*先把整数页都写了*/
			while (NumOfPage--) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
			//	I2C_EE_WaitEepromStandbyState();
			//	HAL_Delay(50);
				WriteAddr += I2C_PageSize;
				pBuffer += I2C_PageSize;
			}
			/*若有多余的不满一页的数据,把它写完*/
			if (NumOfSingle!=0) {
			I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
		//	I2C_EE_WaitEepromStandbyState();
		//		HAL_Delay(50);
			}
		}
	}
	// 如果 WriteAddr 不是按 I2C_PageSize 对齐
	// 那就算出对齐到页地址还需要多少个数据,然后
	// 先把这几个数据写完,剩下开始的地址就已经对齐
	// 到页地址了,代码重复上面的即可
	else {
		/* 如果 NumByteToWrite < I2C_PageSize */
		if (NumOfPage== 0) {
			/*若 NumOfSingle>count,当前面写不完,要写到下一页*/
				if (NumOfSingle > count) {
					// temp 的数据要写到写一页
					temp = NumOfSingle - count;
					I2C_EE_PageWrite(pBuffer, WriteAddr, count);
		//			I2C_EE_WaitEepromStandbyState();
		//			HAL_Delay(50);
					WriteAddr += count;
					pBuffer += count;
					
					I2C_EE_PageWrite(pBuffer, WriteAddr, temp);
			//		I2C_EE_WaitEepromStandbyState();
			//		HAL_Delay(50);
				} 
				else { /*若 count 比 NumOfSingle 大*/
						I2C_EE_PageWrite(pBuffer, WriteAddr, NumByteToWrite);
		//				I2C_EE_WaitEepromStandbyState();
		//			HAL_Delay(50);
					}
		}
		/* 如果 NumByteToWrite > I2C_PageSize */
		else {
			/*地址不对齐多出的 count 分开处理,不加入这个运算*/
			NumByteToWrite -= count;
			NumOfPage = NumByteToWrite / I2C_PageSize;
			NumOfSingle = NumByteToWrite % I2C_PageSize;
			
			/*先把 WriteAddr 所在页的剩余字节写了*/
			if (count != 0) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, count);
		//		I2C_EE_WaitEepromStandbyState();
		//		HAL_Delay(50);
				/*WriteAddr 加上 count 后,地址就对齐到页了*/
				WriteAddr += count;
				pBuffer += count;
			}
			/*把整数页都写了*/
			while (NumOfPage--) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, I2C_PageSize);
		//		I2C_EE_WaitEepromStandbyState();
		//		HAL_Delay(50);
				WriteAddr += I2C_PageSize;
				pBuffer += I2C_PageSize;
			}
			/*若有多余的不满一页的数据,把它写完*/
			if (NumOfSingle != 0) {
				I2C_EE_PageWrite(pBuffer, WriteAddr, NumOfSingle);
	//			I2C_EE_WaitEepromStandbyState();
	//			HAL_Delay(50);
			}
		}
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可见读取正确,页写入成功。

早睡不掉头发,祝大家多喝水(手动狗头)

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

地球先生_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值