基于RT-Thread驱动EEPROM_AD24C02

前言

  1. 存储容量2048位,内部组织256x8(2K),即256个字节的存储单元;分为16页,每页16个字节
  2. 具有写保护,擦写寿命1,000,000次,数据保存期限100年
  3. 写操作可按字节写,也可按页写。
  4. I2C通信,器件从机写地址0x50, 从机读地址0x51
    在这里插入图片描述

一、硬件设计

  1. WP引脚上拉,这个引脚是写保护引脚,低电平解开保护,可以读写。高电平写保护,
    在这里插入图片描述
  2. 通过IIC即可与之通信。
    在这里插入图片描述

二、软件设计

  1. 创建工程
    在这里插入图片描述

  2. 打开RT-Thread Settings
    在这里插入图片描述

  3. 打开I2C设备驱动程序
    在这里插入图片描述

  4. 使能I2C模块
    在这里插入图片描述

  5. 进入board.h打开I2C1的的宏定义,SCL跟SDA引脚的绑定需要根据你实际硬件连接去修改
    在这里插入图片描述

  6. 主函数中这么写
    在这里插入图片描述

  7. 在applications文件夹下新建一个system_deal文件夹,然后再在system_deal文件夹下新建一个system_deal.csystem_deal.h文件,这个文件夹里我放一个给板子闪灯的程序,判断板子是否跑起来
    在这里插入图片描述

  8. system_deal.c文件里这么写

/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-04-18     Administrator       the first version
 */

#include "system_deal.h"

/*********************************************************************************************************
 ** Function name:       SystemLedRun
 ** Descriptions:        System Led Run
 ** input parameters:    NONE
 ** output parameters:   NONE
 ** Returned value:      NONE
 *********************************************************************************************************/
static void SystemLedRun(void)
{
    static uint8_t l_ucmode = 0;
    if (l_ucmode == 0)
    {
        rt_pin_write(SYS_LED, PIN_HIGH);
        l_ucmode = 1;
    }
    else if (l_ucmode == 1)
    {
        rt_pin_write(SYS_LED, PIN_LOW);
        l_ucmode = 0;
    }
}

/*********************************************************************************************************
 ** Function name:       SysDeal_thread
 ** Descriptions:        SysDeal thread
 ** input parameters:    parameter
 ** output parameters:   NONE
 ** Returned value:      NONE
 *********************************************************************************************************/
static void SysDeal_thread(void* parameter)
{
    // set pin
    rt_pin_mode(SYS_LED, PIN_MODE_OUTPUT);
    rt_pin_write(SYS_LED, PIN_HIGH);

    while(1)
    {
        SystemLedRun();   //闪个灯
        rt_thread_mdelay(500);
    }

}

/*********************************************************************************************************
 ** Function name:       SystemDealTaskInit
 ** Descriptions:        System Task Init
 ** input parameters:    NONE
 ** output parameters:   NONE
 ** Returned value:      NONE
 *********************************************************************************************************/
void SystemDealTaskInit(void)
{
    rt_thread_t SysDeal_tid;
    SysDeal_tid = rt_thread_create("sys_ctl", SysDeal_thread, RT_NULL, SYS_THREAD_STACK, SYS_THREAD_PRO, SYS_THREAD_TICK);
    if (SysDeal_tid != RT_NULL)
    {
        rt_thread_startup(SysDeal_tid);
    }
    else
    {
#if DEBUG_LOG_ENABLE
        rt_kprintf("/--> SysDeal create failed!\n");
#endif
    }
}


/*********************************************************************************************************
 ** Function name:       SystemTaskInit
 ** Descriptions:        System Task Init
 ** input parameters:    NONE
 ** output parameters:   NONE
 ** Returned value:      NONE
 *********************************************************************************************************/
static void SystemTaskInit(void)
{
    SystemDealTaskInit();  // 15

}


/*********************************************************************************************************
 ** Function name:       SystemStartInit
 ** Descriptions:        System Start Init
 ** input parameters:    NONE
 ** output parameters:   NONE
 ** Returned value:      NONE
 *********************************************************************************************************/
void SystemStartInit(void)
{
    SystemTaskInit();
}

  1. system_deal.h文件里这么写
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-04-18     Administrator       the first version
 */
#ifndef APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_
#define APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_

#include <rtdevice.h>
#include <rtthread.h>
#include "board.h"
#include "stdio.h"


/* system io */
#define SYS_LED             GET_PIN(G, 13)

/* thread information */
#define SYS_THREAD_STACK 1024
#define SYS_THREAD_PRO 15
#define SYS_THREAD_TICK 10

extern void SystemStartInit(void);

#endif /* APPLICATIONS_SYSTEM_DEAL_SYSTEM_DEAL_H_ */

  1. 在applications文件夹下新建drv_ad24c02文件夹,再在drv_ad24c02文件夹下新建drv_ad24c02.cdrv_ad24c02.h文件,这个文件夹里写的是ad24c02的驱动
    在这里插入图片描述
  2. drv_ad24c02.c文件里这么写
    在这里插入图片描述
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-04-18     Administrator       the first version
 */
#include "drv_ad24c02.h"

static struct rt_i2c_bus_device *i2c_bus = RT_NULL;
/**
 * eeprom write byte
 * @note This operation is write one bye to eeprom.
 *
 * @param addr: the data address to write
 *        data: the data write to the address
 *
 * @return >= 0: successful
 *           -1: error
 *
 */
rt_err_t eeprom_write_byte(uint8_t addr, uint8_t data)
{
    struct rt_i2c_msg msg;

    uint8_t buffer[2];

    buffer[0] = addr;
    buffer[1] = data;

    msg.addr  = EEPROM_I2C_ADDR;
    msg.flags = RT_I2C_WR;
    msg.buf = buffer;
    msg.len = 2;

    if(rt_i2c_transfer(i2c_bus, &msg, 1) != 1)
    {
        rt_kprintf("eeprom i2c data write error.\n");
        return RT_ERROR;
    }

    rt_thread_mdelay(5);
    return RT_EOK;
}
/**
 * eeprom read byte
 * @note This operation is read one bye from eeprom.
 *
 * @param addr: the data address to read
 *
 * @return data: the data read from the address
 *
 *
 */
uint8_t eeprom_read_byte(uint8_t addr)
{
    struct rt_i2c_msg msg;
    uint8_t buffer[2];
    uint8_t data;

    msg.addr = EEPROM_I2C_ADDR;
    msg.flags = RT_I2C_WR;
    buffer[0] = addr;
    msg.buf = buffer;
    msg.len = 1;

    rt_i2c_transfer(i2c_bus, &msg, 1);

    msg.flags = RT_I2C_RD;
    msg.buf = &data;

    rt_i2c_transfer(i2c_bus, &msg, 1);

    return data;
}
/**
 * eeprom check
 * @note This operation is check eeprom.
 *
 * @param
 *
 * @return >= 0: successful
 *           -1: error
 *
 */
static rt_err_t eeprom_check(uint8_t data)
{
    uint8_t temp;

    temp = eeprom_read_byte(EEPROM_SIZE - 1);
    if(temp != data)
    {
        eeprom_write_byte(EEPROM_SIZE - 1, data);
        rt_thread_mdelay(5);

        temp = eeprom_read_byte(EEPROM_SIZE - 1);
        if(temp != data)
        {
#if 1
            rt_kprintf("eeprom check data [0x%02X] not equal read data [0x%02X].\n", data, temp);
#endif
            return RT_ERROR;
        }
        rt_kprintf("eeprom check data [0x%02X] equal read data [0x%02X].\n", data, temp);
    }
    return RT_EOK;
}


/**
 * eeprom init
 * @note This operation is eeprom init.
 *
 * @param
 *
 * @return >= 0: successful
 *           -1: error
 *
 */
rt_err_t eeprom_init(void)
{
    i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(EEPROM_I2C_BUS_NAME);
    if (i2c_bus == RT_NULL)
    {
        rt_kprintf("eeprom i2c bus find error.\n");
        return RT_ERROR;
    }

    rt_pin_mode(EEPROM_WP_PIN, PIN_MODE_OUTPUT);
    rt_pin_write(EEPROM_WP_PIN, PIN_LOW);

    if(eeprom_check(EEPROM_CHECK_VALUE) != RT_EOK)
    {
        rt_kprintf("eeprom check error.\n");
        return RT_ERROR;
    }else {
        rt_kprintf("eeprom check success.\n");
    }

    return RT_EOK;
}

/**
 * eeprom test
 * @note This operation is test eeprom.
 *
 * @param
 *
 * @return >= 0: successful
 *           -1: error
 *
 */
static int eeprom_test(void)
{
    rt_uint8_t *rw_buf = RT_NULL;

    rw_buf = (rt_uint8_t *)rt_malloc(EEPROM_SIZE);    //分配一个256字节大小的空间

    eeprom_init();

    //erase eeprom
    for(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++)
    {
        if(RT_EOK == eeprom_write_byte(addr, 0))
        {
            rt_kprintf("address [0x%02X] erase OK.\n", addr);
        }
        else
        {
            rt_kprintf("address [0x%02X] erase failed.\n", addr);
        }
    }

    rt_kprintf("\n");
    rt_thread_mdelay(1000);

    //read eeprom
    for(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++)
    {
        rw_buf[addr] = eeprom_read_byte(addr);
        rt_kprintf("address [0x%02X] data is [%d].\n", addr, rw_buf[addr]);
    }

    rt_kprintf("\n");
    rt_thread_mdelay(1000);

    //write eeprom
    for(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++)
    {
        if(RT_EOK == eeprom_write_byte(addr, 0XFF))
        {
            rt_kprintf("address [0x%02X] write OK.\n", addr);
        }
        else
        {
            rt_kprintf("address [0x%02X] write failed.\n", addr);
        }
    }

    rt_kprintf("\n");
    rt_thread_mdelay(1000);

    //read eeprom
    for(rt_uint16_t addr = 0; addr < EEPROM_SIZE; addr++)
    {
        rw_buf[addr] = eeprom_read_byte(addr);
        rt_kprintf("address [0x%02X] data is [%d].\n", addr, rw_buf[addr]);
    }

    //free
    rt_free(rw_buf);

    return RT_EOK;
}
MSH_CMD_EXPORT(eeprom_test, eeprom test);

static void basic_test(int argc, char** argv)
{
    if (argc != 3)
    {
        rt_kprintf("Usage: basic_test [addr(0-255)] [data(0-255)]\n");
        return;
    }

    uint8_t addr = atoi(argv[1]);
    uint8_t wr_data = atoi(argv[2]);

    // 写入并验证
    eeprom_write_byte(addr, wr_data);
    uint8_t rd_data = eeprom_read_byte(addr);
    rt_kprintf("Immediate read: Addr 0x%02X => Wr:0x%02X Rd:0x%02X %s \r\n",
              addr, wr_data, rd_data, (wr_data == rd_data) ? "OK" : "FAIL");

    // 重启后验证
    rt_kprintf("Power cycle device and run again to check persistence");
}
MSH_CMD_EXPORT(basic_test, basic single-byte test);

static void read_test(int argc, char** argv)
{
    if(argc != 2)
    {
        rt_kprintf("Usage: read_test [addr(0-255)]\n");
        return;
    }
    uint8_t addr = atoi(argv[1]);
    uint8_t rd_data = eeprom_read_byte(addr);
    rt_kprintf("Immediate read: Addr %d => Rd:%d \r\n",
              addr, rd_data);

}
MSH_CMD_EXPORT(read_test, read single-byte test);

  1. drv_ad24c02.h文件里这么写
    在这里插入图片描述
/*
 * Copyright (c) 2006-2021, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2025-04-18     Administrator       the first version
 */
#ifndef APPLICATIONS_DRV_AD24C02_DEAL_DRV_AD24C02_H_
#define APPLICATIONS_DRV_AD24C02_DEAL_DRV_AD24C02_H_

#include <rtdevice.h>
#include <rtthread.h>
#include "board.h"
#include "stdio.h"
#include "stdlib.h"

#define EEPROM_I2C_BUS_NAME         "i2c1"
#define EEPROM_I2C_ADDR             0x50        //0xA0 << 1
#define EEPROM_SIZE                  256         //Byte
#define EEPROM_CHECK_VALUE           0x5A

/*********************************eeprom**************************************************/
#define EEPROM_WP_PIN               GET_PIN(B, 4)


extern rt_err_t eeprom_init(void);   //ad24c02初始化
#endif /* APPLICATIONS_DRV_AD24C02_DEAL_DRV_AD24C02_H_ */

  1. 包含头文件
    在这里插入图片描述
  2. 找个位置进行ad24c02初始化
    在这里插入图片描述
  3. 包含一下ad24c02驱动头文件
    在这里插入图片描述
  4. 编译通过
    在这里插入图片描述

三、测试

1、eeprom_test()测试

在MSH中使用命令行敲出eeprom_test进行测试。

  1. 先打help可以看到目前有什么指令,然后输入eeprom_test进行测试,按TAB键可以自动补齐。
    在这里插入图片描述

  2. 该测试函数首先会往eeprom的256个字节中写0,一个字节一个字节的写,每写成功一个都会返回erase OK
    在这里插入图片描述

  3. 写完后,又会再读出来,可以看到我们写进去是0,那读出来也是0
    在这里插入图片描述

  4. 然后又往这256个字节里面写,不过这回写的是0XFF
    在这里插入图片描述

  5. 然后再读,0XFF对应十进制就是255。
    在这里插入图片描述

  6. 检查打印,看是否都写成功,然后读出来是否是前面一次是0,后面这次是255。如果符合预期,说明咱的eeprom驱动写得没问题了。

2、基础操作字节实验

步骤:

  1. 在指定地址写入特定值
  2. 立即读取验证
  3. 断电重启再次读取验证持久性
    在MSH中敲出命令行,使用basic_test ,第一个参数写地址,第二个参数写数据
    在这里插入图片描述
    可以看到有返回,当然我们写进去的地址跟数据使用的是十进制,返回的使用的是十六进制,所以看起来不一样,自己换算一下可以发现是一样的。
    在这里插入图片描述
    我们再用read_test去读这个23地址,我们刚刚就在这个23地址中写入了66
    在这里插入图片描述
    可以发现读出来的是66
    在这里插入图片描述
    进行一次重启(即掉电),可以发现读出来的还是66,说明eeprom是起作用的
    在这里插入图片描述

3、多字节读写

新增这两个函数,这两个函数可以进行多字节读写

int16_t eeprom_write_params(uint8_t *buf, int16_t start_index, int16_t buf_len)
{
    static int write_count = 0;
    rt_kprintf("[EEPROM] write count : %d, write len : %d\n", ++write_count, buf_len);

    if (start_index + buf_len >= EEPROM_SIZE)
    {
        rt_kprintf("EEPROM write params assert\n");
        return RT_ERROR;
    }

    // Write data to EEPROM
    for (int16_t i = 0; i < buf_len; i++)
    {
        if (eeprom_write_byte(start_index + i, buf[i]) != RT_EOK)
        {
            rt_kprintf("EEPROM write error at address %d\n", start_index + i);
            return RT_ERROR;
        }
    }
    // Verify the written data
    uint8_t tmp_mem[buf_len];
    for (int16_t i = 0; i < buf_len; i++)
    {
        tmp_mem[i] = eeprom_read_byte(start_index + i);
        if (tmp_mem[i] != buf[i])
        {
            rt_kprintf("EEPROM write verify failed at address %d\n", start_index + i);
            return RT_ERROR;
        }
        else
        {
            rt_kprintf("EEPROM write verify success at address %d\n", start_index + i);
        }
    }

    return RT_EOK;
}

//eeprom read
int16_t eeprom_read_params(uint8_t *buf, int16_t start_index, int16_t buf_len)
{
    if (start_index + buf_len >= EEPROM_SIZE || buf == RT_NULL)
    {
        rt_kprintf("EEPROM read params assert\n");
        return RT_ERROR;
    }

    // Read data from EEPROM
    for (int16_t i = 0; i < buf_len; i++)
    {
        buf[i] = eeprom_read_byte(start_index + i);
    }

    return RT_EOK;
}

再新加这个测试函数,用于验证

void eeprom_tes2(void)
{
    uint8_t write_buf[TEST_DATA_SIZE] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    uint8_t read_buf[TEST_DATA_SIZE] = {0};
    int16_t start_index = 0;

    // 初始化 EEPROM
    if (eeprom_init() != RT_EOK)
    {
        rt_kprintf("EEPROM initialization failed\n");
        return;
    }

    // 向 EEPROM 写入数据
    if (eeprom_write_params(write_buf, start_index, TEST_DATA_SIZE) != RT_EOK)
    {
        rt_kprintf("EEPROM write params failed\n");
        return;
    }

    rt_thread_mdelay(100); // 适当延时,确保写入完成

    // 从 EEPROM 读取数据
    if (eeprom_read_params(read_buf, start_index, TEST_DATA_SIZE) != RT_EOK)
    {
        rt_kprintf("EEPROM read params failed\n");
        return;
    }

    // 验证写入和读取的数据是否一致
    for (int16_t i = 0; i < TEST_DATA_SIZE; i++)
    {
        if (write_buf[i] != read_buf[i])
        {
            rt_kprintf("Data verification failed at index %d: write %d, read %d\n", i, write_buf[i], read_buf[i]);
            return;
        }
    }

    rt_kprintf("EEPROM read and write test passed\n");
}

MSH_CMD_EXPORT(eeprom_tes2, EEPROM read and write test);

验证结果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

先睡个好觉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值