xld0932 发表于 2021-4-21 21:37

【HC32F460开发板测评】07.硬件I2C实现EEPROM读写操作

<p>HC32F460开发板搭载了一颗I2C接口的EEPROM存储芯片,可以用于存储一些需要掉电记忆保存的数据或者是配置参数;在官方的例程中给出了关于EEPROM的读写操作,但这个例程仅限于小于等于一个PAGE的数据内容的写操作,如果写入的数据是跨PAGE的,就需要重新设计一下程序代码了;正好本文给出了EEPROM跨PAGE写入的通用程序,可以在实际项目做作为参考;同时也可以掌握硬件I2C的读写操作。</p>

<p>&nbsp;</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>&nbsp;</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 *)&amp;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 *)&amp;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(&amp;stcClkFreq);

    MEM_ZERO_STRUCT(stcI2cInit);
    stcI2cInit.u32Pclk3    = stcClkFreq.pclk3Freq;
    stcI2cInit.u32Baudrate = 100000ul;
    stcI2cInit.u32SclTime= 0ul;
    enRet = I2C_Init(M4_I2C1, &amp;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 &lt; 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 &lt; 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>&nbsp;</p>

<p>运行结果:</p>

<p>EEPROM的每一个PAGE大小为8个字节,例程中演示的是从EEPROM的起始存储地址0开始,写入20个字节的数据(跨了3个PAGE域),然后再将这20个存储空间的内容读取出来与写入数据进行比对,并打印出读取到的数据内容;</p>

<p></p>

<p>&nbsp;</p>

<p>工程源码:</p>

<p></p>

<p>&nbsp;</p>

w494143467 发表于 2021-4-22 18:15

<p>不错不错!感谢分享!!!</p>

freebsder 发表于 2021-4-23 15:46

<table cellpadding="0" cellspacing="0">
        <tbody>
                <tr>
                        <td>
                        <p>不错不错!感谢分享!!!</p>
                        </td>
                </tr>
        </tbody>
</table>

songweiabcde 发表于 2022-7-21 14:12

<p>感谢分享</p>

Luxuff 发表于 2024-8-14 10:59

<p>发送地址时&nbsp;(const uint8_t *)&amp;Address&nbsp;的写法不适用于小端序机器且I2C器件要求地址高位先发的情况,会造成页覆盖的假象,示例正常有可能是PAGE大小为32字节</p>
页: [1]
查看完整版本: 【HC32F460开发板测评】07.硬件I2C实现EEPROM读写操作