当前位置: 代码迷 >> 综合 >> 学习笔记四.基于HAL库的stm32f103硬件读写EEPROM(CUBEMX)
  详细解决方案

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

热度:76   发布时间:2023-11-22 19:29:56.0

基于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 8void 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);}}}
}

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

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

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

  相关解决方案