【HC32F460开发板测评】07.硬件I2C实现EEPROM读写操作
<p>HC32F460开发板搭载了一颗I2C接口的EEPROM存储芯片,可以用于存储一些需要掉电记忆保存的数据或者是配置参数;在官方的例程中给出了关于EEPROM的读写操作,但这个例程仅限于小于等于一个PAGE的数据内容的写操作,如果写入的数据是跨PAGE的,就需要重新设计一下程序代码了;正好本文给出了EEPROM跨PAGE写入的通用程序,可以在实际项目做作为参考;同时也可以掌握硬件I2C的读写操作。</p><p> </p>
<p>硬件原理图:</p>
<p></p>
<p>EEPROM头文件:</p>
<pre>
<code class="language-cpp">/*******************************************************************************
* @file EEPROM.h
* @authorxld0932
* @version V1.00
* @date 31-Mar-2021
* @brief ......
*******************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __EEPROM_H__
#define __EEPROM_H__
#ifdef __cplusplus
extern "C" {
#endif
#undefEXTERN
#ifdef__EEPROM_C__
#define EXTERN
#else
#define EXTERN extern
#endif
/* Includes ------------------------------------------------------------------*/
#include "config.h"
/* Exported constants --------------------------------------------------------*/
#define EEPROM_I2C_ADDRESS (0x50u)
#define EEPROM_I2C_TIMEOUT (0x40000ul)
#define EEPROM_PAGE_SIZE (8u)
/* Exported types ------------------------------------------------------------*/
/* Exported macro ------------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
EXTERN void EEPROM_Init(void);
EXTERN void EEPROM_Demo(void);
#ifdef __cplusplus
}
#endif
#endif
/******************* (C) COPYRIGHT 2021 *************************END OF FILE***/
</code></pre>
<p> </p>
<p>EEPROM源程序:</p>
<pre>
<code class="language-cpp">/*******************************************************************************
* @file EEPROM.c
* @authorxld0932
* @version V1.00
* @date 31-Mar-2021
* @brief ......
*******************************************************************************/
/* Define to prevent recursive inclusion -------------------------------------*/
#define __EEPROM_C__
/* Includes ------------------------------------------------------------------*/
#include "EEPROM.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported function prototypes ----------------------------------------------*/
/*******************************************************************************
* @brief
* @param
* @retval
* @attention *******************************************************************************/
en_result_t EEPROM_I2C_Write(uint16_t Address, uint8_t *Buffer, uint32_t Length)
{
en_result_t enRet;
I2C_Cmd(M4_I2C1, Enable);
I2C_SoftwareResetCmd(M4_I2C1, Enable);
I2C_SoftwareResetCmd(M4_I2C1, Disable);
if(I2C_Start(M4_I2C1, EEPROM_I2C_TIMEOUT) == Ok)
{
if(I2C_TransAddr(M4_I2C1, EEPROM_I2C_ADDRESS, I2CDirTrans, EEPROM_I2C_TIMEOUT) == Ok)
{
if(I2C_TransData(M4_I2C1, (const uint8_t *)&Address, 1u, EEPROM_I2C_TIMEOUT) == Ok)
{
enRet = I2C_TransData(M4_I2C1, Buffer, Length, EEPROM_I2C_TIMEOUT);
}
}
}
I2C_Stop(M4_I2C1, EEPROM_I2C_TIMEOUT);
I2C_Cmd(M4_I2C1, Disable);
return enRet;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
en_result_t EEPROM_I2C_Read(uint16_t Address, uint8_t *Buffer, uint32_t Length)
{
en_result_t enRet;
I2C_Cmd(M4_I2C1, Enable);
I2C_SoftwareResetCmd(M4_I2C1, Enable);
I2C_SoftwareResetCmd(M4_I2C1, Disable);
if(I2C_Start(M4_I2C1, EEPROM_I2C_TIMEOUT) == Ok)
{
if(I2C_TransAddr(M4_I2C1, EEPROM_I2C_ADDRESS, I2CDirTrans, EEPROM_I2C_TIMEOUT) == Ok)
{
if(I2C_TransData(M4_I2C1, (uint8_t const *)&Address, 1u, EEPROM_I2C_TIMEOUT) == Ok)
{
if(I2C_Restart(M4_I2C1, EEPROM_I2C_TIMEOUT) == Ok)
{
if(1ul == Length)
{
I2C_AckConfig(M4_I2C1, I2c_NACK);
}
if(I2C_TransAddr(M4_I2C1, EEPROM_I2C_ADDRESS, I2CDirReceive, EEPROM_I2C_TIMEOUT) == Ok)
{
enRet = I2C_MasterDataReceiveAndStop(M4_I2C1, Buffer, Length, EEPROM_I2C_TIMEOUT);
}
I2C_AckConfig(M4_I2C1, I2c_ACK);
}
}
}
}
if(Ok != enRet)
{
I2C_Stop(M4_I2C1, EEPROM_I2C_TIMEOUT);
}
I2C_Cmd(M4_I2C1, Disable);
return enRet;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
en_result_t EEPROM_I2C_Init(void)
{
stc_i2c_init_t stcI2cInit;
stc_clk_freq_t stcClkFreq;
en_result_t enRet;
/* Initialize I2C port*/
PORT_SetFunc(PortC, Pin04, Func_I2c1_Scl, Disable);
PORT_SetFunc(PortC, Pin05, Func_I2c1_Sda, Disable);
/* Enable I2C Peripheral*/
PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_I2C1, Enable);
I2C_DeInit(M4_I2C1);
/* Get system clock frequency */
CLK_GetClockFreq(&stcClkFreq);
MEM_ZERO_STRUCT(stcI2cInit);
stcI2cInit.u32Pclk3 = stcClkFreq.pclk3Freq;
stcI2cInit.u32Baudrate = 100000ul;
stcI2cInit.u32SclTime= 0ul;
enRet = I2C_Init(M4_I2C1, &stcI2cInit);
I2C_BusWaitCmd(M4_I2C1, Enable);
return enRet;
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void EEPROM_ReadData(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
EEPROM_I2C_Read(Address, Buffer, Length);
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void EEPROM_WriteData(uint8_t Address, uint8_t *Buffer, uint8_t Length)
{
uint8_t Start, StartCount, PageNumber, FinalCount;
/*
* EEPROM需要分页写入, 根据当前的写入起始地址和数据长度进行判断处理
*/
if((Address % EEPROM_PAGE_SIZE) == 0)
{
StartCount = 0;
PageNumber = Length / EEPROM_PAGE_SIZE;
FinalCount = Length % EEPROM_PAGE_SIZE;
}
else
{
Start = Address % EEPROM_PAGE_SIZE;
if(((Start + Length) / EEPROM_PAGE_SIZE) == 0)
{
StartCount = Length;
PageNumber = 0;
FinalCount = 0;
}
else
{
StartCount = EEPROM_PAGE_SIZE - Start;
PageNumber = (Length - StartCount) / EEPROM_PAGE_SIZE;
FinalCount = (Length - StartCount) % EEPROM_PAGE_SIZE;
}
}
if(StartCount)
{
EEPROM_I2C_Write(Address, Buffer, StartCount);
Address += StartCount;
Buffer+= StartCount;
printf("\r\nWait A Moument...");Ddl_Delay1ms(5);
}
while(PageNumber--)
{
EEPROM_I2C_Write(Address, Buffer, EEPROM_PAGE_SIZE);
Address += EEPROM_PAGE_SIZE;
Buffer+= EEPROM_PAGE_SIZE;
printf("\r\nWait A Moument...");Ddl_Delay1ms(5);
}
if(FinalCount)
{
EEPROM_I2C_Write(Address, Buffer, FinalCount);
printf("\r\nWait A Moument...");Ddl_Delay1ms(5);
}
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void EEPROM_Init(void)
{
EEPROM_I2C_Init();
}
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void EEPROM_Demo(void)
{
uint8_t rBuffer, wBuffer;
uint8_t Address = 0;
uint8_t Length = 20;
for(uint8_t i = 0; i < 20; i++)
{
rBuffer = 0;
wBuffer = i + 10;
}
printf("\r\n\r\nEEPROM Write Data : ");
EEPROM_WriteData(Address, wBuffer, Length);
printf("OK");
printf("\r\n\r\nEEPROM ReadData : \r\n");
EEPROM_ReadData(Address, rBuffer, Length);
for(uint8_t i = 0; i < Length; i++)
{
printf("0x%02x ", rBuffer);
if(((i + 1) % 10) == 0) printf("\r\n");
}
printf("\r\n\r\n");
}
/******************* (C) COPYRIGHT 2021 *************************END OF FILE***/
</code></pre>
<p> </p>
<p>运行结果:</p>
<p>EEPROM的每一个PAGE大小为8个字节,例程中演示的是从EEPROM的起始存储地址0开始,写入20个字节的数据(跨了3个PAGE域),然后再将这20个存储空间的内容读取出来与写入数据进行比对,并打印出读取到的数据内容;</p>
<p></p>
<p> </p>
<p>工程源码:</p>
<p></p>
<p> </p>
<p>不错不错!感谢分享!!!</p>
<table cellpadding="0" cellspacing="0">
<tbody>
<tr>
<td>
<p>不错不错!感谢分享!!!</p>
</td>
</tr>
</tbody>
</table>
<p>感谢分享</p> <p>发送地址时 (const uint8_t *)&Address 的写法不适用于小端序机器且I2C器件要求地址高位先发的情况,会造成页覆盖的假象,示例正常有可能是PAGE大小为32字节</p>
页:
[1]