RT-Thread: eeprom存储芯片 at24cxx软件包使用流程

说明:介绍 i2c 通讯接口的 eeprom at24cxx 读写测、试代码,代码基于 at24cxx 软件包实现。

使用步骤:

* 1:在 RT-Thread Settings 中开启 【软件模拟I2C】

* 2:在 RT-Thread Settings 软件包中搜索 at24cxx 添加软件包,并保存。

* 3:drivers-> board.h 中打开I2C接口的定义 搜索 I2C CONFIG BEGIN,按介绍定义。

* 4:packages 目录中可以找到添加的软件包,at24cxx.h 中定义 eeprom的型号 ,如 #define EE_TYPE AT24C64

* 软件包提示: 注意事项

* 请在at24cxx.h中修改EE_TYPE为自己使用的型号(默认为AT25C512) 。

* 请在at24cxx.h中修改EE_TWR为自己使用EEPROM的Write Cycle Time,具体值请查看芯片datasheet(默认为5ms) 。

* 从设备地址为7位地址 0x50, 而不是 0xA0 。

1:在 RT-Thread Settings 中开启 【软件模拟I2C】

2:在 RT-Thread Settings 软件包中搜索 at24cxx 添加软件包,添加后并保存。

3:drivers-> board.h 中打开I2C接口的定义 搜索 I2C CONFIG BEGIN,按介绍定义。

4:packages 目录中可以找到添加的软件包,at24cxx.h 中定义 eeprom的型号 ,如 #define EE_TYPE AT24C64

4.1.设置 EEPROM芯片型号,写周期,地址

at24cxx.h 头文件中设置芯片型号,修改写周期(根据芯片手册)

4.2.型号设置好后先编译,编译后对应的 c文件中的相应配置就会打开。

4.3. 芯片地址设置(EEPROM地址一般是 0x50 不含读写标志位及3个IO设置的地址, A0 = A1 = A2 =L 接 GND时地址为0x50;A0 = H, A1 = L, A2 = L 地址为0x51)

5. 测试代码

/*
 * Copyright (c) 2006-2020, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 说明:本eeprom 读写测试代码基于 at24cxx 软件包
 * 使用步骤:
 * 1:在 RT-Thread Settings 中开启  【软件模拟I2C】
 * 2:在 RT-Thread Settings 软件包中搜索 at24cxx 添加软件包,并保存。
 * 3:drivers-> board.h 中打开I2C接口的定义  搜索 I2C CONFIG BEGIN,按介绍定义。
 * 4:packages 目录中可以找到添加的软件包,at24cxx.h 中定义 eeprom的型号 ,如 #define EE_TYPE     AT24C64
 *
 * 软件包提示: 注意事项
 * 请在at24cxx.h中修改EE_TYPE为自己使用的型号(默认为AT25C512) 。
 * 请在at24cxx.h中修改EE_TWR为自己使用EEPROM的Write Cycle Time,具体值请查看芯片datasheet(默认为5ms) 。
 * 从设备地址为7位地址 0x50, 而不是 0xA0 。
 */
#include "user_cfg.h"

#define EEPROM_I2C  "i2c1"   /* eeprom 所挂载的i2c总线 */
#define EEP_ADDR     0       /* 从设备芯片地址,IC的A2,A1,A0设置的值 */
#define CF_START_ADD 0       /* eeprom 校准系数的首地址 */

//#define EEPROM_TEST_CODE

static at24cxx_device_t eeprom_dev;  /*    at24cxx 设备对象 */

/* eeprom 设备初始化 */
void eeprom_init(void)
{
    eeprom_dev = at24cxx_init(EEPROM_I2C,EEP_ADDR);
    if(eeprom_dev == RT_NULL)
    {
        rt_kprintf(">eeprom 注册失败... \n");
    }
}

/* 校准系数保存到 eeprom  */
void eeprom_cf_save(void)
{
    int8_t temp[CH_NUM*2];

    for (int8_t var = 0; var < CH_NUM; ++var)
    {
        temp[var*2] = Adc_Channel_CF_Data[var]>>8;
        temp[var*2+1] = Adc_Channel_CF_Data[var];
    }

    at24cxx_write(eeprom_dev,CF_START_ADD,(uint8_t *)temp,CH_NUM*2); /*向eeprom 中写入数据*/
    rt_kprintf(">校准值已保存到 eeprom ... \n");
}

void eeprom_rw_entry(void *param)
{

   rt_kprintf(">eeprom 线程启动... \n");
   eeprom_init();
   rt_kprintf(">eeprom 初始化完成... \n");

#ifdef  EEPROM_TEST_CODE
   /* 数据读写测试 */
   uint8_t eeprom_RBuffer[254];
   uint8_t eeprom_WBuffer[254];

   for (uint8_t var = 0; var < 254; ++var)
   {
       eeprom_WBuffer[var] = var ;
   }


   at24cxx_write(eeprom_dev,0,eeprom_WBuffer,254); /*向eeprom 中写入数据*/
   rt_kprintf("eeprom 数据写入 完成... \n");
   rt_thread_mdelay(100);

   at24cxx_read(eeprom_dev,0,eeprom_RBuffer,254);  /*从eeprom 中读数据*/
   rt_kprintf("eeprom 数据读出 完成... \n");
   for (uint8_t var = 0; var < 254; ++var)
   {
       rt_kprintf("ADD = %d ,Data = %d \n",var,eeprom_RBuffer[var]);
   }
   /* 以上 数据读写测试 */
#endif

   uint8_t eeprom_RBuffer[CH_NUM*2];
   at24cxx_read(eeprom_dev,CF_START_ADD,eeprom_RBuffer,CH_NUM*2);  /*从eeprom 中读数据放入内存*/

   for (uint8_t var = 0; var < CH_NUM; ++var)  /* eeprom 中的校准数据转换成16bit后给校准值变量,eeprom中存储方式为高位在前,低位在后。*/
   {
       Adc_Channel_CF_Data[var] = eeprom_RBuffer[2*var];
       Adc_Channel_CF_Data[var] = (Adc_Channel_CF_Data[var]<<8)|eeprom_RBuffer[2*var+1];
       rt_kprintf("校准值:%011s ,Data = %05d \n",Adc_Channel_Name[var],Adc_Channel_CF_Data[var]);
   }


   while(1)
   {
       rt_thread_mdelay(100);

   }

}



void eeprom_test(void)
{
    rt_thread_t tid1;//创建线程控制块指针来接收线程创建函数的返回值,目的是通过返回值判断线程是否创建ok

    /* 创建线程 1,名称是 pt_io_test_entry,入口是 pt_io_test_entry*/
        tid1 = rt_thread_create("eeprom_rw_entry",
                                eeprom_rw_entry, RT_NULL,
                                1700,//设置内存堆栈大小
                                10, 50);//设置优先级,时间片参数,时间片是在有多个相同优先级线程时,这个线程每次被执行多少个时间片

        /* 如果获得线程控制块,启动这个线程 */
        if (tid1 != RT_NULL)
            rt_thread_startup(tid1);
}

INIT_APP_EXPORT(eeprom_test);

6. 项目使用中对软件包函数的一些描述

at24cxx.c

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-04-13     XiaojieFan   the first version
 * 2019-12-04     RenMing      ADD PAGE WRITE and input address can be selected 
 */
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#include <string.h>
#include <stdlib.h>

#define DBG_ENABLE
#define DBG_SECTION_NAME "at24xx"
#define DBG_LEVEL DBG_LOG
#define DBG_COLOR
#include <rtdbg.h>

#include "at24cxx.h"

#ifdef PKG_USING_AT24CXX
#define AT24CXX_ADDR (0xA0 >> 1)                      //A0 = A1 = A2 =L, connect GND
//#define AT24CXX_ADDR (0x51)                             //A0 = H, A1 = L, A2 = L

#if (EE_TYPE == AT24C01)
    #define AT24CXX_PAGE_BYTE               8
    #define AT24CXX_MAX_MEM_ADDRESS         128
#elif (EE_TYPE == AT24C02)
    #define AT24CXX_PAGE_BYTE               8
    #define AT24CXX_MAX_MEM_ADDRESS         256
#elif (EE_TYPE == AT24C04)
    #define AT24CXX_PAGE_BYTE               16
    #define AT24CXX_MAX_MEM_ADDRESS         512
#elif (EE_TYPE == AT24C08)
    #define AT24CXX_PAGE_BYTE               16
    #define AT24CXX_MAX_MEM_ADDRESS         1024
#elif (EE_TYPE == AT24C16)
    #define AT24CXX_PAGE_BYTE               16
    #define AT24CXX_MAX_MEM_ADDRESS         2048
#elif (EE_TYPE == AT24C32)
    #define AT24CXX_PAGE_BYTE               32
    #define AT24CXX_MAX_MEM_ADDRESS         4096
#elif (EE_TYPE == AT24C64)
    #define AT24CXX_PAGE_BYTE               32
    #define AT24CXX_MAX_MEM_ADDRESS         8192
#elif (EE_TYPE == AT24C128)
    #define AT24CXX_PAGE_BYTE               64
    #define AT24CXX_MAX_MEM_ADDRESS         16384
#elif (EE_TYPE == AT24C256)
    #define AT24CXX_PAGE_BYTE               64
    #define AT24CXX_MAX_MEM_ADDRESS         32768
#elif (EE_TYPE == AT24C512)
    #define AT24CXX_PAGE_BYTE               128
    #define AT24CXX_MAX_MEM_ADDRESS         65536
#endif

static rt_err_t read_regs(at24cxx_device_t dev, rt_uint8_t len, rt_uint8_t *buf)
{
    struct rt_i2c_msg msgs;

    msgs.addr = AT24CXX_ADDR | dev->AddrInput;
    msgs.flags = RT_I2C_RD;
    msgs.buf = buf;
    msgs.len = len;

    if (rt_i2c_transfer(dev->i2c, &msgs, 1) == 1)
    {
        return RT_EOK;
    }
    else
    {
        return -RT_ERROR;
    }
}

/**读取 eeprom 一个字节函数 (YL已验证测试)

 * @param dev ,at24cxx 设备对象
 * @param readAddr;读取地址
 * @return temp;返回读取到的数据
 */

uint8_t at24cxx_read_one_byte(at24cxx_device_t dev, uint16_t readAddr)
{
    rt_uint8_t buf[2];
    rt_uint8_t temp = 0;
#if (EE_TYPE > AT24C16)
    buf[0] = (uint8_t)(readAddr>>8);
    buf[1] = (uint8_t)readAddr;
    if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR, 0, buf, 2) == 0) 
#else
    buf[0] = readAddr;
    if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR | dev->AddrInput, 0, buf, 1) == 0)
#endif        
    {
        return RT_ERROR;
    }
    read_regs(dev, 1, &temp);
    return temp;
}

/**写一个字节  eeprom 函数 (YL已验证测试)

 * @param dev ,at24cxx 设备对象
 * @param readAddr;写地址
 * @param dataToWrite;待写入数据
 * @return 写成功,写失败
 */


rt_err_t at24cxx_write_one_byte(at24cxx_device_t dev, uint16_t writeAddr, uint8_t dataToWrite)
{
    rt_uint8_t buf[3];
#if (EE_TYPE > AT24C16)
    buf[0] = (uint8_t)(writeAddr>>8);
    buf[1] = (uint8_t)writeAddr;
    buf[2] = dataToWrite;
    if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR, 0, buf, 3) == 3)    
#else    
    buf[0] = writeAddr; //cmd
    buf[1] = dataToWrite;
    //buf[2] = data[1];
    

    if (rt_i2c_master_send(dev->i2c, AT24CXX_ADDR | dev->AddrInput, 0, buf, 2) == 2)
#endif        
        return RT_EOK;
    else
        return -RT_ERROR;

}

rt_err_t at24cxx_read_page(at24cxx_device_t dev, uint32_t readAddr, uint8_t *pBuffer, uint16_t numToRead)
{
    struct rt_i2c_msg msgs[2];
    uint8_t AddrBuf[2];
    
    msgs[0].addr = AT24CXX_ADDR | dev->AddrInput;
    msgs[0].flags = RT_I2C_WR ;
 
#if (EE_TYPE > AT24C16)
    AddrBuf[0] = readAddr >> 8;
    AddrBuf[1] = readAddr;
    msgs[0].buf = AddrBuf;
    msgs[0].len = 2; 
#else
    AddrBuf[0] = readAddr;
    msgs[0].buf = AddrBuf;
    msgs[0].len = 1;
#endif    
    
    msgs[1].addr = AT24CXX_ADDR | dev->AddrInput;
    msgs[1].flags = RT_I2C_RD;
    msgs[1].buf = pBuffer;
    msgs[1].len = numToRead;
    
    if(rt_i2c_transfer(dev->i2c, msgs, 2) == 0) 
    {
        return RT_ERROR;
    }

    return RT_EOK;
}

/**写一页  eeprom 函数

 * @param dev ,at24cxx 设备对象
 * @param readAddr;写地址
 * @param *pBuffer;
 * @param numToWrite;
 * @return 写成功,写失败
 */

rt_err_t at24cxx_write_page(at24cxx_device_t dev, uint32_t wirteAddr, uint8_t *pBuffer, uint16_t numToWrite)
{
    struct rt_i2c_msg msgs[2];
    uint8_t AddrBuf[2];

    msgs[0].addr = AT24CXX_ADDR | dev->AddrInput;
    msgs[0].flags = RT_I2C_WR ;
    
#if (EE_TYPE > AT24C16)
    AddrBuf[0] = wirteAddr >> 8;
    AddrBuf[1] = wirteAddr;
    msgs[0].buf = AddrBuf;
    msgs[0].len = 2; 
#else
    AddrBuf[0] = wirteAddr;
    msgs[0].buf = AddrBuf;
    msgs[0].len = 1;
#endif    

    msgs[1].addr = AT24CXX_ADDR | dev->AddrInput;
    msgs[1].flags = RT_I2C_WR | RT_I2C_NO_START;
    msgs[1].buf = pBuffer;
    msgs[1].len = numToWrite;

    if(rt_i2c_transfer(dev->i2c, msgs, 2) == 0) 
    {
        return RT_ERROR;
    }

    return RT_EOK;
}
/**查看是否存在eeprom 设备,通过在最后一个字节写入标志位,进行判断

 * @param dev ,at24cxx 设备对象
 * @return =RT_EOK  设备存在, != RT_EOK  设备不存在
 */

rt_err_t at24cxx_check(at24cxx_device_t dev)
{
    uint8_t temp;
    RT_ASSERT(dev);

    temp = at24cxx_read_one_byte(dev, AT24CXX_MAX_MEM_ADDRESS - 1);
    if (temp == 0x55) return RT_EOK;
    else
    {
        at24cxx_write_one_byte(dev, AT24CXX_MAX_MEM_ADDRESS - 1, 0x55);
        rt_thread_mdelay(EE_TWR);                 // wait 5ms befor next operation
        temp = at24cxx_read_one_byte(dev, AT24CXX_MAX_MEM_ADDRESS - 1);
        if (temp == 0x55) return RT_EOK;
    }
    return RT_ERROR;
}

/**连续读取
 * This function read the specific numbers of data to the specific position;读取 eeprom ,在AT24CXX里面的指定地址开始读出指定个数的数据
 *
 * @param bus the name of at24cxx device ;                   dev:总线at24cxx设备的名称
 * @param ReadAddr the start position to read;                   ReadAddr:读取的起始位置
 * @param pBuffer  the read data store position;         pBuffer:读取数据存储位置
 * @param NumToRead;                                                                     NumToRead:读取数量
 * @return RT_EOK  write ok.  != RT_EOK 读取成功,RT_EOK 读取失败
 */
rt_err_t at24cxx_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead)
{
    rt_err_t result;
    RT_ASSERT(dev);
    
    if(ReadAddr + NumToRead > AT24CXX_MAX_MEM_ADDRESS)
    {
        return RT_ERROR;
    }
    
    result = rt_mutex_take(dev->lock, RT_WAITING_FOREVER);
    if (result == RT_EOK)
    {
        while (NumToRead)
        {
            *pBuffer++ = at24cxx_read_one_byte(dev, ReadAddr++);
            NumToRead--;
        }
    }
    else
    {
        LOG_E("The at24cxx could not respond  at this time. Please try again");
    }
    rt_mutex_release(dev->lock);

    return RT_EOK;
}

/**
 * This function read the specific numbers of data to the specific position
 *
 * @param bus the name of at24cxx device
 * @param ReadAddr the start position to read
 * @param pBuffer  the read data store position
 * @param NumToRead 
 * @return RT_EOK  write ok.
 */
rt_err_t at24cxx_page_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead)
{
    rt_err_t result = RT_EOK;
    uint16_t pageReadSize = AT24CXX_PAGE_BYTE - ReadAddr % AT24CXX_PAGE_BYTE;

    RT_ASSERT(dev);

    if(ReadAddr + NumToRead > AT24CXX_MAX_MEM_ADDRESS)
    {
        return RT_ERROR;
    }

    result = rt_mutex_take(dev->lock, RT_WAITING_FOREVER);
    if(result == RT_EOK)
    {
        while (NumToRead)
        {
            if(NumToRead > pageReadSize)
            {
                if(at24cxx_read_page(dev, ReadAddr, pBuffer, pageReadSize))
                {
                    result = RT_ERROR;
                }

                ReadAddr += pageReadSize;
                pBuffer += pageReadSize;
                NumToRead -= pageReadSize;
                pageReadSize = AT24CXX_PAGE_BYTE;
            }
            else
            {
                if(at24cxx_read_page(dev, ReadAddr, pBuffer, NumToRead))
                {
                    result = RT_ERROR;
                }
                NumToRead = 0;
            }
        }
    }
    else
    {
        LOG_E("The at24cxx could not respond  at this time. Please try again");
    }

    rt_mutex_release(dev->lock);
    return result;
}

/**连续写入
 * This function write the specific numbers of data to the specific position;写入,在AT24CXX里面的指定地址开始写入指定个数的数据
 *
 * @param bus the name of at24cxx device;at24cxx                        dev:设备对象
 * @param WriteAddr the start position to write;                                    WriteAddr:写入的首地址
 * @param pBuffer  the data need to write;                                                  *pBuffer:需要写入的数据的首地址
 * @param NumToWrite;                                                                                        NumToWrite:写入数量
 * @return RT_EOK  write ok.at24cxx_device_t dev
 */
rt_err_t at24cxx_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite)
{

    //rt_err_t ret; /*YL新增*/
    uint16_t i = 0;
    rt_err_t result;
    RT_ASSERT(dev);
    
    if(WriteAddr + NumToWrite > AT24CXX_MAX_MEM_ADDRESS)
    {
        return RT_ERROR;
    }
    
    result = rt_mutex_take(dev->lock, RT_WAITING_FOREVER);
    if (result == RT_EOK)
    {
        /*以下 原源代码*/
        while (1) //NumToWrite--
        {
            if (at24cxx_write_one_byte(dev, WriteAddr, pBuffer[i]) != RT_EOK)
            {
                rt_thread_mdelay(EE_TWR);
            }
            else
            {
                WriteAddr++;
                i++;
            }
            if (i == NumToWrite)
            {
                break;
            }

        }
        /*以上 原源代码*/
//        while (1) //NumToWrite--
//        {
//            ret = at24cxx_write_one_byte(dev, WriteAddr, pBuffer[i]);
//            if (at24cxx_write_one_byte(dev, WriteAddr, pBuffer[i]) != RT_EOK)
//            {
//                rt_thread_mdelay(EE_TWR);
//            }
//            else
//            {
//                WriteAddr++;
//                i++;
//            }
//            if (i == NumToWrite)
//            {
//                break;
//            }
//
//        }
    }
    else
    {
        LOG_E("The at24cxx could not respond  at this time. Please try again");
    }
    rt_mutex_release(dev->lock);

    return RT_EOK;
}

/**此函数将特定数量的数据写入特定位置
 * This function write the specific numbers of data to the specific position
 *
 * @param bus the name of at24cxx device;                     dev:设备对象
 * @param WriteAddr the start position to write;        WriteAddr:写入的首地址
 * @param pBuffer  the data need to write                *pBuffer:需要写入的数据的首地址
 * @param NumToWrite                                   NumToWrite:写入数量
 * @return RT_EOK  write ok.at24cxx_device_t dev
 */

rt_err_t at24cxx_page_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite)
{
    rt_err_t result = RT_EOK;
    uint16_t pageWriteSize = AT24CXX_PAGE_BYTE - WriteAddr % AT24CXX_PAGE_BYTE;

    RT_ASSERT(dev);

    if(WriteAddr + NumToWrite > AT24CXX_MAX_MEM_ADDRESS)
    {
        return RT_ERROR;
    }

    result = rt_mutex_take(dev->lock, RT_WAITING_FOREVER);
    if(result == RT_EOK)
    {
        while (NumToWrite)
        {
            if(NumToWrite > pageWriteSize)
            {
                if(at24cxx_write_page(dev, WriteAddr, pBuffer, pageWriteSize))
                {
                    result = RT_ERROR;
                }
                rt_thread_mdelay(EE_TWR);    // wait 5ms befor next operation

                WriteAddr += pageWriteSize;
                pBuffer += pageWriteSize;
                NumToWrite -= pageWriteSize;
                pageWriteSize = AT24CXX_PAGE_BYTE;
            }
            else
            {
                if(at24cxx_write_page(dev, WriteAddr, pBuffer, NumToWrite))
                {
                    result = RT_ERROR;
                }
                rt_thread_mdelay(EE_TWR);   // wait 5ms befor next operation

                NumToWrite = 0;
            }
        }
    }
    else
    {
        LOG_E("The at24cxx could not respond  at this time. Please try again");
    }

    rt_mutex_release(dev->lock);
    return result;
}

/**设备初始化
 * This function initializes at24cxx registered device driver ;根据总线名称,自动初始化对应的 AT24CXX 设备
 *
 * @param dev the name of at24cxx device ;i2c_bus_name,i2c 设备名称
 * @param
 * @return the at24cxx device.
 */
at24cxx_device_t at24cxx_init(const char *i2c_bus_name, uint8_t AddrInput)
{
    at24cxx_device_t dev;

    RT_ASSERT(i2c_bus_name);

    dev = rt_calloc(1, sizeof(struct at24cxx_device));
    if (dev == RT_NULL)
    {
        LOG_E("Can't allocate memory for at24cxx device on '%s' ", i2c_bus_name);
        return RT_NULL;
    }

    dev->i2c = rt_i2c_bus_device_find(i2c_bus_name);
    if (dev->i2c == RT_NULL)
    {
        LOG_E("Can't find at24cxx device on '%s' ", i2c_bus_name);
        rt_free(dev);
        return RT_NULL;
    }

    dev->lock = rt_mutex_create("mutex_at24cxx", RT_IPC_FLAG_FIFO);
    if (dev->lock == RT_NULL)
    {
        LOG_E("Can't create mutex for at24cxx device on '%s' ", i2c_bus_name);
        rt_free(dev);
        return RT_NULL;
    }

    dev->AddrInput = AddrInput;
    return dev;
}

/**
 * This function releases memory and deletes mutex lock
 * 如果设备不再使用,反初始化将回收 at24cxx 设备的相关资源
 * @param dev the pointer of device driver structure
 */
void at24cxx_deinit(at24cxx_device_t dev)
{
    RT_ASSERT(dev);

    rt_mutex_delete(dev->lock);

    rt_free(dev);
}

uint8_t TEST_BUFFER[] = "WELCOM TO RTT";
#define SIZE sizeof(TEST_BUFFER)

void at24cxx(int argc, char *argv[])
{
    static at24cxx_device_t dev = RT_NULL;

    if (argc > 1)
    {
        if (!strcmp(argv[1], "probe"))
        {
            if (argc > 2)
            {
                /* initialize the sensor when first probe */
                if (!dev || strcmp(dev->i2c->parent.parent.name, argv[2]))
                {
                    /* deinit the old device */
                    if (dev)
                    {
                        at24cxx_deinit(dev);
                    }
                    dev = at24cxx_init(argv[2], atoi(argv[3]));
                }
            }
            else
            {
                rt_kprintf("at24cxx probe <dev_name> <AddrInput> - probe sensor by given name\n");
            }
        }
        else if (!strcmp(argv[1], "read"))
        {
            if (dev)
            {
                uint8_t testbuffer[50];

                /* read the eeprom data */
                at24cxx_read(dev, 0, testbuffer, SIZE);

                rt_kprintf("read at24cxx : %s\n", testbuffer);

            }
            else
            {
                rt_kprintf("Please using 'at24cxx probe <dev_name>' first\n");
            }
        }
        else if (!strcmp(argv[1], "write"))
        {
            at24cxx_write(dev, 0, TEST_BUFFER, SIZE);
            rt_kprintf("write ok\n");
        }
        else if (!strcmp(argv[1], "check"))
        {
            if (at24cxx_check(dev) == 1)
            {
                rt_kprintf("check faild \n");
            }
        }
        else
        {
            rt_kprintf("Unknown command. Please enter 'at24cxx0' for help\n");
        }
    }
    else
    {
        rt_kprintf("Usage:\n");
        rt_kprintf("at24cxx probe <dev_name>   - probe eeprom by given name\n");
        rt_kprintf("at24cxx check              - check eeprom at24cxx \n");
        rt_kprintf("at24cxx read               - read eeprom at24cxx data\n");
        rt_kprintf("at24cxx write              - write eeprom at24cxx data\n");

    }
}
MSH_CMD_EXPORT(at24cxx, at24cxx eeprom function);
#endif

at24cxx.h

/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-04-13     XiaojieFan   the first version
 * 2019-12-04     RenMing      Use PAGE WRITE instead of BYTE WRITE and input address can be selected 
 */

#ifndef __AT24CXX_H__
#define __AT24CXX_H__

#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#define AT24C01     0
#define AT24C02     1
#define AT24C04     2
#define AT24C08     3
#define AT24C16     4
#define AT24C32     5
#define AT24C64     6
#define AT24C128    7
#define AT24C256    8
#define AT24C512    9
#define AT24CTYPE   10   // Number of supported types


/*
 *注意事项:
 *请在at24cxx.h中修改EE_TYPE为自己使用的型号(默认为AT25C512) 。
 *请在at24cxx.h中修改EE_TWR为自己使用EEPROM的Write Cycle Time,具体值请查看芯片datasheet(默认为5ms) 。
 *从设备地址为7位地址 0x50, 而不是 0xA0 。
 */


#define EE_TWR      5 //Write Cycle Time;写周期时间 ms

#ifndef EE_TYPE
#define EE_TYPE     AT24C64
#endif

struct at24cxx_device
{
    struct rt_i2c_bus_device *i2c;
    rt_mutex_t lock;
    uint8_t AddrInput;
};
typedef struct at24cxx_device *at24cxx_device_t;


extern uint8_t at24cxx_read_one_byte(at24cxx_device_t dev, uint16_t readAddr);
extern rt_err_t at24cxx_write_one_byte(at24cxx_device_t dev, uint16_t writeAddr, uint8_t dataToWrite);

extern at24cxx_device_t at24cxx_init(const char *i2c_bus_name, uint8_t AddrInput);
extern rt_err_t at24cxx_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead);
extern rt_err_t at24cxx_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite);
extern rt_err_t at24cxx_page_read(at24cxx_device_t dev, uint32_t ReadAddr, uint8_t *pBuffer, uint16_t NumToRead);
extern rt_err_t at24cxx_page_write(at24cxx_device_t dev, uint32_t WriteAddr, uint8_t *pBuffer, uint16_t NumToWrite);


#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/323399.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深入理解零拷贝技术

注意事项&#xff1a;除了 Direct I/O&#xff0c;与磁盘相关的文件读写操作都有使用到 page cache 技术。 粉丝福利&#xff0c; 免费领取C/C 开发学习资料包、技术视频/代码&#xff0c;1000道大厂面试题&#xff0c;内容包括&#xff08;C基础&#xff0c;网络编程&#xff…

浅讲人工智能,初识人工智能几个重要领域。

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

PTA-7-4 堆排序

代码如下: #include<iostream> using namespace std; void change(int arr[], int n, int i); int main() {int n,i,end,arr[1000];cin >> n;for (i 0; i < n; i){cin >> arr[i];}//进行一次排序,把最大值放到顶端for (i n/2-1; i > 0; i--){change…

Linux 下GEO Server发布图层后,中文乱码解决方案

发布的图层&#xff0c;显示中文乱码&#xff0c;都是框框&#xff1a;如“口口” 第一步先查看Linux字符集 如下命令所示&#xff1a; 1.查看当前系统语言 echo $LANG2.查看安装的语言包 locale如果上面的命令执行后显示的是en_US.UTF-8&#xff0c;则说明当前语言系统及安…

汇编语言与接口技术实验报告——单总线温度采集

一、 实验要求 实验目的&#xff1a; 掌握数码管的使用方式掌握DS18B20温度传感器的工作原理掌握单总线通信方式实现MCU与DS18B20数据传输 实验内容&#xff1a; 学习DS18B20温度传感器的单总线传输机制&#xff0c;通过单片机MCU的I/O实现温度采集&#xff0c;并将数据显示在…

Ubuntu配置NFS客户端和服务端详解——手把手配置

Ubuntu配置NFS客户端和服务端 如果您想实现远程访问并修改 ROS 主机中 Ubuntu 上的文件&#xff0c;可以通过 NFS挂载的方式。虚拟机上的 Ubuntu 系统可以通过 NFS 的方式来访问 ROS 主机中Ubuntu 系统的文件&#xff0c;NFS 分为服务器挂载和客户端访问。这里虚拟机上的 Ubun…

KubeSphere 在 vsleem 的落地实践

作者&#xff1a;方忠&#xff0c;苏州威视通智能科技有限公司技术经理&#xff0c;开源技术爱好者&#xff0c;长期活跃于 dromara 开源社区并参与贡献。 公司介绍 公司简介 苏州威视通智能科技有限公司&#xff0c;是一家全球领先的全景 AI 平台提供商&#xff0c;结合极致…

界面控件DevExpress WPF属性网格 - 让应用轻松显示编辑各种属性事件

DevExpress WPF Property Grid&#xff08;属性网格&#xff09;灵感来自于Visual Studio&#xff0c;Visual Studio启发的属性窗口(对象检查器)让在WPF应用程序显示和编辑任何对象的属性和事件变得更容易&#xff01; P.S&#xff1a;DevExpress WPF拥有120个控件和库&#x…

Elasticsearch添加7.17.10IK分词器

Elasticsearch添加7.17.10IK分词器 在https://github.com/medcl/elasticsearch-analysis-ik/tree/7.x中未找到7.17.10版本的发布版本&#xff0c;如歌ik版本和Elasticsearch版本不同安装后无法启动。所以下载git上的源代码&#xff0c;并手动编译指定版本IK分词器。 &#xff…

2. 示例:Spring Boot 入门

1.1 概述 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。习惯优于配置 1.2 为什么使用Spring Boot J2EE笨重的开发、繁多的配置、低下的开发效率、复杂的部署流程、第三方技术集成难度大。 1.3 Spring Bo…

HarmonyOS 通过 animateTo讲解角度动画效果

本文 我们依旧来说动画 这次 我们来说角度 我们先写一个这样的代码模板 Entry Component struct Index {build() {Column({space: 30}) {Text("修改元素尺寸").fontSize(38).margin({top:188})Image("https://img2.baidu.com/it/u1814561676,2470063876&f…

gradle版本中-bin与-all区别

打开android studio下载的gradle文件&#xff0c;发现-all比-bin多了一个docs文件夹和一个src文件夹。-bin是编译后的二进制发布版&#xff0c;-all还包含了源码和文档&#xff0c;比-bin大了几十兆&#xff0c;两者其余没有区别。 android开发只关注gradle功能不关注实现的情况…

Rust-借用检查

Rust语言的核心特点是&#xff1a;在没有放弃对内存的直接控制力的情况下&#xff0c;实现了内存安全。 所谓对内存的直接控制能力&#xff0c;前文已经有所展示&#xff1a;可以自行决定内存布局&#xff0c;包括在栈上分配内存&#xff0c;还是在堆上分配内存&#xff1b;支…

虾皮广告数据:​如何利用广告数据优化虾皮(Shopee)销售业绩

在虾皮&#xff08;Shopee&#xff09;平台上&#xff0c;广告数据对于卖家来说是至关重要的&#xff0c;它可以帮助卖家了解广告的效果并进行相应的优化。通过监控和分析这些广告数据&#xff0c;卖家可以更好地理解广告的表现&#xff0c;调整广告策略&#xff0c;提高广告的…

网站监测工具的极与极,Site24x7 与百川云

今天我们聊聊我用 Site24x7 的感受。对于有网站监测有需求的站长们来说&#xff0c;Site24x7 确实是个很强大的应用。但是它与百川云网站监测完全不一样&#xff0c;百川云网站监测是适合用中小微企业的交互极简的saas 应用&#xff0c;Site24x7 完全是另一个极端&#xff0c;适…

【我与Java的成长记】之继承详解(二)

系列文章目录 能看懂文字就能明白系列 C语言笔记传送门 Java笔记传送门 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言一、super关…

跨境电商账号频繁?你的IP可能“不干净”了

疫情促进了跨境电商行业的加速发展&#xff0c;许多卖家也抓住了这波流量红利&#xff0c;跨境电商月入数万&#xff0c;数十万甚至数百万的造福神话也不断在上演&#xff0c;但由于国内外电商运营模式不同&#xff0c;多店运营、用户数据收集、刷单等行为都受到了国外平台的严…

【复现】Tenda信息泄露漏洞_19

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 Tenda远端WEB管理是为了在外网&#xff08;其他网络&#xff09;可以访问路由器&#xff0c;从而进行管理。 电脑可以通过网线连接…

关于K8S组件,你真正了解多少?

Kubernetes架构图 Kubernetes系统用于管理分布式节点集群中的微服务或容器化应用程序&#xff0c;并且其提供了零停机时间部署、自动回滚、缩放和容器的自愈&#xff08;其中包括自动配置、自动重启、自动复制的高弹性基础设施&#xff0c;以及容器的自动缩放等&#xff09;等…

SpringBoot源码分析

一&#xff1a;简介 由Pivotal团队提供的全新框架其设计目的是用来简化新Spring应用的初始搭建以及开发过程使用了特定的方式来进行配置快速应用开发领域 二&#xff1a;运行原理以及特点 运行原理&#xff1a; SpringBoot为我们做的自动配置&#xff0c;确实方便快捷&#…